SAMPLE: Changing Color Bitmaps to MonochromeLast reviewed: February 15, 1996Article ID: Q77282 |
The information in this article applies to:
SUMMARYIt is often desirable to convert a color bitmap into a monochrome bitmap so that it can be used to dynamically create a cursor (or icon). The procedure is relatively simple and is described in this article. BIT2MONO is a sample application in the Microsoft Software Library that demonstrates converting a color bitmap to a monochrome bitmap. It also demonstrates the effect of changing the background and text color on a monochrome bitmap. Download BIT2MONO.EXE, a self-extracting file, from the Microsoft Software Library (MSL) on the following services:
MORE INFORMATIONConverting a color bitmap to a monochrome bitmap basically involves three steps:
The following code sample demonstrates this process:
hbmLoaded = LoadBitmap(hInst, "mybitmap"); // convert color bitmap to monochrome hbmMono = ColorDDBToMonoDDB(hbmLoaded, 0, 0, NULL); DeleteDC(hDCMem); ReleaseDC(hWnd, hDC);The DibNumColors, PaletteSize, and ColorDDBToMonoDDB functions are listed below. They are based on code found in the SHOWDIB example provided with the Windows Software Development Kit (SDK).
#define WIDTHBYTES(bits) (((bits) + 31) / 32 * 4)WORD DibNumColors (pv) VOID FAR * pv; { int bits; LPBITMAPINFOHEADER lpbi; LPBITMAPCOREHEADER lpbc; lpbi = ((LPBITMAPINFOHEADER)pv); lpbc = ((LPBITMAPCOREHEADER)pv); // With the BITMAPINFO format headers, the size of the palette is // in biClrUsed. In the BITMAPCORE-style headers, it depends on // the bits per pixel (2 raised to the power of bits/pixel). if (lpbi->biSize != sizeof(BITMAPCOREHEADER)) { if (lpbi->biClrUsed != 0) return (WORD)lpbi->biClrUsed; bits = lpbi->biBitCount; } else bits = lpbc->bcBitCount; switch (bits) { case 1: return 2; case 4: return 16; case 8: return 256; default: // A 24 bit DIB has no color table return 0; } }WORD PaletteSize(pv) VOID FAR * pv; { LPBITMAPINFOHEADER lpbi; WORD NumColors; lpbi = (LPBITMAPINFOHEADER)pv; NumColors = DibNumColors(lpbi); if (lpbi->biSize == sizeof(BITMAPCOREHEADER)) return NumColors * sizeof(RGBTRIPLE); else return NumColors * sizeof(RGBQUAD); }HBITMAP ColorDDBToMonoDDB(hbm, biStyle, biBits, hpal)
HBITMAP hbm; DWORD biStyle; WORD biBits; HPALETTE hpal; { BITMAP bm; BITMAPINFOHEADER bi; BITMAPINFOHEADER FAR *lpbi; DWORD dwLen; HANDLE hdib; HANDLE h; HDC hdc; HBITMAP hbmMono; if (!hbm) return NULL; if (hpal == NULL) hpal = GetStockObject(DEFAULT_PALETTE); GetObject(hbm, sizeof(bm), (LPSTR)&bm); if (biBits == 0) biBits = bm.bmPlanes * bm.bmBitsPixel; bi.biSize = sizeof(BITMAPINFOHEADER); bi.biWidth = bm.bmWidth; bi.biHeight = bm.bmHeight; bi.biPlanes = 1; bi.biBitCount = biBits; bi.biCompression = biStyle; bi.biSizeImage = 0; bi.biXPelsPerMeter = 0; bi.biYPelsPerMeter = 0; bi.biClrUsed = 0; bi.biClrImportant = 0; dwLen = bi.biSize + PaletteSize(&bi); hdc = GetDC(NULL); hpal = SelectPalette(hdc, hpal, FALSE); RealizePalette(hdc); hdib = GlobalAlloc(GHND, dwLen); if (!hdib) { SelectPalette(hdc, hpal, FALSE); ReleaseDC(NULL, hdc); return NULL; } lpbi = (VOID FAR *)GlobalLock(hdib); *lpbi = bi; // Call GetDIBits with a NULL lpBits parameter; it will calculate // the biSizeImage field. GetDIBits(hdc, hbm, 0, (WORD)bi.biHeight, NULL, (LPBITMAPINFO)lpbi, DIB_RGB_COLORS); bi = *lpbi; GlobalUnlock(hdib); // If the driver did not fill in the biSizeImage field, // calculate it. if (bi.biSizeImage == 0) { bi.biSizeImage = WIDTHBYTES((DWORD)bm.bmWidth * biBits) * bm.bmHeight; if (biStyle != BI_RGB) bi.biSizeImage = (bi.biSizeImage * 3) / 2; } // Reallocate the buffer big enough to hold all the bits. dwLen = bi.biSize + PaletteSize(&bi) + bi.biSizeImage; if ((h = GlobalReAlloc(hdib, dwLen, 0))) hdib = h; else { GlobalFree(hdib); hdib = NULL; SelectPalette(hdc, hpal, FALSE); ReleaseDC(NULL, hdc); return hdib; } // Call GetDIBits with a NON-NULL lpBits parameter, to actually // get the bits this time. lpbi = (VOID FAR *)GlobalLock(hdib); if (GetDIBits(hdc, hbm, 0, (WORD)bi.biHeight, (LPSTR)lpbi + (WORD)lpbi->biSize + PaletteSize(lpbi), (LPBITMAPINFO)lpbi, DIB_RGB_COLORS) == 0) { GlobalUnlock(hdib); hdib = NULL; SelectPalette(hdc, hpal, FALSE); ReleaseDC(NULL, hdc); return NULL; } // Finally, create a monochrome DDB, and put the DIB into it. // SetDIBits does smart color conversion. hbmMono = CreateBitmap((WORD)lpbi->biWidth, (WORD)lpbi->biHeight, 1, 1, NULL); SetDIBits(hdc, hbmMono, 0, lpbi->biHeight, (LPSTR)lpbi + lpbi->biSize + PaletteSize(lpbi), (LPBITMAPINFO)lpbi, DIB_RGB_COLORS); bi = *lpbi; GlobalUnlock(hdib); GlobalFree(hdib); SelectPalette(hdc, hpal, FALSE); ReleaseDC(NULL, hdc); return hbmMono;}
An application can create a cursor from the monochrome bitmap produced by ColorDDBToMonoDDB. The application can use the bitmap as either the ANDbitPlane or the XORbitPlane parameter to CreateCursor. The following code demonstrates this procedure:
// Get only the bitmap's bits, and load into a BYTE array of // correct size. // In this example, the bitmap created happens to have the // dimensions needed for a cursor or icon. This may not always be // the case. It may be necessary to "stretch" or "compress" the // bitmap to the correct size, using StretchDIBits or StretchBlt // (depending at what point the change in size is done). xsize = GetSystemMetrics(SM_CXCURSOR); ysize = GetSystemMetrics(SM_CYCURSOR); GetObject(hbmMono, sizeof(BITMAP), (LPSTR)&bm); GetBitmapBits(hbmMono, (bm.bmWidthBytes * bm.bmHeight), (LPSTR)XORbitPlane); // The call above uses bm.bmWidthBytes instead of planes and // bitsPixel because the former takes into account the fact that // some drivers might pad scan lines for speed reasons. hBitCursor = CreateCursor(ghInstance, 0, 0, xsize, ysize, ANDbitPlane, XORbitPlane);The above procedure also applies to the CreateIcon function. The following two notes should be considered when an application uses this procedure:
|
Additional reference words: 3.00 3.10 softlib BIT2MONO.EXE
© 1998 Microsoft Corporation. All rights reserved. Terms of Use. |