Bitmaps
Bitmaps are graphical objects that can be used to create, draw, manipulate, and retrieve images in a device context. Bitmaps are everywhere within Windows, from the little Windows logo on the Start button to the Close button on the title bar. Think of a bitmap as a picture composed of an array of pixels that can be painted onto the screen. Like any picture, a bitmap has height and width. It also has a method for determining what color or colors it uses. Finally, a bitmap has an array of bits that describe each pixel in the bitmap.Historically, bitmaps under Windows have been divided into two types; device-dependent bitmaps (DDBs) and device-independent bitmaps (DIBs). DDBs are bitmaps that are tied to the characteristics of a specific DC and can't easily be rendered on DCs with different characteristics. DIBs, on the other hand, are independent of any device and therefore must carry around enough information so that they can be rendered accurately on any device.Windows CE contains many of the bitmap functions available in other versions of Windows. The differences include a new four-color bitmap format not supported anywhere but on Windows CE and a different method for manipulating DIBs.
Device-Dependent Bitmaps
A device-dependent bitmap can be created with this function:
HBITMAP CreateBitmap (int nWidth, int nHeight, UINT cPlanes,
UINT cBitsPerPel, CONST VOID *lpvBits);
The nWidth and nHeight parameters indicate the dimensions of the bitmap. The cPlanes parameter is a historical artifact from the days when display hardware implemented each color within a pixel in a different hardware plane. For Windows CE, this parameter must be set to 1. The cBitspPerPel parameter indicates the number of bits used to describe each pixel. The number of colors is 2 to the power of the cBitspPerPel parameter. Under Windows CE, the allowable values are 1, 2, 4, 8, 16, and 24. As I said, the four-color bitmap is unique to Windows CE and isn't supported under other Windows platforms.The final parameter is a pointer to the bits of the bitmap. Under Windows CE, the bits are always arranged in a packed pixel format; that is, each pixel is stored as a series of bits within a byte, with the next pixel starting immediately after the first. The first pixel in the array of bits is the pixel located in the upper left corner of the bitmap. The bits continue across the top row of the bitmap, then across the second row, and so on. Each row of the bitmap must be double-word (4-byte) aligned. If any pad bytes are required at the end of a row to align the start of the next row, they should be set to 0. Figure 2-5 illustrates this scheme, showing a 126-by-64-pixel bitmap with 8 bits per pixel.

