Quick tiny bitmaps from PROGMEM

128x128 pixel 1.5" full colour OLED display with MicroSD card slot. [Product page]
Post Reply
krt
Posts: 15
Joined: Tue Jan 07, 2014 7:45 am
Location: Lake Macquarie, NSW

Quick tiny bitmaps from PROGMEM

Post by krt » Thu Jul 03, 2014 1:19 am

Hi,

I found the bitmap library added quite a few kilobytes to my compiled sketch (enough to push me over the limit). So I coded up a quick bitmap function. I used it to do a 3-frame animation of a 16x16 icon, so the bitmaps themselves were smaller than the library code to paint them.

First get your bitmap, then convert it to a raw 16 bit RGB565 bunch of pixels format. This can be done with ffmpeg (converting hamburger.png to hamburger.raw):

Code: Select all

# ffmpeg -vcodec png -i hamburger.png -vcodec rawvideo -f rawvideo -pix_fmt rgb565 hamburger.raw
Then format it nicely:

Code: Select all

# hexdump -v -e '/1 "0x%02x,\n"' hamburger.raw | columns -c 16
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, etc...
Paste it into your sketch as a PROGMEM array:

Code: Select all

prog_char hamburger[] PROGMEM = 
{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x40, 0x18, 0xf1, 0xee, 0xab, 0xff, 0xcc, 0xff, 0xee, 0xff,
0xef, 0xff, 0xf0, 0xff, 0xf0, 0xff, 0xee, 0xff, 0xcf, 0xff, 0xab, 0xff, 0x6a,
0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0xf6, 0xc3, 0xfe,
0x6a, 0xff, 0xaa, 0xff, 0xcd, 0xff, 0xcc, 0xff, 0xcd, 0xff, 0xed, 0xff, 0xee,
0xff, 0xed, 0xff, 0xcc, 0xff, 0x6a, 0xff, 0x6e, 0xe6, 0x20, 0x18, 0x00, 0x28,
0x4b, 0xd5, 0xc0, 0xfd, 0xe0, 0xfd, 0x40, 0xfe, 0x61, 0xfe, 0xc4, 0xfe, 0x06,
0xff, 0x26, 0xff, 0x27, 0xff, 0x46, 0xff, 0xe6, 0xfe, 0xc4, 0xfe, 0x83, 0xfe,
0x21, 0xfe, 0x80, 0xf5, 0x00, 0x28, 0x0a, 0xdd, 0x00, 0xfd, 0x20, 0xfd, 0x40,
0xfd, 0x60, 0xfd, 0x80, 0xfd, 0xa0, 0xfd, 0xc0, 0xfd, 0xe0, 0xfd, 0xe0, 0xfd,
0xe0, 0xfd, 0xa0, 0xfd, 0x80, 0xfd, 0xa1, 0xfc, 0x40, 0xfc, 0x00, 0x38, 0x48,
0xab, 0xc0, 0xf3, 0x62, 0xfc, 0xe0, 0xfc, 0xe0, 0xfc, 0xe0, 0xfc, 0xc0, 0xfc,
0xe0, 0xfc, 0xe0, 0xfc, 0x00, 0xfd, 0xe0, 0xfc, 0x40, 0xfc, 0xe0, 0xf3, 0xa0,
0xdb, 0x60, 0xd3, 0x00, 0x10, 0xc3, 0x51, 0x40, 0xa0, 0x01, 0xb9, 0xe0, 0xd1,
0x81, 0xe2, 0xa0, 0xda, 0xe0, 0xe2, 0xc0, 0xe2, 0xc0, 0xe2, 0xa0, 0xe2, 0x20,
0xf3, 0xc1, 0xcc, 0x60, 0xc4, 0xe0, 0x55, 0x40, 0x66, 0xc0, 0x00, 0x86, 0x3b,
0x21, 0x99, 0x80, 0x80, 0x00, 0x98, 0xe2, 0xb0, 0xa1, 0xda, 0x20, 0xca, 0xa0,
0xca, 0xa2, 0xeb, 0x20, 0xdd, 0x81, 0xe5, 0xc0, 0xee, 0x62, 0xff, 0xc3, 0x76,
0x00, 0x35, 0x20, 0x01, 0x88, 0x65, 0x03, 0x6c, 0x80, 0x3a, 0x00, 0x69, 0x42,
0x9a, 0x60, 0xcd, 0x23, 0xff, 0xc2, 0xff, 0xa0, 0xe6, 0x03, 0x9c, 0x60, 0x6a,
0xa0, 0x5a, 0x63, 0x9c, 0x60, 0x15, 0xa0, 0x25, 0xc0, 0x00, 0xa8, 0x64, 0x20,
0x0d, 0xe0, 0x04, 0xc0, 0x0c, 0xa0, 0x04, 0x00, 0x14, 0x65, 0x66, 0x44, 0x6e,
0xc0, 0x1b, 0x20, 0x14, 0xc2, 0x24, 0x60, 0x04, 0x40, 0x04, 0x40, 0x3c, 0xa1,
0x44, 0x00, 0x30, 0x67, 0xb3, 0x02, 0xca, 0x40, 0xb1, 0xa0, 0x71, 0x00, 0x7a,
0xa0, 0x03, 0xc0, 0x03, 0x20, 0x0c, 0x60, 0x14, 0xc0, 0x63, 0x20, 0x74, 0x20,
0x99, 0x40, 0x99, 0xa0, 0xd9, 0x20, 0xea, 0x00, 0x30, 0xaa, 0xcc, 0x40, 0xfc,
0xe0, 0xfb, 0x40, 0xfb, 0xe0, 0xfa, 0xc0, 0xda, 0x40, 0xca, 0xa0, 0xda, 0xe1,
0xe2, 0x60, 0xf2, 0xa1, 0xfa, 0x60, 0xfb, 0x81, 0xfb, 0x00, 0xfc, 0xc0, 0xf3,
0x00, 0x00, 0x00, 0x00, 0x41, 0xfc, 0xe0, 0xfb, 0x00, 0xf4, 0x40, 0xfc, 0x00,
0xfc, 0x40, 0xfc, 0x20, 0xfc, 0x20, 0xfc, 0x60, 0xfc, 0x80, 0xfc, 0x60, 0xfc,
0x40, 0xfc, 0x8a, 0xd4, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00
};  // don't forget the trailing semicolon

