19.3.1 Creating a LOGPALETTE Structure

The LOGPALETTE structure describes the logical palette you plan to use. It contains the following information:

A Windows version number (for Windows versions 3.0 and 3.1, this value should be 0x300)

The number of entries in the palette

An array of PALETTEENTRY structures, each of which contains 1-byte values for red, green, and blue, and a flags member named peFlags. The peFlags member can be set to one of the following values:

NULL

PC_EXPLICIT

PC_NOCOLLAPSE

PC_RESERVED

Specifying NULL for the peFlags member informs Windows that the palette entry contains an RGB value and that it should be mapped normally.

Setting the PC_EXPLICIT flag indicates to Windows that the palette entry does not contain color values; instead, the low-order word of the entry specifies an index into the system palette.

Setting the PC_NOCOLLAPSE flag indicates to Windows that the color will be placed in an unused entry in the system palette instead of being matched to an existing color in the system palette. Once this color is in the system palette, colors in other logical palettes can be matched to this color. If there are no unused entries in the system palette, the color is matched normally.

An application sets PC_RESERVED in a palette entry when it is going to animate the entry (that is, change it dynamically by using the AnimatePalette function). Setting this flag prevents Windows from attempting to match colors from other logical palettes to this color while the entry is mapped to the system palette.

The ShowDIB code sample creates its LOGPALETTE structure as follows:

#define PALETTESIZE       256
        .
        .
        .

/* Make space for the logical palette. */

pLogPal = (NPLOGPALETTE) LocalAlloc(LMEM_FIXED,
    (sizeof(LOGPALETTE) + (sizeof(PALETTEENTRY) * (PALETTESIZE))));

ShowDIB initializes the palette structure with 256 entries; however, you can make a palette any size you need.

ShowDIB fills in the palette entries by opening a bitmap (.BMP) file and copying the color values in the BITMAPINFO structure's color table to the corresponding palette entries:

HPALETTE CreateBIPalette(lpbi)
LPBITMAPINFOHEADER lpbi;
{
    LOGPALETTE *pPal;
    HPALETTE   hpal = NULL;
    WORD       nNumColors;
    BYTE       red;
    BYTE       green;
    BYTE       blue;
    int        i;
    RGBQUAD    FAR *pRgb;

    if (!lpbi)
        return NULL;

    if (lpbi->biSize != sizeof(BITMAPINFOHEADER))
        return NULL;

    /*
     * Retrieve a pointer to the color table, and retrieve the
     * number of colors in the table.
     */

    pRgb = (RGBQUAD FAR *) ((LPSTR) lpbi + (WORD) lpbi->biSize);
    nNumColors = DibNumColors(lpbi);

    if (nNumColors) {

        /* Allocate memory for the logical-palette structure. */

        pPal = (LOGPALETTE*) LocalAlloc(LPTR, sizeof(LOGPALETTE) +
            nNumColors * sizeof(PALETTEENTRY));

        if (!pPal)
            return NULL;

        pPal->palNumEntries = nNumColors;
        pPal->palVersion = 0x300;

/*
 * Fill in the palette entries from the DIB color table and
 * create a logical color palette.
 */

        for (i = 0; i < nNumColors; i++) {
            pPal->palPalEntry[i].peRed   = pRgb[i].rgbRed;
            pPal->palPalEntry[i].peGreen = pRgb[i].rgbGreen;
            pPal->palPalEntry[i].peBlue  = pRgb[i].rgbBlue;
            pPal->palPalEntry[i].peFlags = (BYTE) 0;
        }
        hpal = CreatePalette(pPal);
        LocalFree((HANDLE) pPal);
    }
    else if (lpbi->biBitCount == 24) {

        /*
         * A 24-bitcount DIB has no color-table entries, so set
         * the number of entries to the maximum value (256).
         */

        nNumColors = MAXPALETTE;
        pPal = (LOGPALETTE*) LocalAlloc(LPTR, sizeof(LOGPALETTE) +
            nNumColors * sizeof(PALETTEENTRY));
        if (!pPal)
            return NULL;

        pPal->palNumEntries = nNumColors;
        pPal->palVersion = 0x300;

        red = green = blue = 0;

        /*
         * Generate 256 (= 8*8*4) RGB combinations to fill the
         * palette entries.
         */

        for (i = 0; i < pPal->palNumEntries; i++) {
            pPal->palPalEntry[i].peRed   = red;
            pPal->palPalEntry[i].peGreen = green;
            pPal->palPalEntry[i].peBlue  = blue;
            pPal->palPalEntry[i].peFlags = (BYTE) 0;





            if (!(red += 32))
                if (!(green += 32))
                    blue += 64;
        }
        hpal = CreatePalette(pPal);
        LocalFree((HANDLE) pPal);
    }
    return hpal;
}

ShowDIB first calls the DibNumColors function to determine the number of colors in the color table. If there is a color table (that is, the biBitCount member is not 24), it copies the RGBQUAD values in each bmiColors member in the BITMAPINFO structure to the corresponding palette entry. If there is no color table, ShowDIB creates a palette of 256 entries containing a spread of colors. When ShowDIB displays the bitmap, Windows matches the colors in the bitmap to the colors in this spread.