There are the following possibilities with image files:
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.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.Platform-specific strategy: use whatever is the standard way for the current platform meaning:Resource section of the files under Windows (see #Embedding PNG images into Windows rc file).A file in application bundle directory under OS X (see #Putting PNG images in OS X resources).Using one of the previous two approaches for the other platforms, including Linux.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 executablesFiles 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 listComparisonToolInput filesOutput filesVar namesRatio out:in (avg.)Source outputhxtools bin2cmultiple arbitrary.h, .c(pp)+.hbased on path and filename, trimmable~2.74 (ultra mode), ~4.47 (std)raw, wxBitmapSigala bin2c/Cmultiple arbitrary.hno6.0rawSigala bin2c/P*single arbitrary.hbased on filename only6.0rawwx/Leoni png2csingle PNG.hno6.0rawwxInclude???6.0rawThe 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 bin2cThe 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.pngand the main Makefile.am to generate and build:
BUILT_SOURCES = images.cpp images.hppCLEANFILES = images.cpp images.hppinclude images.amimages.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.hppIf 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 */bin2c_init_IMAGES_HPP();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 bin2cS.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 Nicola Leoni
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.
wxIncludeAnother 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.pngMost useful is --input-type=.png this will convert all png files in the directory.
InclusionOnce 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.)
NotesRemember 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 fileUnder 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:
RCDATA""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; DWORDa_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; HRSRCa_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 resourcesUnder 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.