Img2Cpp: Create C++ Headers for Embedding Images

Updated on 2022-07-05

Easily embed image data into your code

Introduction

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.

Using this Mess

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 _size will get you to a struct that indicates the size of the bitmap.

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.

htcw_gfx

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 x to resize for both the width and the height, , to resize the width and maintain the aspect ratio or x to do the same but with the height.

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.

Coding this Mess

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.

Standard C++

// 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.

gfx14/gfx17

// 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());

Disclaimer

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.

History

  • 29th June, 2022 - Initial submission
  • 29th June, 2022 - Fixed bug with jpg generation under gfx