Embedding PNG Images

From WxWiki
Jump to navigation Jump to search

Possible strategies for handling images

There are the following possibilities with image files:

  1. Load them during run-time. Files can be replaced without rebuilding the program, and may be looked up in different directories, but also requires that such files be distributed alongside the application.
  2. Embed images in the program source code itself. This requires rebuilding the program or parts thereof, but does not require to distribute any separate files. It works under all platforms.
  3. Platform-specific strategy: use whatever is the standard way for the current platform meaning:

The last strategy is the best from wxWidgets philosophy of trying to do everything in the most native way possible. Since version 2.9.5, wxWidgets simplifies its implementation by providing wxBITMAP_PNG() macro that will load the bitmap from the corresponding location depending on the platform, i.e. from the resource section under Windows, a file in the resources directory under OS X or from embedded byte array elsewhere.

Embedding images into executables

Files in the XPM format are made of plain C code already, so they could be easily embedded into C++ code by way of using #include. However, when your master image is in a different format (and it often is), one needs to convert to XPM first. In addition, XPM is uncompressed and does not support an alpha channel (only on-off-transparency), which makes it unsuitable for large images, or images that want to be composited.

As such, preparing JPEG/PNG/etc. images for source code inclusion is not any more work-intensive than XPM in the end.

First of all, you will need a program to convert the byte stream of your image(s) into a C object, like:

