Programming with wxBitmap
These are some of the things you can do with a wxBitmap:
- Draw it on a window via a device context.
- Use it as a bitmap label for classes such as wxBitmapButton, wxStaticBitmap, and wxToolBar.
- Use it to implement double buffering (drawing into an off-screen wxMemoryDC before drawing to a window).
On some platforms (in particular, Windows), the bitmap is a limited resource, so if you have many images to store in memory, you may prefer to work mainly with wxImage objects and convert to a temporary wxBitmap when drawing on a device context.Before discussing how to create wxBitmap and draw with it, let's summarize the main functions (Table 10-2).
| wxBitmap | A bitmap can be created given a width and height, another bitmap, a wxImage, XPM data (char**), raw data (char[]), or a file name and type. |
| ConvertToImage | Converts to a wxImage, preserving transparency. |
| CopyFromIcon | Creates the bitmap from a wxIcon. |
| Create | Creates the bitmap from data or a given size. |
| GetWidth, GetHeight | Returns the bitmap's size. |
| Getdepth | Returns the bitmap's color depth. |
| GetMask, SetMask | Returns the wxMask object or NULL. |
| GetSubBitmap | Returns an area of the bitmap as a new bitmap. |
| LoadFile, SaveFile | Files can be loaded and (for some formats) saved. |
| Ok | Returns TRue if the bitmap's data is present. |
Creating a wxBitmap
There are several ways to create a wxBitmap object.You can create the object in an uninitialized state (no bitmap data) by using the default constructor. You will need to call Create or LoadFile or assign another bitmap to it to do anything useful with the object.You can create a wxBitmap with a given size and depth. The bitmap will be filled with random data, so for this object to be useful, you will need to draw on it. The following code creates a 200 x 100 pixel bitmap and gives it a white background.
You can create a bitmap from an image object, preserving any mask or alpha channel in the original image:
// Create a 200x100 bitmap with the current display depth
wxBitmap bitmap(200, 100, -1);
// Create a memory device context
wxMemoryDC dc;
// Select the bitmap into the DC
dc.SelectObject(bitmap);
// Set the background
dc.SetBackground(*wxWHITE_BRUSH);
// Color the bitmap white
dc.Clear();
// Select the bitmap out of the DC
dc.SelectObject(wxNullBitmap);
A bitmap can also be constructed from an icon by using CopyFromIcon:
// Load an image
wxImage image(wxT("image.png"), wxBITMAP_TYPE_PNG);
// Convert it to a bitmap
wxBitmap bitmap(image);
Or you can load a bitmap from a file:
// Load an icon
wxIcon icon(wxT("image.xpm"), wxBITMAP_TYPE_XPM);
// Convert it to a bitmap
wxBitmap bitmap;
bitmap.CopyFromIcon(icon);
wxBitmap can load all the file types that wxImage can (see Table 10-7), by using either wxImage or a more efficient platform-specific implementation for certain file types. Some of the most popular formats are PNG, JPEG, TIFF, BMP, and XPM, which are available on all platforms for both loading and saving, assuming that wxWidgets support for these formats has been enabled.
// Load from a file
wxBitmap bitmap(wxT("picture.png", wxBITMAP_TYPE_PNG);
if (!bitmap.Ok())
{
wxMessageBox(wxT("Sorry, could not load file."));
}
This will load the resource named picture from the executable on Windows and OS/2, and on all other platforms, it will load an XPM from the picture_xpm variable. However, the XPM format is supported on all platforms, so use of this macro is not usually necessary.
#if !defined(__WXMSW__) && !defined(__WXPM__)
#include "picture.xpm"
#endif
wxBitmap bitmap(wxBITMAP(picture));
Setting a wxMask
Each wxBitmap object can contain a wxMask, a monochrome bitmap that indicates the transparent areas of the main bitmap. This will be created automatically when you load a transparent image, for example using XPM, PNG, or GIF, but you can also create it programmatically and assign it to a bitmap with SetMask. You can create a wxMask object from a wxBitmap, or a wxBitmap plus a color to indicate the transparent area.The following example creates a monochrome transparent image called mainBitmap, 32 pixels wide by 32 pixels high, from bitmap data (imageBits) and a mask (maskBits) where 1 is black and 0 is white for the bits, and 1 is opaque and 0 is transparent for the mask.
static char imageBits[] = { 255, 255, 255, 255, 31,
255, 255, 255, 31, 255, 255, 255, 31, 255, 255, 255,
31, 255, 255, 255, 31, 255, 255, 255, 31, 255, 255,
255, 31, 255, 255, 255, 31, 255, 255, 255, 25, 243,
255, 255, 19, 249, 255, 255, 7, 252, 255, 255, 15, 254,
255, 255, 31, 255, 255, 255, 191, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255 };
static char maskBits[] = { 240, 1, 0, 0, 240, 1,
0, 0, 240, 1, 0, 0, 240, 1, 0, 0, 240, 1, 0, 0, 240, 1,
0, 0, 240, 1, 0, 0, 240, 1, 0, 0, 255, 31, 0, 0, 255,
31, 0, 0, 254, 15, 0, 0, 252, 7, 0, 0, 248, 3, 0, 0,
240, 1, 0, 0, 224, 0, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0 };
wxBitmap mainBitmap(imageBits, 32, 32);
wxBitmap maskBitmap(maskBits, 32, 32);
mainBitmap.SetMask(new wxMask(maskBitmap));
The XPM Format
Where small bitmaps with transparency are needed, for example as toolbar buttons or bitmaps in notebooks and tree controls, wxWidgets programmers often use XPM. One advantage of this format is that it uses C/C++ syntax, and it can either be loaded dynamically or compiled into your program. Here's an example.
As you can see, XPMs are encoded using character data. Before the image data, there is a palette section that maps each character to its color, either as an identifier or as a hash-prefixed six-digit hexadecimal string. Using the identifier None causes this character to represent the transparent area in the bitmap. Although XPM support is uncommon among Windows image manipulation programs, you can create images as PNGs and convert to XPM using a tool such as ImageBlocks (bundled with DialogBlocks), or you can simply write your own converter using wxWidgets.
// You can also use #include "open.xpm"
static char *open_xpm[] = {
/* columns rows colors chars-per-pixel */
"16 15 5 1",
" c None",
". c Black",
"X c Yellow",
"o c Gray100",
"O c #bfbf00",
/* pixels */
" ",
" ... ",
" . . .",
" ..",
" ... ...",
" .XoX....... ",
" .oXoXoXoXo. ",
" .XoXoXoXoX. ",
" .oXoX..........",
" .XoX.OOOOOOOOO.",
" .oo.OOOOOOOOO. ",
" .X.OOOOOOOOO. ",
" ..OOOOOOOOO. ",
" ........... ",
" "
};
wxBitmap bitmap(open_xpm);
Drawing with Bitmaps
You can draw with a bitmap in a couple different ways. You can associate it with a memory device context (wxMemoryDC) and then use wxDC::Blit to transfer the contents of the bitmap to another device context. Or, you can use the simpler wxDC::DrawBitmap. In either case, if the bitmap is transparent or has an alpha channel, you can specify transparent drawing by passing true to the function.The two methods are illustrated in the following.
Chapter 5, "Drawing and Printing," discusses drawing with bitmaps in more detail.
// Draw a bitmap using a wxMemoryDC
wxMemoryDC memDC;
memDC.SelectObject(bitmap);
// Draw the bitmap at 100, 100 on the destination DC
destDC.Blit(100, 100, // Draw at (100, 100)
bitmap.GetWidth(), bitmap.GetHeight(), // Draw full bitmap
& memDC, // Draw from memDC
0, 0, // Draw from bitmap origin
wxCOPY, // Logical operation
true); // Take mask into account
memDC.SelectObject(wxNullBitmap);
// Alternative method: use DrawBitmap
destDC.DrawBitmap(bitmap, 100, 100, true);
Packaging Bitmap Resources
If you come from a Windows programming background, you are accustomed to loading bitmaps from the resource section of the executable. You can still do this by passing a resource name and the wxBITMAP_TYPE_BMP_RESOURCE type to the constructor, but you are likely to want a less platform-specific method.A portable way to package resources, whether they are bitmaps, HTML files, or other files required by an application, is to store them in a single zip file alongside the executable or in a separate data folder. Then you can use the virtual file system functionality in wxWidgets to load the image directly from the zip file, as the following fragment shows.
For more information about virtual file systems, please see Chapter 14, "Files and Streams."
// Create a new file system object
wxFileSystem*fileSystem = new wxFileSystem;
wxString archiveURL(wxT("myapp.bin"));
wxString filename(wxT("myimage.png"));
wxBitmapType bitmapType = wxBITMAP_TYPE_PNG;
// Create a URL
wxString combinedURL(archiveURL + wxString(wxT("#zip:")) + filename);
wxImage image;
wxBitmap bitmap;
// Open the file in the archive
wxFSFile* file = fileSystem->OpenFile(combinedURL);
if (file)
{
wxInputStream* stream = file->GetStream();
// Load and convert to a bitmap
if (image.LoadFile(* stream, bitmapType))
bitmap = wxBitmap(image);
delete file;
}
delete fileSystem;
if (bitmap.Ok())
{
...
}