+PPALETTE
+NTAPI
+CreateDIBPalette(
+ _In_ const BITMAPINFO *pbmi,
+ _In_ PDC pdc,
+ _In_ ULONG iUsage)
+{
+ PPALETTE ppal;
+ ULONG i, cColors;
+
+ /* Check if the colors are indexed */
+ if (pbmi->bmiHeader.biBitCount <= 8)
+ {
+ /* We create a "full" palette */
+ cColors = 1 << pbmi->bmiHeader.biBitCount;
+
+ /* Allocate the palette */
+ ppal = PALETTE_AllocPalette(PAL_INDEXED,
+ cColors,
+ NULL,
+ 0,
+ 0,
+ 0);
+
+ /* Check if the BITMAPINFO specifies how many colors to use */
+ if (pbmi->bmiHeader.biClrUsed != 0)
+ {
+ /* This is how many colors we can actually process */
+ cColors = min(cColors, pbmi->bmiHeader.biClrUsed);
+ }
+
+ /* Check how to use the colors */
+ if (iUsage == DIB_PAL_COLORS)
+ {
+ COLORREF crColor;
+
+ /* The colors are an array of WORD indices into the DC palette */
+ PWORD pwColors = (PWORD)((PCHAR)pbmi + pbmi->bmiHeader.biSize);
+
+ /* Use the DCs palette or, if no DC is given, the default one */
+ PPALETTE ppalDC = pdc ? pdc->dclevel.ppal : gppalDefault;
+
+ /* Loop all color indices in the DIB */
+ for (i = 0; i < cColors; i++)
+ {
+ /* Get the RGB value from the DC palette, indexed by the DIB
+ color table value */
+ crColor = PALETTE_ulGetRGBColorFromIndex(ppalDC, pwColors[i]);
+ PALETTE_vSetRGBColorForIndex(ppal, i, crColor);
+ }
+ }
+ else if (iUsage == DIB_PAL_BRUSHHACK)
+ {
+ /* The colors are an array of WORD indices into the DC palette */
+ PWORD pwColors = (PWORD)((PCHAR)pbmi + pbmi->bmiHeader.biSize);
+
+ /* Loop all color indices in the DIB */
+ for (i = 0; i < cColors; i++)
+ {
+ /* Set the index directly as the RGB color, the real palette
+ containing RGB values will be calculated when the brush is
+ realized */
+ PALETTE_vSetRGBColorForIndex(ppal, i, pwColors[i]);
+ }
+
+ /* Mark the palette as a brush hack palette */
+ ppal->flFlags |= PAL_BRUSHHACK;
+ }
+ else if (iUsage == 2)
+ {
+ // FIXME: this one is undocumented
+ ASSERT(FALSE);
+ }
+ else // if (iUsage == DIB_RGB_COLORS)
+ {
+ /* The colors are an array of RGBQUAD values */
+ RGBQUAD *prgb = (RGBQUAD*)((PCHAR)pbmi + pbmi->bmiHeader.biSize);
+
+ // FIXME: do we need to handle PALETTEINDEX / PALETTERGB macro?
+
+ /* Loop all color indices in the DIB */
+ for (i = 0; i < cColors; i++)
+ {
+ /* Get the color value and translate it to a COLORREF */
+ RGBQUAD rgb = prgb[i];
+ COLORREF crColor = RGB(rgb.rgbRed, rgb.rgbGreen, rgb.rgbBlue);
+
+ /* Set the RGB value in the palette */
+ PALETTE_vSetRGBColorForIndex(ppal, i, crColor);
+ }
+ }
+ }
+ else
+ {
+ /* This is a bitfield / RGB palette */
+ ULONG flRedMask, flGreenMask, flBlueMask;
+
+ /* Check if the DIB contains bitfield values */
+ if (pbmi->bmiHeader.biCompression == BI_BITFIELDS)
+ {
+ /* Check if we have a v4/v5 header */
+ if (pbmi->bmiHeader.biSize >= sizeof(BITMAPV4HEADER))
+ {
+ /* The masks are dedicated fields in the header */
+ PBITMAPV4HEADER pbmV4Header = (PBITMAPV4HEADER)&pbmi->bmiHeader;
+ flRedMask = pbmV4Header->bV4RedMask;
+ flGreenMask = pbmV4Header->bV4GreenMask;
+ flBlueMask = pbmV4Header->bV4BlueMask;
+ }
+ else
+ {
+ /* The masks are the first 3 values in the DIB color table */
+ PDWORD pdwColors = (PVOID)((PCHAR)pbmi + pbmi->bmiHeader.biSize);
+ flRedMask = pdwColors[0];
+ flGreenMask = pdwColors[1];
+ flBlueMask = pdwColors[2];
+ }
+ }
+ else
+ {
+ /* Check what bit depth we have. Note: optimization flags are
+ calculated in PALETTE_AllocPalette() */
+ if (pbmi->bmiHeader.biBitCount == 16)
+ {
+ /* This is an RGB 555 palette */
+ flRedMask = 0x7C00;
+ flGreenMask = 0x03E0;
+ flBlueMask = 0x001F;
+ }
+ else
+ {
+ /* This is an RGB 888 palette */
+ flRedMask = 0xFF0000;
+ flGreenMask = 0x00FF00;
+ flBlueMask = 0x0000FF;
+ }
+ }
+
+ /* Allocate the bitfield palette */
+ ppal = PALETTE_AllocPalette(PAL_BITFIELDS,
+ 0,
+ NULL,
+ flRedMask,
+ flGreenMask,
+ flBlueMask);
+ }
+
+ /* We're done, return the palette */
+ return ppal;
+}
+