static unsigned char myimage_png[] = {
    0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, 
    // ...

Alternative source encodings are of course possible. Using a string literal is generally one of the shorter forms:

 static unsigned char myimage_png[] = "\211PNG\015...";

Different tools to do this exist.

Utility list


Tool Input files Output files Var names Ratio out:in (avg.) Source output
hxtools bin2c multiple arbitrary .h, .c(pp)+.h based on path and filename, trimmable ~2.74 (ultra mode), ~4.47 (std) raw, wxBitmap
Sigala bin2c/C multiple arbitrary .h no 6.0 raw
Sigala bin2c/P* single arbitrary .h based on filename only 6.0 raw
wx/Leoni png2c single PNG .h no 6.0 raw
wxInclude ? ? ? 6.0 raw

The ratio of output bytes to input bytes is taken by (repeatedly) generating a file with some random bytes (openssl rand 10000000), feeding it through the converter and looking at the sizes.

hxtools bin2c

The hxtools implementation of a "bin2c" program provides explict support for wxWidgets. Homepage [1], requires libHX to build.

  • Supports the creation of solitary .h files (meant for #inclusion XPM-style), or .c+.h pairs (for independent compilation) out of zero or more input files with arbitrary content (JPEG, PNG, even non-images).
  • Support for out-of-tree builds and various path-stripping options (since the filename is often used for the variable name).
  • Optional creation of convenient wxBitmap objects (instead of character arrays), directly usable with wxMenu entries, wxButtons, etc. Highly useful if you have a lot of icons.
  • Optional compact source-level encoding with string literals rather than character arrays of number literals.
  • Processes files block-wise (avoids overhead-rich one-char-at-a-time I/O and memory-hungry slurp-whole-file strategies)

If you are using automake, create an images.am file containing the icon list (this is used to detect when this list changes),

imagelist = foo.png bar.png

and the main Makefile.am to generate and build:

BUILT_SOURCES = images.cpp images.hpp
CLEANFILES = images.cpp images.hpp
include images.am
images.cpp images.hpp: images.am ${imagelist}
       ${AM_V_GEN}bin2c --wxbitmap -C images.cpp -D ${srcdir} ${imagelist}
yourprogram_SOURCES = main.cpp main.hpp images.cpp images.hpp

If you chose to use --wxbitmap, you have to initialize the wx image handlers and call a bin2c function to create said bitmap objects from the raw data. In the initialization function of your program — often this is MyApp::OnInit, where MyApp is your wxApp-derived class — this will look like:

bool MyApp::OnInit(void)
        wxImage::AddHandler(new wxPNGHandler()); /* plus any others needed, e.g. JPG */
        return true;

Afterwards, the bitmaps are ready for use:

auto sp = new wxSplashScreen(*bin2c_splash_jpg, wxSPLASH_CENTRE_ON_SCREEN, 0, NULL, wxID_ANY);

Sigala/Leoni bin2c

S.Sigala wrote another bin2c variant, in C, (and a defunct variant with header guards). This produces a solitary .h file with a character array out of exactly one arbitrary file.

There are also other variants in Perl, PHP, Python.

Sandro Sigala <sandro AT sigala DOT it>
Nicola Leoni <nicola AT exilo DOT net>

The wxWidgets 2.9.1+ source tree ships the python script in misc/scripts/png2c.py. (It is uncredited, but judging from the wiki page titles, it may have been authored by Sigala/Leoni.) It produces a solitary .h file with character arrays on stdout out of one or more input files, which strictly have to be PNG.


Another utility for converting more images into one header. It requires a Windows environment (e.g. mingw-w64 or MSVC) due to use of TCHAR, and some old Boost version to build. (boost-1.54 under mingw failed.) Source: [2]. Runtime example:

 wxInclude.exe --const --input-file=mydata1.bin --input-type=.png --input-type=.bmp --output-file=myheader.h mydata2.bin myimage.png

Most useful is --input-type=.png this will convert all png files in the directory.


Once you have converted your graphics files converted with one of the utilities, you need to #include them from your source code to use them. If the conversion program has left you with a pair of .c/.h (or .cpp/.hpp) files, the .c(pp) file contains the actual data and is meant to be compiled using your regular build infrastructure, and the .h(pp) file contains the declarations to use the variables in any other source file. It will perhaps be necessary that you call a function to load all the images; check the .h(pp) file you received.

If you have a solitary .h file, then that leaves you with having to include that to make the raw data available in a particular source file. If you need the image available in multiple source files, you either have to repeatedly #include it per source file (possibly growing the final executable), or constructing additional source code so as to make it available across all translation units.

When dealing with variables containing raw byte streams, you may want to convert them to wxBitmap (if the tool did not already offer you this possibility). Since wxWidgets 2.9.5, you can then use the wxBITMAP_PNG_FROM_DATA macro to create a bitmap from a variable holding raw data:

 wxBitmap bmp = wxBITMAP_PNG_FROM_DATA(myimage);

Notice that this macro appends a "_png" suffix. The macro also requires that myimage_png be an array whose size is determinable (by way of sizeof()). Alternatively, one can directly use the wxMemoryInputStream class, needed if you have non-PNG images:

wxMemoryInputStream istream(myimage_png, sizeof myimage_png);
wxImage myimage_img(istream, wxBITMAP_TYPE_PNG); /* or wxBITMAP_TYPE_ANY, etc. */
wxBitmap myimage_bmp(myimage_img);

Of course, you can define your own macro similar to the one above:

#define wxGetBitmapFromMemory(name) _wxGetBitmapFromMemory(name ## _png, sizeof(name ## _png))
inline wxBitmap _wxGetBitmapFromMemory(const unsigned char *data, int length)
        wxMemoryInputStream is(data, length);
        return wxBitmap(wxImage(is, wxBITMAP_TYPE_ANY, -1), -1);

However, repeatedly parsing the input stream and shoveling it through two conversion (to wxImage, then to wxBitmap) is wasteful, so retaining the wxBitmap object seems preferable. (This is what hxtools's bin2c --wxbitmap would do.)


Remember to add support for your chosen image formats in your wxApp::OnInit() function:

wxImage::AddHandler(new wxPNGHandler);

This technique of embedding an image is also used by the Audacity sound editor (latest CVS only). It has bin2c code built into it and uses wxWidgets code to combine and split PNG images, so that a theme consists of a single large image rather than many small ones.

Embedding data into Windows resource file

Under Windows, it can be desirable to embed the image (or other data) into the application resources instead of application code. One advantage of doing this is that the bitmap can be changed without recompilation, but relinking is still necessary. Another is that standard tools working with the resources can be used.

A file can be included as RCDATA type. (Using the BITMAP leads to essential parts of the data being stripped, and this type would only be useful for .bmp files.) To add a file, add the following line to your .rc file:


NOTE: Since wxWidgets 2.9.5, simply use wxBITMAP_PNG macro described above to load the bitmap. The following instructions are only useful for previous versions.

I use three methods to load the data:

  wxBitmap* CreateBitmapFromPngResource(const wxString& t_name)
     wxBitmap*   r_bitmapPtr = 0;
     char*       a_data      = 0;
     DWORD       a_dataSize  = 0;
     if(LoadDataFromResource(a_data, a_dataSize, t_name))
        r_bitmapPtr = GetBitmapFromMemory(a_data, a_dataSize);
     return r_bitmapPtr;

  bool LoadDataFromResource(char*& t_data, DWORD& t_dataSize, const wxString& t_name)
     bool     r_result    = false;
     HGLOBAL  a_resHandle = 0;
     HRSRC    a_resource;
     a_resource = FindResource(0, t_name.wchar_str(), RT_RCDATA);
     if(0 != a_resource)
        a_resHandle = LoadResource(NULL, a_resource);
        if (0 != a_resHandle)
           t_data = (char*)LockResource(a_resHandle);
           t_dataSize = SizeofResource(NULL, a_resource);
           r_result = true;
     return r_result;

  wxBitmap* GetBitmapFromMemory(const char* t_data, const DWORD t_size)
     wxMemoryInputStream a_is(t_data, t_size);
     return new wxBitmap(wxImage(a_is, wxBITMAP_TYPE_PNG, -1), -1);

The t_name parameter passed to CreateBitmapFromPngResource is the PNG_BITMAP_NAME defined in the RC file.

One thing to be aware of: When you add a PNG resource in Visual Studio 2010, it may define it as "PNG" type rather than "RCDATA", and this method will fail to load them. The easiest way to deal with that is to edit the resource file (.rc) and change the "PNG" entry for each file added to an "RCDATA" entry.

Putting PNG images in OS X resources

Under OS X image files should be put into the Resources subdirectory of the application bundle. This can be done either in the Xcode project or by simply manually copying them there in your makefile. Since wxWidgets 2.9.5 wxBITMAP_PNG macro can be used to load the images from this standard location. With the previous versions you'd need to use wxStandardPaths::GetResourcesDir() manually.