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. |