Brushes and Bitmaps

When you use the CreatePatternBrush or CreateBrushIndirect function with the lbStyle field set to BS_PATTERN, you first need a handle to a bitmap. The bitmap must be least 8 pixels wide and 8 pixels high. If it's larger, Windows uses only the upper left corner of the bitmap for the brush.

Because brushes and bitmaps are GDI objects, you must delete any that you create in your program before the program terminates. When you create a brush based on a bitmap, Windows makes a copy of the bitmap bits for use when drawing with the brush. You can delete the bitmap immediately after calling CreatePatternBrush (or CreateBrushIndirect) without affecting the brush. Similarly, you can delete the brush without affecting the bitmap.

One method of getting a handle to a bitmap was discussed in Chapter 8. You can use SDKPAINT to create a bitmap file (with the extension .BMP), include that filename in a BITMAP statement in the resource script, and then load the bitmap into your program. The LoadBitmap function returns a handle of type HBITMAP:

hBitmap = LoadBitmap (hInstance, lpszBitmap) ;

The variable lpszBitmap is the name of the bitmap in the resource script file.

The second method of getting a handle to a bitmap is to use this function:

hBitmap = CreateBitmap (nWidth, nHeight, nPlanes, nBitsPixel, lpBits) ;

To create a bitmap to use for a brush, nWidth and nHeight should both be set to 8. If you want a monochrome bitmap, nPlanes and nBitsPixel should both be set to 1. The variable lpBits is a long pointer to an array of bytes containing the pixel pattern of the bitmap. You can set this parameter to NULL if you want to create an uninitialized bitmap, in which case the bitmap will contain random data.

The third method of getting a handle to a bitmap is this:

hBitmap = CreateCompatibleBitmap (hdc, nWidth, nHeight) ;

This creates a bitmap with the same number of color planes and the same number of color bits per pixel as the device context indicated by hdc. (The only reason this function requires hdc is to get this color information.) The bitmap initially contains random data.

The final method for getting a handle to a bitmap requires a pointer to a structure (here named bitmap) of type BITMAP:

hBitmap = CreateBitmapIndirect (&bitmap) ;

Watch out for the difference between the types HBITMAP and BITMAP. HBITMAP is a handle to a bitmap. BITMAP is a structure that describes the bitmap. The BITMAP structure has seven fields, as described in the following list. Five of them are similar to the parameters of the CreateBitmap function.

bmType Set to 0
bmWidth Width of bitmap in pixels
bmHeight Height of bitmap in pixels
bmWidthBytes Number of bytes in each raster line
bmPlanes Number of color planes
bmBitsPixel Number of adjacent color bits per pixel
bmBits Far pointer to an array of bytes containing the bitmap pattern

When you have a handle to a bitmap, you can use GetObject to obtain information about the bitmap:

GetObject (hBitmap, sizeof (BITMAP), (LPSTR) &bitmap) ;

where bitmap is a structure of type BITMAP. However, GetObject does not copy a valid far pointer into the bmBits field. To get the actual bits that make up the bitmap, you can call:

GetBitmapBits (hBitmap, dwCount, lpBits) ;

GetBitmapBits copies dwCount number of bytes into an array whose address is lpBits. You can also set the bits of a bitmap using the SetBitmapBits function:

SetBitmapBits (hBitmap, dwCount, lpBits) ;

The bmBits field of the BITMAP structure and the lpBits parameter of the CreateBitmap, SetBitmapBits, and GetBitmapBits functions are far pointers to an array of bytes that define the bitmap pattern. The array of bytes begins with the top scan line. Color bitmaps may be organized with multiple bits per pixel or multiple color planes per scan line. (I'll discuss this more in the next chapter.) If you wish to use a bitmap as a brush and be assured that it will work on all devices, use a monochrome bitmap.

The total size of this array of bytes is equal to (using the fields of the logical bitmap structure):

bmPlanes * bmHeight * bmWidthBytes

The bmWidthBytes field is the width of each scan line in bytes. This value must be the even number equal to or the next even number greater than:

bmWidth * bmBitsPixel / 8

In other words, each scan line is padded with bytes if necessary to get an integral number of words. The scan line is padded at the right because the bytes are arranged from left to right. The most significant bit of the first byte is the leftmost pixel.