Updated on 2022-07-05
Easily embed image data into your code
If you've coded significantly for IoT, you've probably run into situations where you need bitmapped pixel data from images made available to your code. These little devices can't just take JPG or PNG resources and display them.
IoT may not be the only time you need something like this. It may be useful for embedding little toolbar or icon images if you're targeting platforms that don't have a resource fork in the binary.
First, there are two executables: img2cpp and img2cppw. They both do the same thing, but the former is a command line tool and the latter is a GUI based tool. Let's take a look at the usage screen for the command line tool, which will help clarify both:
Usage: img2cpp.exe <imagefile> [/name <name>] [/jpg|/16bpp]
[/gfx14|/gfx17] [/be]
[/resize [<width>][x<height>]]
[/arduino] [/out: <headerfile>]
<imagefile> The image to convert
<name> The base name to use in the header
<jpg> Embed as JPG image
<16bpp> Convert to 16bpp
<gfx14/gfx17> Use gfx14 or 17 bindings
<be> Use big-endian format
<resize> Resize the image. If one dimension
isn't specified, the aspect ratio
is preserved.
<arduino> Create code for Arduino
<headerfile> The output header to generate
imagefile can be any image.
The name will indicate the name of the image in your code. Depending on the code generated, referring to this name will either get you to the byte array for the pixels (cpp), or to the actual bitmap for the pixels (gfx14/gfx17). Referring to
jpg indicates that the embedded data will be a JPG stream. This option is not compatible with be or 16bpp.
16bpp means the pixel data should be converted to RGB565 format. Otherwise, it will be RGB888.
gfx14/gfx17 indicates that code will be generated that uses the htcw_gfx graphics library, using either the C++14 or the C++17 standard.
be indicates that big endian output should be used. Often, for IoT, this is the case, since most of the display controllers expect pixel data in big endian format.
resize indicates that the image should be resized. The format is
arduino indicates that code should be generated for the Arduino framework. The array will be created in program flash (PROGMEM).
headerfile indicates the output file to use. If the command line doesn't specify this, output is directed to stdout.
Once your header file is generated and included into your project, how you use it depends on the type of code generated. The following snippets assume name from above is my_image.
// the raw pixel data:
const uint8_t* px0ptr = my_image;
// the size of the bitmap
uint16_t width = my_image_size.width;
uint16_t height = my_image_size.height;
There is of course, no drawing code included with this. It's up to you to render or otherwise use the pixel data in your code.
// the raw pixel data (not needed):
const uint8_t* px0ptr = my_image_data;
// the size of the bitmap (not needed)
uint16_t width = my_image_size.width;
uint16_t height = my_image_size.height;
// the bitmap (use this)
my_image_t bmp = my_image;
With htcw_gfx, you can draw my_image to your lcd like so:
draw::bitmap(lcd,lcd.bounds(),my_image,my_image.bounds());
I haven't tested all combinations of options yet. If you find something that doesn't work for you, leave a remark in the comments and I'll get on it.