Figure 2-5: Layout of bytes within a bitmap
The function
HBITMAP CreateCompatibleBitmap (HDC hdc, int nWidth, int nHeight);
creates a bitmap whose format is compatible with the device context passed to the function. So if the device context is a four-color DC, the resulting bitmap is a four-color bitmap as well. This function comes in handy when you're manipulating images on the screen because it makes it easy to produce a blank bitmap that's directly color compatible with the screen.
Device-Independent Bitmaps
The fundamental difference between DIBs and their device-dependent cousins is that the image stored in a DIB comes with its own color information. Almost every bitmap file since Windows 3.0, which used the files with the BMP extension, contains information that can be directly matched with the information needed to create a DIB in Windows.In the early days of Windows, it was a rite of passage for a programmer to write a routine that manually read a DIB file and converted the data to a bitmap. These days, the same arduous task can be accomplished with the following function, unique to Windows CE:
HBITMAP SHLoadDIBitmap (LPCTSTR szFileName);
It loads a bitmap directly from a bitmap file and provides a handle to the bitmap. In Windows XP the same process can be accomplished with LoadImage using the LR_LOADFROMFILE flag, but this flag isn't supported under the Windows CE implementation of LoadImage.
DIB Sections
While Windows CE makes it easy to load a bitmap file, sometimes you must read what is on the screen, manipulate it, and redraw the image back to the screen. This is another case in which DIBs are better than DDBs. While the bits of a device-dependent bitmap are obtainable, the format of the buffer is directly dependent on the screen format. By using a DIB, or more precisely, something called a DIB section, your program can read the bitmap into a buffer that has a predefined format without worrying about the format of the display device.While Windows has a number of DIB creation functions that have been added over the years since Windows 3.0, Windows CE carries over only a handful of DIB functions from Windows XP. Here is the first of these functions:
HBITMAP CreateDIBSection (HDC hdc, const BITMAPINFO *pbmi,
UINT iUsage, void *ppvBits,
HANDLE hSection, DWORD dwOffset);
Because they're a rather late addition to the Win32 API, DIB sections might be new to Windows programmers. DIB sections were invented to improve the performance of applications on Windows NT that directly manipulated bitmaps. In short, a DIB section allows a programmer to select a DIB in a device context while still maintaining direct access to the bits that compose the bitmap. To achieve this, a DIB section associates a memory DC with a buffer that also contains the bits of that DC. Because the image is mapped to a DC, other graphics calls can be made to modify the image. At the same time, the raw bits of the DC, in DIB format, are available for direct manipulation. While the improved performance is all well and good on Windows NT, the relevance to the Windows CE programmer is the ease with which an application can work with bitmaps and manipulate their contents.This call's parameters lead with the pointer to a BITMAPINFO structure. The structure describes the layout and color composition of a device-independent bitmap and is a combination of a BITMAPINFOHEADER structure and an array of RGBQUAD values that represent the palette of colors used by the bitmap.The BITMAPINFOHEADER structure is defined as the following:
typedef struct tagBITMAPINFOHEADER{
DWORD biSize;
LONG biWidth;
LONG biHeight;
WORD biPlanes;
WORD biBitCount;
DWORD biCompression;
DWORD biSizeImage;
LONG biXPelsPerMeter;
LONG biYPelsPerMeter;
DWORD biClrUsed;
DWORD biClrImportant;
} BITMAPINFOHEADER;
As you can see, this structure contains much more information than just the parameters passed to CreateBitmap. The first field is the size of the structure and must be filled in by the calling program to differentiate this structure from the similar BITMAPCOREINFOHEADER structure that's a holdover from the OS/2 presentation manager. The biWidth, biHeight, biPlanes, and biBitCount fields are similar to their like-named parameters to the CreateBitmap call—with one exception. The sign of the biHeight field specifies the organization of the bit array. If biHeight is negative, the bit array is organized in a top-down format, as is CreateBitmap. If biHeight is positive, the array is organized in a bottom-up format, in which the bottom row of the bitmap is defined by the first bits in the array. As with the CreateBitmap call, the biPlanes field must be set to 1.The biCompression field specifies the compression method used in the bit array. Under Windows CE, the allowable flags for this field are BI_RGB, indicating that the buffer isn't compressed, and BI_BITFIELDS, indicating that the pixel format is specified in the first three entries in the color table. The biSizeImage parameter is used to indicate the size of the bit array; when used with BI_RGB, however, the biSizeImage field can be set to 0, which means that the array size is computed using the dimensions and bits per pixel information provided in the BITMAPINFOHEADER structure.The biXPelsPerMeter and biYPelsPerMeter fields provide information to accurately scale the image. For CreateDIBSection, however, these parameters can be set to 0. The biClrUsed parameter specifies the number of colors in the palette that are actually used. In a 256-color image, the palette will have 256 entries, but the bitmap itself might need only 100 or so distinct colors. This field helps the palette manager, the part of Windows that manages color matching, to match the colors in the system palette with the colors required by the bitmap. The biClrImportant field further defines the colors that are really required as opposed to those that are used. For most color bitmaps, these two fields are set to 0, indicating that all colors are used and that all colors are important.As I mentioned above, an array of RGBQUAD structures immediately follows the BITMAPINFOHEADER structure. The RGBQUAD structure is defined as follows:
typedef struct tagRGBQUAD { /* rgbq */
BYTE rgbBlue;
BYTE rgbGreen;
BYTE rgbRed;
BYTE rgbReserved;
} RGBQUAD;
This structure allows for 256 shades of red, green, and blue. While almost any shade of color can be created using this structure, the color that's actually rendered on the device will, of course, be limited by what the device can display.
The array of RGBQUAD structures, taken as a whole, describe the palette of the DIB. The palette is the list of colors in the bitmap. If a bitmap has a palette, each entry in the bitmap array contains not colors, but an index into the palette that contains the color for that pixel. While redundant on a monochrome bitmap, the palette is quite important when rendering color bitmaps on color devices. For example, a 256-color bitmap has one byte for each pixel, but that byte points to a 24-bit value that represents equal parts red, green, and blue colors. So while a 256-color bitmap can contain only 256 distinct colors, each of those colors can be one of 16 million colors rendered using the 24-bit palette entry. For convenience in a 32-bit world, each palette entry, while containing only 24 bits of color information, is padded out to a 32-bit-wide entry—hence the name of the data type: RGBQUAD.Of the remaining four CreateDIBSection parameters, only two are used under Windows CE. The iUsage parameter indicates how the colors in the palette are represented. If the parameter is DIB_RGB_COLORS, the bits in the bitmap contain the full RGB color information for each pixel. If the parameter is DIB_PAL_COLORS, the bitmap pixels contain indexes into the palette currently selected in the DC. The ppvBits parameter is a pointer to a variable that receives the pointer to the bitmap bits that compose the bitmap image. The final two parameters, hSection and dwOffset, aren't supported under Windows CE and must be set to 0. In other versions of Windows, they allow the bitmap bits to be specified by a memory-mapped file. While Windows CE does support memory-mapped files, they aren't supported by CreateDIBSection.Two functions exist to manage the palette of the DIB, as follows:
UINT GetDIBColorTable (HDC hdc, UINT uStartIndex,
UINT cEntries, RGBQUAD *pColors);
and
UINT SetDIBColorTable (HDC hdc, UINT uStartIndex,
UINT cEntries, RGBQUAD *pColors);
For both of these functions, uStartIndex indicates the first entry into the palette array to set or query. The cEntries parameter indicates how many palette entries to change. The pointer to the RGBQUAD array is the array of colors either being set, for SetDIBColorTable, or queried, for GetDIBColorTable.
Drawing Bitmaps
Creating and loading bitmaps is all well and good, but there's not much point to it unless the bitmaps you create can be rendered on the screen. Drawing a bitmap isn't as straightforward as you might think. Before a bitmap can be drawn in a screen DC, it must be selected into a DC and then copied over to the screen device context. While this process sounds convoluted, there is rhyme to this reason.The process of selecting a bitmap into a device context is similar to selecting a logical font into a device context; it converts the ideal to the actual. Just as Windows finds the best possible match to a requested font, the bitmap selection process must match the available colors of the device to the colors requested by a bitmap. Only after this is done can the bitmap be rendered on the screen. To help with this intermediate step, Windows provides a shadow type of DC, a memory device context.To create a memory device context, use this function:
HDC CreateCompatibleDC (HDC hdc);
This function creates a memory DC that's compatible with the current screen DC. Once created, the source bitmap is selected into this memory DC using the same SelectObject function you used to select a logical font. Finally, the bitmap is copied from the memory DC to the screen DC using one of the bit functions, BitBlt or StretchBlt.The workhorse of bitmap functions is the following:
BOOL BitBlt (HDC hdcDest, int nXDest, int nYDest, int nWidth,
int nHeight, HDC hdcSrc, int nXSrc, int nYSrc,
DWORD dwRop);
Fundamentally, the BitBlt function, pronounced bit blit, is just a fancy memcopy function, but since it operates on device contexts, not memory, it's something far more special. The first parameter is a handle to the destination device context—the DC to which the bitmap is to be copied. The next four parameters specify the location and size of the destination rectangle where the bitmap is to end up. The next three parameters specify the handle to the source device context and the location within that DC of the upper left corner of the source image.The final parameter, dwRop, specifies how the image is to be copied from the source to the destination device contexts. The ROP code defines how the source bitmap and the current destination are combined to produce the final image. The ROP code for a simple copy of the source image is SRCCOPY. The ROP code for combining the source image with the current destination is SRCPAINT. Copying a logically inverted image, essentially a negative of the source image, is accomplished using SRCINVERT. Some ROP codes also combine the currently selected brush into the equation to compute the resulting image. A large number of ROP codes are available, too many for me to cover here. For a complete list, check out the Windows CE programming documentation.
The following code fragment sums up how to paint a bitmap:
// Create a DC that matches the device.
hdcMem = CreateCompatibleDC (hdc);
// Select the bitmap into the compatible device context.
hOldSel = SelectObject (hdcMem, hBitmap);
// Get the bitmap dimensions from the bitmap.
GetObject (hBitmap, sizeof (BITMAP), &bmp);
// Copy the bitmap image from the memory DC to the screen DC.
BitBlt (hdc, rect.left, rect.top, bmp.bmWidth, bmp.bmHeight,
hdcMem, 0, 0, SRCCOPY);
// Restore original bitmap selection and destroy the memory DC.
SelectObject (hdcMem, hOldSel);
DeleteDC (hdcMem);
The memory device context is created, and the bitmap to be painted is selected into that DC. Since you might not have stored the dimensions of the bitmap to be painted, the routine makes a call to GetObject. GetObject returns information about a graphics object, in this case, a bitmap. Information about fonts and other graphic objects can be queried using this useful function. Next, BitBlt is used to copy the bitmap into the screen DC. To clean up, the bitmap is deselected from the memory device context and the memory DC is deleted using DeleteDC. Don't confuse DeleteDC with ReleaseDC, which is used to free a display DC. DeleteDC should be paired only with CreateCompatibleDC, and ReleaseDC should be paired only with GetDC or GetWindowDC.Instead of merely copying the bitmap, stretch or shrink it using this function:
BOOL StretchBlt (HDC hdcDest, int nXOriginDest, int nYOriginDest,
int nWidthDest, int nHeightDest, HDC hdcSrc,
int nXOriginSrc, int nYOriginSrc, int nWidthSrc,
int nHeightSrc, DWORD dwRop);
The parameters in StretchBlt are the same as those used in BitBlt, with the exception that now the width and height of the source image can be specified. Here again, the ROP codes specify how the source and destination are combined to produce the final image.Windows CE also has another bitmap function. It is
BOOL TransparentImage (HDC hdcDest, LONG DstX, LONG DstY, LONG DstCx,
LONG DstCy, HANDLE hSrc, LONG SrcX, LONG SrcY,
LONG SrcCx, LONG SrcCy, COLORREF TransparentColor);
This function is similar to StretchBlt, with two very important exceptions. First, you can specify a color in the bitmap to be the transparent color. When the bitmap is copied to the destination, the pixels in the bitmap that are the transparent color are not copied. The second difference is that the hSrc parameter can be either a device context or a handle to a bitmap, which allows you to bypass the requirement to select the source image into a device context before rendering it on the screen. TransparentImage is essentially the same function as Windows 2000's TransparentBlt function with the exception that TransparentBlt can't directly use a bitmap as the source.As in other versions of Windows, Windows CE supports two other blit functions: PatBlt and MaskBlt. The PatBlt function combines the currently selected brush with the current image in the destination DC to produce the resulting image. I cover brushes later in this chapter. The MaskBlt function is similar to BitBlt but encompasses a masking image that provides the ability to draw only a portion of the source image onto the destination DC.