11.2.3 Creating a Bitmap with Hard-Coded Bits

You can create a bitmap and set its initial image to an array of bitmap bits by using the CreateDIBitmap function. This function creates a memory bitmap of a given size with a device-dependent color format; it initializes the bitmap image by translating a device-independent bitmap definition into the device-dependent format required by the display device and copying this device-dependent information to the memory bitmap. Typically, this method is useful for creating small bitmaps for use with pattern brushes, but you may also find it useful for creating larger bitmaps.

Note:

Unless the bitmap is monochrome (that is, having a single color plane and one bit per pixel), the memory bitmap created by CreateBitmap is device-specific and therefore might not be suitable for display on some devices.

The following example creates a 64-by-32-pixel monochrome bitmap; the example initializes the bitmap by using the bits in the array Square.

HBITMAP        hBitmap;
HANDLE         hDibInfo;
PBITMAPINFO    pDibInfo;

BYTE Square[] = {
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0xFF,0xFF,0xFF,0xFF,0x00,0x00,
0x00,0x00,0xFF,0xFF,0xFF,0xFF,0x00,0x00,
0x00,0x00,0xFF,0xFF,0xFF,0xFF,0x00,0x00,
0x00,0x00,0xFF,0xFF,0xFF,0xFF,0x00,0x00,
0x00,0x00,0xFF,0xFF,0xFF,0xFF,0x00,0x00,
0x00,0x00,0xFF,0xFF,0xFF,0xFF,0x00,0x00,
0x00,0x00,0xFF,0xFF,0xFF,0xFF,0x00,0x00,
0x00,0x00,0xFF,0xFF,0xFF,0xFF,0x00,0x00,
0x00,0x00,0xFF,0xFF,0xFF,0xFF,0x00,0x00,
0x00,0x00,0xFF,0xFF,0xFF,0xFF,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 };

if (pDibInfo = (PBITMAPINFO) LocalAlloc(LMEM_FIXED,
        sizeof(BITMAPINFOHEADER) + 2 * sizeof(RGBQUAD))) {
    HBRUSH hOldBrush, hBrush;
    pDibInfo->bmiHeader.biSize = (LONG) sizeof(BITMAPINFOHEADER);
    pDibInfo->bmiHeader.biWidth = 64L;
    pDibInfo->bmiHeader.biHeight = 32;
    pDibInfo->bmiHeader.biPlanes = 1;
    pDibInfo->bmiHeader.biBitCount = 1;
    pDibInfo->bmiHeader.biCompression = 0L;
    pDibInfo->bmiHeader.biSizeImage = 0L;
    pDibInfo->bmiHeader.biXPelsPerMeter = 0L;
    pDibInfo->bmiHeader.biYPelsPerMeter = 0L;
    pDibInfo->bmiHeader.biClrUsed = 0L;
    pDibInfo->bmiHeader.biClrImportant = 0L;
    pDibInfo->bmiColors[0].rgbRed = 0;
    pDibInfo->bmiColors[0].rgbGreen = 0;
    pDibInfo->bmiColors[0].rgbBlue = 0;
    pDibInfo->bmiColors[1].rgbRed = 0xFF;
    pDibInfo->bmiColors[1].rgbGreen = 0xFF;
    pDibInfo->bmiColors[1].rgbBlue = 0xFF;
    hDC = GetDC(hWnd);
    hBitmap = CreateDIBitmap(hDC,
       LPBITMAPINFOHEADER & pDibInfo->bmiHeader, CBM_INIT,
       (LPSTR) Square, (LPBITMAPINFO) pDibInfo, DIB_RGB_COLORS);
            .
            . /* Use the bitmap. */
            .

   ReleaseDC(hWnd, hDC);
   DeleteObject(hBitmap);
   LocalFree((HANDLE) pDibInfo);
}

The CreateDIBitmap function creates and initializes the bitmap before returning the bitmap handle. The width and height of the bitmap are 64 and 32 pixels, respectively. The bitmap has one bit for each pixel, making it a monochrome bitmap.

The Square array contains the bits used to initialize the bitmap. The BITMAPINFO structure determines how the bits in the array are interpreted. It defines the width and height of the bitmap, how many bits (1, 4, 8, or 24) are used in the array to represent each pixel, and a table of colors for the pixels. Since the Square array defines a monochrome bitmap, the bit count per pixel is 1 and the color table contains only two entries, one for black and one for white. If a given bit in the array is 0, GDI draws a black pixel for that bit; if the given bit is 1, GDI draws a white pixel.

Since the Square array defines a monochrome bitmap, you could also use the CreateBitmap function to create the bitmap:

hBitmap = CreateBitmap(64, 32, 1, 1, Square);

This is possible because all monochrome memory bitmaps are device independent. For color bitmaps, however, CreateBitmap cannot use the same bitmap-bit specification as can CreateDIBitmap.

Once you have created and initialized the bitmap, you can use its handle in subsequent GDI functions. If you want to change the bitmap, you can draw in it by selecting it into a memory device context as described in Section 11.2.2, “Creating and Filling a Blank Bitmap.” If you want to replace the bitmap image with another or want to change a portion of it, you can use the SetDIBits function to copy another array of bits into the bitmap. The following example replaces the current bitmap image with the bits in the array Circle:

BYTE Circle[] = {
    .
    .
    .

};

SetDIBits(hDC, hBitmap, 0, 32, Circle,
    (BITMAPINFO FAR*) &myDIBInfo, DIB_RGB_COLORS);

The SetDIBits function copies the bits in the Circle array into the bitmap specified by the hBitmap variable. The array contains 32 scan lines, representing the image of a 64-by-32-pixel monochrome bitmap. If you want to retrieve the current bits in a bitmap before replacing them, you can use the GetDIBits function. This function copies a specified number of scan lines from the bitmap into a device-independent bitmap specification. You can also use GetBitmapBits to retrieve bits from a monochrome bitmap.

Again, since the Circle array defines a monochrome bitmap, you could call SetBitmapBits instead to change the bitmap:

SetBitmapBits(hBitmap, 256, Circle);

The preceding examples show how to create and modify a small bitmap. Typically, you will not want to hard-code larger bitmaps in your application source code. Instead, you can store a larger bitmap in a device-independent bitmap file created by Image Editor or other tools. A device-independent bitmap file consists of a BITMAPFILEHEADER structure followed by a BITMAPINFO structure and an array of bytes that together define the bitmap.

For more information about Windows color palettes, see Chapter 19, “Color Palettes.”