And paint it to the screen with this simple function:

Code: Select all

void drawBitmap(OLED *oled, prog_char *bitmap, int width, int height, int at_x, int at_y)
{
    Colour rgb;
    
    for (int i=0; i<height; i++)
    {
        for (int j=0; j<width; j++)
        {
            int pixel = pgm_read_word(bitmap);
            bitmap += sizeof(int);
            
            rgb.red   = (unsigned char) ((pixel & 0xf800) >> 11);
            rgb.green = (unsigned char) ((pixel & 0x07e0) >>  5);
            rgb.blue  = (unsigned char) (pixel & 0x001f);
            
            oled->setPixel(at_x + j, at_y + i, rgb);
        }
    }
}

...
    // paint a hamburger roughly in the middle of the screen (i.e.: at 60, 60)
    drawBitmap(&oled, hamburger, 16, 16, 60, 60);
...

It's not fast, and you will need to rotate your bitmap to suit the display. but if you just want a quick image or symbol, this method can take less memory than using a BMP with the bitmap function. Trim off any empty rows of the bitmap that are a constants colour.

angusgr
Freetronics Staff
Freetronics Staff
Posts: 853
Joined: Tue Apr 09, 2013 11:19 pm
Location: Melbourne, Australia
Contact:

Re: Quick tiny bitmaps from PROGMEM

Post by angusgr » Thu Jul 03, 2014 2:12 am

Very nice trick, krt. Thanks for sharing it.

Something I considered when writing FTOLED is a formatting tool for "raw" bitmap data similar to this. The FTOLED controller (SSD1351) supports just declaring a region to draw into and then outputting bitmap data directly as a stream (this is ultimately how all of the pixel writes occur.) So in theory it should be possible to write a tool that formats a bitmap image in SSD1351-compatible data, similar to the ffmpeg step you're running trhere. Then you can literally write that raw data from PROGMEM (or an SD card) onto the display.

In the end the BMP support seemed fast enough for most purposes so I dropped the idea from FTOLED, but it would save a similar amount of space while allowing fast drawing operations.

- Angus

Post Reply