Figure 3 Colors
Colors.h
//***************************************************************************
//
// Colors.h
//
//***************************************************************************
#define IDR_MENU 100
#define IDD_COLORBITSDLG 101
#define IDC_COLORBITS 102
#define IDC_SPINBUTTON 103
#define IDM_OPEN 200
#define IDM_NO_PALETTE 201
#define IDM_HALFTONE_PALETTE 202
#define IDM_OPTIMIZED_PALETTE 203
#define IDM_COLOR_BITS 204
#define IDM_EXIT 205
typedef struct _NODE {
BOOL bIsLeaf; // TRUE if node has no children
UINT nPixelCount; // Number of pixels represented by this leaf
UINT nRedSum; // Sum of red components
UINT nGreenSum; // Sum of green components
UINT nBlueSum; // Sum of blue components
struct _NODE* pChild[8]; // Pointers to child nodes
struct _NODE* pNext; // Pointer to next reducible node
} NODE;
Colors.rc
//***********************************************************************
//
// Colors.rc
//
//***********************************************************************
#include <windows.h>
#include <commctrl.h>
#include "Colors.h"
IDR_MENU MENU
BEGIN
POPUP "&Options" {
MENUITEM "&Open...", IDM_OPEN
MENUITEM SEPARATOR
MENUITEM "&No Palette", IDM_NO_PALETTE
MENUITEM "&Halftone Palette", IDM_HALFTONE_PALETTE, CHECKED
MENUITEM "Optimi&zed Palette", IDM_OPTIMIZED_PALETTE
MENUITEM SEPARATOR
MENUITEM "&Color Bits...", IDM_COLOR_BITS
MENUITEM SEPARATOR
MENUITEM "E&xit", IDM_EXIT
}
END
IDD_COLORBITSDLG DIALOG 0, 0, 144, 72
STYLE DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_VISIBLE |
WS_SYSMENU
CAPTION "Set Color Bits"
FONT 8, "MS Sans Serif"
BEGIN
LTEXT "Significant Color Bits", -1, 16, 24, 68, 8
EDITTEXT IDC_COLORBITS, 88, 20, 40, 14, ES_AUTOHSCROLL
CONTROL "", IDC_SPINBUTTON, "MSCTLS_UPDOWN32", UDS_SETBUDDYINT |
UDS_AUTOBUDDY | UDS_ARROWKEYS | UDS_ALIGNRIGHT, 0, 0, 0, 0
DEFPUSHBUTTON "OK", IDOK, 16, 48, 50, 14, WS_GROUP
PUSHBUTTON "Cancel", IDCANCEL, 80, 48, 50, 14, WS_GROUP
END
Colors.c
//***************************************************************************
//
// Colors presents an implementation of the Gervautz-Purgathofer octree
// color quanitization algorithm that creates optimized color palettes for
// for 16, 24, and 32-bit DIB sections
//
//***************************************************************************
#include <windows.h>
#include <commctrl.h>
#include "Colors.h"
LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM);
BOOL CALLBACK DlgProc (HWND, UINT, WPARAM, LPARAM);
HPALETTE CreateExactPalette (HANDLE);
HPALETTE CreateOctreePalette (HANDLE, UINT, UINT);
void AddColor (NODE**, BYTE, BYTE, BYTE, UINT, UINT, UINT*, NODE**);
NODE* CreateNode (UINT, UINT, UINT*, NODE**);
void ReduceTree (UINT, UINT*, NODE**);
void DeleteTree (NODE**);
void GetPaletteColors (NODE*, PALETTEENTRY*, UINT*);
int GetRightShiftCount (DWORD);
int GetLeftShiftCount (DWORD);
void UpdatePaletteType (HWND, UINT);
BOOL DoFileOpen (HWND);
void UpdateWindowTitle (HWND, LPSTR);
void DisplayDIBSection (HDC, HANDLE, HPALETTE);
HPALETTE GetPaletteHandle (HWND, HANDLE);
UINT BitsPerPixel (HANDLE);
/////////////////////////////////////////////////////////////////////////////
// Global variables
UINT g_nPaletteType = IDM_HALFTONE_PALETTE;
HANDLE g_hImage = NULL;
HPALETTE g_hPalette = NULL;
UINT g_nColorBits = 6;
/////////////////////////////////////////////////////////////////////////////
// WinMain
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpszCmdLine, int nCmdShow)
{
static char szAppName[] = "Colors";
WNDCLASS wc;
HWND hwnd;
MSG msg;
wc.style = 0;
wc.lpfnWndProc = (WNDPROC) WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon (NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor (NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1);
wc.lpszMenuName = MAKEINTRESOURCE (IDR_MENU);
wc.lpszClassName = szAppName;
RegisterClass (&wc);
hwnd = CreateWindow (szAppName, szAppName,
WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, HWND_DESKTOP, NULL, hInstance, NULL);
ShowWindow (hwnd, nCmdShow);
UpdateWindow (hwnd);
while (GetMessage (&msg, NULL, 0, 0)) {
TranslateMessage (&msg);
DispatchMessage (&msg);
}
return msg.wParam;
}
/////////////////////////////////////////////////////////////////////////////
// Window procedure
LRESULT CALLBACK WndProc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
HDC hdc;
PAINTSTRUCT ps;
UINT nColors;
switch (msg) {
case WM_CREATE:
InitCommonControls ();
return 0;
case WM_PAINT:
hdc = BeginPaint (hwnd, &ps);
if (g_hImage != NULL)
DisplayDIBSection (hdc, g_hImage, g_hPalette);
EndPaint (hwnd, &ps);
return 0;
case WM_QUERYNEWPALETTE:
if (g_hPalette != NULL) {
hdc = GetDC (hwnd);
SelectPalette (hdc, g_hPalette, FALSE);
if (nColors = RealizePalette (hdc))
InvalidateRect (hwnd, NULL, FALSE);
ReleaseDC (hwnd, hdc);
return nColors;
}
break;
case WM_PALETTECHANGED:
if ((g_hPalette != NULL) && ((HWND) wParam != hwnd)) {
hdc = GetDC (hwnd);
SelectPalette (hdc, g_hPalette, FALSE);
if (RealizePalette (hdc))
InvalidateRect (hwnd, NULL, FALSE);
ReleaseDC (hwnd, hdc);
return 0;
}
break;
case WM_COMMAND:
switch (LOWORD (wParam)) {
case IDM_OPEN:
if (DoFileOpen (hwnd)) {
if (g_hPalette != NULL)
DeleteObject (g_hPalette);
g_hPalette = GetPaletteHandle (hwnd, g_hImage);
InvalidateRect (hwnd, NULL, TRUE);
}
return 0;
case IDM_NO_PALETTE:
UpdatePaletteType (hwnd, IDM_NO_PALETTE);
return 0;
case IDM_HALFTONE_PALETTE:
UpdatePaletteType (hwnd, IDM_HALFTONE_PALETTE);
return 0;
case IDM_OPTIMIZED_PALETTE:
UpdatePaletteType (hwnd, IDM_OPTIMIZED_PALETTE);
return 0;
case IDM_COLOR_BITS:
if (DialogBox ((HINSTANCE) GetWindowLong (hwnd, GWL_HINSTANCE),
MAKEINTRESOURCE (IDD_COLORBITSDLG), hwnd, DlgProc)) {
if (g_hPalette != NULL)
DeleteObject (g_hPalette);
if (g_hImage != NULL) {
g_hPalette = GetPaletteHandle (hwnd, g_hImage);
InvalidateRect (hwnd, NULL, FALSE);
}
}
return 0;
case IDM_EXIT:
PostMessage (hwnd, WM_CLOSE, 0, 0);
return 0;
}
break;
case WM_DESTROY:
PostQuitMessage (0);
return 0;
}
return DefWindowProc (hwnd, msg, wParam, lParam);
}
/////////////////////////////////////////////////////////////////////////////
// Palette generation routines and helpers
HPALETTE CreateExactPalette (HANDLE hImage)
{
DIBSECTION ds;
UINT nColors, i;
RGBQUAD* prgb;
LOGPALETTE* plp;
HDC hdc, hdcMem;
HBITMAP hOldBitmap;
HPALETTE hPalette;
DWORD dwSize;
// Get the number of colors in the image
GetObject (hImage, sizeof (ds), &ds);
if (ds.dsBmih.biClrUsed != 0)
nColors = ds.dsBmih.biClrUsed;
else
nColors = 1 << ds.dsBmih.biBitCount;
if (nColors > 256) // Sanity check
return NULL;
// Retrieve the image's color table
if ((prgb = (RGBQUAD*) HeapAlloc (GetProcessHeap (), 0,
nColors * sizeof (RGBQUAD))) == NULL)
return NULL;
hdc = GetDC (NULL);
hdcMem = CreateCompatibleDC (hdc);
hOldBitmap = SelectObject (hdcMem, hImage);
nColors = min (nColors, GetDIBColorTable (hdcMem, 0, nColors, prgb));
SelectObject (hdcMem, hOldBitmap);
DeleteDC (hdcMem);
ReleaseDC (NULL, hdc);
if (nColors == 0) { // Another sanity check
HeapFree (GetProcessHeap (), 0, prgb);
return NULL;
}
// Create a logical palette from the colors in the color table
dwSize = sizeof (LOGPALETTE) + ((nColors - 1) * sizeof (PALETTEENTRY));
if ((plp = (LOGPALETTE*) HeapAlloc (GetProcessHeap (), 0,
dwSize)) == NULL) {
HeapFree (GetProcessHeap (), 0, prgb);
return NULL;
}
plp->palVersion = 0x300;
plp->palNumEntries = (WORD) nColors;
for (i=0; i<nColors; i++) {
plp->palPalEntry[i].peRed = prgb[i].rgbRed;
plp->palPalEntry[i].peGreen = prgb[i].rgbGreen;
plp->palPalEntry[i].peBlue = prgb[i].rgbBlue;
plp->palPalEntry[i].peFlags = 0;
}
hPalette = CreatePalette (plp);
HeapFree (GetProcessHeap (), 0, plp);
HeapFree (GetProcessHeap (), 0, prgb);
return hPalette;
}
HPALETTE CreateOctreePalette (HANDLE hImage, UINT nMaxColors, UINT nColorBits)
{
DIBSECTION ds;
int i, j, nPad;
BYTE* pbBits;
WORD* pwBits;
DWORD* pdwBits;
DWORD rmask, gmask, bmask;
int rright, gright, bright;
int rleft, gleft, bleft;
BYTE r, g, b;
WORD wColor;
DWORD dwColor, dwSize;
LOGPALETTE* plp;
HPALETTE hPalette;
NODE* pTree;
UINT nLeafCount, nIndex;
NODE* pReducibleNodes[9];
// Initialize octree variables
pTree = NULL;
nLeafCount = 0;
if (nColorBits > 8) // Just in case
return NULL;
for (i=0; i<=(int) nColorBits; i++)
pReducibleNodes[i] = NULL;
// Scan the DIB and build the octree
GetObject (hImage, sizeof (ds), &ds);
nPad = ds.dsBm.bmWidthBytes - (((ds.dsBmih.biWidth *
ds.dsBmih.biBitCount) + 7) / 8);
switch (ds.dsBmih.biBitCount) {
case 16: // One case for 16-bit DIBs
if (ds.dsBmih.biCompression == BI_BITFIELDS) {
rmask = ds.dsBitfields[0];
gmask = ds.dsBitfields[1];
bmask = ds.dsBitfields[2];
}
else {
rmask = 0x7C00;
gmask = 0x03E0;
bmask = 0x001F;
}
rright = GetRightShiftCount (rmask);
gright = GetRightShiftCount (gmask);
bright = GetRightShiftCount (bmask);
rleft = GetLeftShiftCount (rmask);
gleft = GetLeftShiftCount (gmask);
bleft = GetLeftShiftCount (bmask);
pwBits = (WORD*) ds.dsBm.bmBits;
for (i=0; i<ds.dsBmih.biHeight; i++) {
for (j=0; j<ds.dsBmih.biWidth; j++) {
wColor = *pwBits++;
b = (BYTE) (((wColor & (WORD) bmask) >> bright) << bleft);
g = (BYTE) (((wColor & (WORD) gmask) >> gright) << gleft);
r = (BYTE) (((wColor & (WORD) rmask) >> rright) << rleft);
AddColor (&pTree, r, g, b, nColorBits, 0, &nLeafCount,
pReducibleNodes);
while (nLeafCount > nMaxColors)
ReduceTree (nColorBits, &nLeafCount, pReducibleNodes);
}
pwBits = (WORD*) (((BYTE*) pwBits) + nPad);
}
break;
case 24: // Another for 24-bit DIBs
pbBits = (BYTE*) ds.dsBm.bmBits;
for (i=0; i<ds.dsBmih.biHeight; i++) {
for (j=0; j<ds.dsBmih.biWidth; j++) {
b = *pbBits++;
g = *pbBits++;
r = *pbBits++;
AddColor (&pTree, r, g, b, nColorBits, 0, &nLeafCount,
pReducibleNodes);
while (nLeafCount > nMaxColors)
ReduceTree (nColorBits, &nLeafCount, pReducibleNodes);
}
pbBits += nPad;
}
break;
case 32: // And another for 32-bit DIBs
if (ds.dsBmih.biCompression == BI_BITFIELDS) {
rmask = ds.dsBitfields[0];
gmask = ds.dsBitfields[1];
bmask = ds.dsBitfields[2];
}
else {
rmask = 0x00FF0000;
gmask = 0x0000FF00;
bmask = 0x000000FF;
}
rright = GetRightShiftCount (rmask);
gright = GetRightShiftCount (gmask);
bright = GetRightShiftCount (bmask);
pdwBits = (DWORD*) ds.dsBm.bmBits;
for (i=0; i<ds.dsBmih.biHeight; i++) {
for (j=0; j<ds.dsBmih.biWidth; j++) {
dwColor = *pdwBits++;
b = (BYTE) ((dwColor & bmask) >> bright);
g = (BYTE) ((dwColor & gmask) >> gright);
r = (BYTE) ((dwColor & rmask) >> rright);
AddColor (&pTree, r, g, b, nColorBits, 0, &nLeafCount,
pReducibleNodes);
while (nLeafCount > nMaxColors)
ReduceTree (nColorBits, &nLeafCount, pReducibleNodes);
}
pdwBits = (DWORD*) (((BYTE*) pdwBits) + nPad);
}
break;
default: // DIB must be 16, 24, or 32-bit!
return NULL;
}
if (nLeafCount > nMaxColors) { // Sanity check
DeleteTree (&pTree);
return NULL;
}
// Create a logical palette from the colors in the octree
dwSize = sizeof (LOGPALETTE) + ((nLeafCount - 1) * sizeof (PALETTEENTRY));
if ((plp = (LOGPALETTE*) HeapAlloc (GetProcessHeap (), 0,
dwSize)) == NULL) {
DeleteTree (&pTree);
return NULL;
}
plp->palVersion = 0x300;
plp->palNumEntries = (WORD) nLeafCount;
nIndex = 0;
GetPaletteColors (pTree, plp->palPalEntry, &nIndex);
hPalette = CreatePalette (plp);
HeapFree (GetProcessHeap (), 0, plp);
DeleteTree (&pTree);
return hPalette;
}
void AddColor (NODE** ppNode, BYTE r, BYTE g, BYTE b, UINT nColorBits,
UINT nLevel, UINT* pLeafCount, NODE** pReducibleNodes)
{
int nIndex, shift;
static BYTE mask[8] = { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 };
// If the node doesn't exist, create it
if (*ppNode == NULL)
*ppNode = CreateNode (nLevel, nColorBits, pLeafCount,
pReducibleNodes);
// Update color information if it's a leaf node
if ((*ppNode)->bIsLeaf) {
(*ppNode)->nPixelCount++;
(*ppNode)->nRedSum += r;
(*ppNode)->nGreenSum += g;
(*ppNode)->nBlueSum += b;
}
// Recurse a level deeper if the node is not a leaf
else {
shift = 7 - nLevel;
nIndex = (((r & mask[nLevel]) >> shift) << 2) |
(((g & mask[nLevel]) >> shift) << 1) |
((b & mask[nLevel]) >> shift);
AddColor (&((*ppNode)->pChild[nIndex]), r, g, b, nColorBits,
nLevel + 1, pLeafCount, pReducibleNodes);
}
}
NODE* CreateNode (UINT nLevel, UINT nColorBits, UINT* pLeafCount,
NODE** pReducibleNodes)
{
NODE* pNode;
if ((pNode = (NODE*) HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY,
sizeof (NODE))) == NULL)
return NULL;
pNode->bIsLeaf = (nLevel == nColorBits) ? TRUE : FALSE;
if (pNode->bIsLeaf)
(*pLeafCount)++;
else { // Add the node to the reducible list for this level
pNode->pNext = pReducibleNodes[nLevel];
pReducibleNodes[nLevel] = pNode;
}
return pNode;
}
void ReduceTree (UINT nColorBits, UINT* pLeafCount, NODE** pReducibleNodes)
{
int i;
NODE* pNode;
UINT nRedSum, nGreenSum, nBlueSum, nChildren;
// Find the deepest level containing at least one reducible node
for (i=nColorBits - 1; (i>0) && (pReducibleNodes[i] == NULL); i--);
// Reduce the node most recently added to the list at level i
pNode = pReducibleNodes[i];
pReducibleNodes[i] = pNode->pNext;
nRedSum = nGreenSum = nBlueSum = nChildren = 0;
for (i=0; i<8; i++) {
if (pNode->pChild[i] != NULL) {
nRedSum += pNode->pChild[i]->nRedSum;
nGreenSum += pNode->pChild[i]->nGreenSum;
nBlueSum += pNode->pChild[i]->nBlueSum;
pNode->nPixelCount += pNode->pChild[i]->nPixelCount;
HeapFree (GetProcessHeap (), 0, pNode->pChild[i]);
pNode->pChild[i] = NULL;
nChildren++;
}
}
pNode->bIsLeaf = TRUE;
pNode->nRedSum = nRedSum;
pNode->nGreenSum = nGreenSum;
pNode->nBlueSum = nBlueSum;
*pLeafCount -= (nChildren - 1);
}
void DeleteTree (NODE** ppNode)
{
int i;
for (i=0; i<8; i++) {
if ((*ppNode)->pChild[i] != NULL)
DeleteTree (&((*ppNode)->pChild[i]));
}
HeapFree (GetProcessHeap (), 0, *ppNode);
*ppNode = NULL;
}
void GetPaletteColors (NODE* pTree, PALETTEENTRY* pPalEntries, UINT* pIndex)
{
int i;
if (pTree->bIsLeaf) {
pPalEntries[*pIndex].peRed =
(BYTE) ((pTree->nRedSum) / (pTree->nPixelCount));
pPalEntries[*pIndex].peGreen =
(BYTE) ((pTree->nGreenSum) / (pTree->nPixelCount));
pPalEntries[*pIndex].peBlue =
(BYTE) ((pTree->nBlueSum) / (pTree->nPixelCount));
(*pIndex)++;
}
else {
for (i=0; i<8; i++) {
if (pTree->pChild[i] != NULL)
GetPaletteColors (pTree->pChild[i], pPalEntries, pIndex);
}
}
}
int GetRightShiftCount (DWORD dwVal)
{
int i;
for (i=0; i<sizeof (DWORD) * 8; i++) {
if (dwVal & 1)
return i;
dwVal >>= 1;
}
return -1;
}
int GetLeftShiftCount (DWORD dwVal)
{
int nCount, i;
nCount = 0;
for (i=0; i<sizeof (DWORD) * 8; i++) {
if (dwVal & 1)
nCount++;
dwVal >>= 1;
}
return (8 - nCount);
}
/////////////////////////////////////////////////////////////////////////////
// Other helper routines
void UpdatePaletteType (HWND hwnd, UINT nNewPaletteType)
{
HMENU hMenu;
hMenu = GetMenu (hwnd);
CheckMenuItem (hMenu, g_nPaletteType, MF_UNCHECKED);
CheckMenuItem (hMenu, nNewPaletteType, MF_CHECKED);
g_nPaletteType = nNewPaletteType;
if (g_hPalette != NULL)
DeleteObject (g_hPalette);
if (g_hImage != NULL) {
g_hPalette = GetPaletteHandle (hwnd, g_hImage);
InvalidateRect (hwnd, NULL, FALSE);
}
}
BOOL DoFileOpen (HWND hwnd)
{
OPENFILENAME ofn;
char szFileName[MAX_PATH];
char szFileTitle[MAX_PATH];
char szErrMsg[MAX_PATH + 32];
HANDLE hImage;
szFileName[0] = 0;
szFileTitle[0] = 0;
ZeroMemory (&ofn, sizeof (ofn));
ofn.lStructSize = sizeof (ofn);
ofn.hwndOwner = hwnd;
ofn.lpstrFilter = "BMP Files\0*.bmp\0All Files\0*.*\0";
ofn.lpstrFile = szFileName;
ofn.nMaxFile = sizeof (szFileName);
ofn.lpstrFileTitle = szFileTitle;
ofn.nMaxFileTitle = sizeof (szFileTitle);
ofn.Flags = OFN_FILEMUSTEXIST | OFN_HIDEREADONLY |
OFN_EXPLORER | OFN_SHOWHELP;
ofn.lpstrDefExt = "bmp";
if (GetOpenFileName (&ofn)) {
UpdateWindowTitle (hwnd, ofn.lpstrFileTitle);
hImage = LoadImage (NULL, ofn.lpstrFile, IMAGE_BITMAP, 0, 0,
LR_LOADFROMFILE | LR_CREATEDIBSECTION);
if (hImage != NULL) {
if (g_hImage != NULL)
DeleteObject (g_hImage);
g_hImage = hImage;
return TRUE;
}
else { // LoadImage failed
lstrcpy (szErrMsg, szFileTitle);
lstrcat (szErrMsg, " does not contain a valid DIB");
MessageBox (hwnd, szErrMsg, "Error", MB_ICONEXCLAMATION | MB_OK);
}
}
return FALSE;
}
void UpdateWindowTitle (HWND hwnd, LPSTR pszDocName)
{
char szTitle[MAX_PATH + 16];
lstrcpy (szTitle, pszDocName);
lstrcat (szTitle, " - Colors");
SetWindowText (hwnd, szTitle);
}
void DisplayDIBSection (HDC hdc, HANDLE hImage, HPALETTE hPalette)
{
HDC hdcMem;
HBITMAP hOldBitmap;
DIBSECTION ds;
int cx, cy;
hdcMem = CreateCompatibleDC (hdc);
if (hPalette != NULL) {
SelectPalette (hdcMem, hPalette, FALSE);
RealizePalette (hdcMem);
SelectPalette (hdc, hPalette, FALSE);
RealizePalette (hdc);
}
GetObject (g_hImage, sizeof (ds), &ds);
cx = ds.dsBmih.biWidth;
cy = ds.dsBmih.biHeight;
hOldBitmap = SelectObject (hdcMem, hImage);
BitBlt (hdc, 0, 0, cx, cy, hdcMem, 0, 0, SRCCOPY);
SelectObject (hdcMem, hOldBitmap);
DeleteDC (hdcMem);
}
HPALETTE GetPaletteHandle (HWND hwnd, HANDLE hImage)
{
HDC hdc;
HPALETTE hPalette;
HCURSOR hCursor;
int bpp;
// Return NULL if this isn't a palette-based device
hdc = GetDC (hwnd);
if (!(GetDeviceCaps (hdc, RASTERCAPS) & RC_PALETTE)) {
ReleaseDC (hwnd, hdc);
return NULL;
}
// Otherwise create a palette and return the palette handle
switch (g_nPaletteType) {
case IDM_NO_PALETTE:
hPalette = NULL;
break;
case IDM_HALFTONE_PALETTE:
hPalette = CreateHalftonePalette (hdc);
break;
case IDM_OPTIMIZED_PALETTE:
bpp = BitsPerPixel (hImage);
if (bpp <= 8)
hPalette = CreateExactPalette (hImage);
else if ((bpp == 16) || (bpp == 24) || (bpp == 32)) {
hCursor = SetCursor (LoadCursor (NULL, IDC_WAIT));
hPalette = CreateOctreePalette (hImage, 236, g_nColorBits);
SetCursor (hCursor);
}
else // Default = halftone palette
hPalette = CreateHalftonePalette (hdc);
break;
}
ReleaseDC (hwnd, hdc);
return hPalette;
}
UINT BitsPerPixel (HANDLE hImage)
{
DIBSECTION ds;
GetObject (hImage, sizeof (ds), &ds);
return (UINT) ds.dsBmih.biBitCount;
}
/////////////////////////////////////////////////////////////////////////////
// Dialog Procedure
BOOL CALLBACK DlgProc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
UINT nColorBits;
switch (msg) {
case WM_INITDIALOG:
SendDlgItemMessage (hwnd, IDC_SPINBUTTON, UDM_SETRANGE, 0,
(LPARAM) MAKELONG (8, 1));
SetDlgItemInt (hwnd, IDC_COLORBITS, g_nColorBits, FALSE);
return TRUE;
case WM_COMMAND:
switch (LOWORD (wParam)) {
case IDOK:
nColorBits = GetDlgItemInt (hwnd, IDC_COLORBITS, NULL, FALSE);
if ((nColorBits < 1) || (nColorBits > 8)) {
MessageBox (hwnd, "Enter a value from 1 to 8", "Error",
MB_ICONEXCLAMATION | MB_OK);
SendDlgItemMessage (hwnd, IDC_COLORBITS, EM_SETSEL, 0, -1);
SetFocus (GetDlgItem (hwnd, IDC_COLORBITS));
}
else {
g_nColorBits = nColorBits;
EndDialog (hwnd, 1);
}
return TRUE;
case IDCANCEL:
EndDialog (hwnd, 0);
return TRUE;
}
break;
}
return FALSE;
}