Intro
Most of my blog posts share info about a general topic or highlight something interesting that I've discovered. This post will be essentially a tutorial or "how-to". Users of my display libraries probably know that they support Windows BMP files as a source of graphics. My latest eink libraries (both SPI and parallel - bb_epaper, FastEPD) both support this format in addition to a special lossless compression format I call Group5. It's challenging to describe in a few words what type of images will work correctly in both of these formats, so this article will walk through the steps needed to prepare graphics for eink projects.
What's inside of the file?
One of the first challenges of working with any image file format is that each file format can support quite a long list of different types of data within it. The two main variables are bit depth and compression options. Bit depth is probably the most confounding issue because it can be hidden in plain sight. What I mean is that two images can look identical, but have very different data inside.

The image above is a PNG file. To any observer, it is clearly a smiley face in pure black and pure white colors. The problem is that pure black and white can be represented by as few as 1-bpp (bit per pixel) and as many as 32. Looking at the image doesn't give any clues about the way the pixels are stored because there are only two unique colors visible. Storing the image as 1-bpp obviously requires less storage space compared to storing it as 32-bpp. Even if you apply something like PNG-style compression, the more bits per pixel of the original image, the larger the compressed file will be too. The reason I'm calling attention to this issue is because eink displays normally support 1, 2 or 4-bpp (2/4/16 gray levels). Understanding pixel bit depth is quite useful when preparing images for eink projects.
The Tools
There are many programs/apps that people use to draw and prepare graphics. I'm not an artist, so my use of these tools is much more limited. I use them simply for modifying existing graphics (touch-ups, resizing, cropping, etc). One tool that exists on every operating system and doesn't cost anything is Gimp. It's not necessarily user friendly, but it can do everything we need. I'll start with an image that's in need of adjustment. I found this "smiley" image that's 8-bit grayscale on a transparent background:

Gimp uses the checkered background to indicate that it's a transparent color. If you look closely at the smiley, you can see that it has highlighting which has the appearance of a light source coming from the upper left corner. At this point I can resize it, or crop it smaller to remove the blank edges around the interesting part. After making these types of adjustments, this image is still not ready to be displayed on a 1-bit eink panel. To convert the grayscale values into pure black and white, I can simply tell Gimp to change it to an indexed image with 2 possible colors. A better way is to use the threshold feature under the Colors menu:

With the slider in the threshold window, I can determine what gray level separates black from white. Once I've settled on a threshold level and clicked the ok button, the image becomes pure black and pure white, but...it's still 8 bits per pixel (in this case) or 24 or 32 depending on what you started with. The Image->Mode menu allows you to choose RGB, grayscale or indexed (24/32-bpp, 8-bit grayscale, 8 or fewer bits of color palette). My image is currently indexed 8-bpp. Gimp doesn't seem to offer a way to change an indexed image into a different bit depth directly, so in order to turn it into 1-bpp, I need to first switch to RGB mode (24bpp) and then select indexed mode again. This will allow me to choose 1-bit (2 colors):

Since the image is already pure black and white, asking Gimp to generate an "optimum palette" is safe because it can't choose any unwanted colors. Now that I've got a 1-bit image, I need to export it into a file. By default, Gimp will try to save images in its proprietary xcf format. This format supports multiple image layers and, as far as I know, is only readable in Gimp. Therefore we need to use "Export As" to save it in a different format - Windows BMP. Gimp's "Export As" feature only knows what format you want to use based on the filename extension (e.g. jpg, bmp, png). If I choose the name smiley.bmp, it will create the desired type (Windows BMP). If the image being exported has a higher bit depth, a set of options will pop up for how to save it. 1-bpp BMP files have no options, so it doesn't need to ask. Now that I've got a 1-bpp BMP file, I can use my imgconvert tool to compress it with my "Group5" image compression. This is a modified version of Group 4 FAX compression. It does really well at losslessly compressing images with large, smooth black and white areas or text. In the imageconvert folder of bb_epaper and FastEPD is the tool I wrote to read Windows BMP images and compress them into G5 format. I recently added the ability to automatically threshold 4/8/16/24/32-bit images to 1-bpp before compressing them. It assumes a middle point between black and white which may not be ideal, so it's best to provide it with 1-bpp images. For the safety of end users, I don't provide executables in my repos, so you'll need to build it first:

For this smiley BMP image, I had resized it to 100x100 pixels. By specifying a name extension of .H for the output file (smiley.h), it tells the imgconvert tool to generate a .H file after compressing the image to G5. This H file can now be directly included in my Arduino project and only takes 232 bytes of FLASH space:
The G5 file format uses an 8-byte header with the "magic" word followed by the image dimensions, so the final size of the header plus compressed data is 240 bytes. I added a "images_and_icons" example sketch to show how to use these compressed images. The loadG5Image() method now allows a floating point scale factor. Here's the code which draws the smiley:
...and here's the result on the eink display:
Comments
Post a Comment