Sunday, 4 January 2015

Using Imagemagick to generate a c array for images

Imagemagick is a really versatile tool for manipulating images from the command line. It also is a vary handy tool for generating image bitmaps for embedded systems.
This example is for generating a data array for SSD1306 based OLED displays. These are available  for a few pounds from china / ebay and comes in two forms of interfaces:   i2c or spi interface.  For simplicity I picked up an i2c one.
The data is written as column major. i.e each byte represents 8 vertical pixels. The following image is from the SSD1306 datasheet, describing display ram writing sequence:
click to enlarge
It takes 128x64/8 = 1024 bytes for a full image for these displays. So lets start with a simple 350x174 png image :

now use imagemagick to convert this to an .xbm

  convert -resize 128x64\! 1.png 1.xbm  
The 1.xbm file looks like :
 #define 1_width 128  
 #define 1_height 64  
 static char 1_bits[] = {  
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0,   
  0x03, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,   
  0x00, 0x00, 0x00, 0x60, 0x87, 0xCF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,   
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0xFC, 0x81, 0x01, 0x00,   
  0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18,   
 ........ abbreviated ...       
  0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,   
  0x00, 0xC0, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00,   
  0x00, 0x00, 0x00, 0x00, };  
Now we have a c array with 1024 bytes where eight pixels in each byte. as mentioned before, this data is row major, and needs to be transposed to column major array of 1024 bytes. The transpose looks something like :
      __u8 xfdata[1024] = {0x00,};   
      int row, col , offset , pos;  
      pos =0;   
      for (row=0; row <1024; row +=128)  
      {  
           for (col=0; col <128 ; col++)  
           {  
                pos = (0x07 & col);  
                offset = (col >> 3);  
                if ((1<<pos) & data[row+offset+0]) xfdata[row+col] +=1;  
                if ((1<<pos) & data[row +offset+16]) xfdata[row+col] +=2;  
                if ((1<<pos) & data[row +offset +32]) xfdata[row+col] +=4;  
                if ((1<<pos) & data[row +offset +48]) xfdata[row+col] +=8;  
                if ((1<<pos) & data[row +offset + 64]) xfdata[row+col] +=16;  
                if ((1<<pos) & data[row +offset +80]) xfdata[row+col] +=32;  
                if ((1<<pos) & data[row +offset +96]) xfdata[row+col] +=64;  
                if ((1<<pos) & data[row +offset +112]) xfdata[row+col] +=128;  
           }  
      }  

the xfdata[] can now be dumped into SSD1306 ...
note: this display is a dual colour display, where top 16rows are yellow, hence the yellow hats !