Palette

Palette is a collection of colors in a plate which painter uses to draw a picture. Painter takes differrent colors from each palette entries and draw the picture. Palette is like like a look up table.

Palette in VGA graphics

Graphics card in VGA 2,8,16, 256 color mode works in the same way. It contains a harware palette and stores all possible colors in true color. Hareware uses this look up table to map the true color in the output monitor.

Palette in Bitmaps and GIFs

GIF and bitmaps images still uses these palette mathod. Palette entry colors are stored in the header section and body part is the array of index pixels. 16 color bitmap can hold two pixel information in one byte. 256 color bitmap can store one pixel information in one byte. 16 color bitmap can reduce the size of the image by 1:6 and 256 color bitmap can reduce by 1:3. These GIF and bitmaps does not require any encoder or decoder like JPEG format and still can achieve less size.

PALETTEENTRY

Palette will have an array of color entries. Each palette entry is a color and represented by PALETTEENTRY structure. and it is represented by RGB member.

typedef struct tagPALETTEENTRY {
    BYTE        peRed;
    BYTE        peGreen;
    BYTE        peBlue;
    BYTE        peFlags;
} PALETTEENTRY, *PPALETTEENTRY, FAR *LPPALETTEENTRY;

LOGPALETTE

Logical palette is an array of PALETTEENTRY colors and an member variable to hold the number of entries and version information. This datastructure is used in CreatePalette() function to create a handle to palette.

typedef struct tagLOGPALETTE {
  WORD         palVersion;
  WORD         palNumEntries;
  PALETTEENTRY palPalEntry[1];
} LOGPALETTE;

CreatePalette

CreatePalette API is used to create a palette handle from a logical palette entry. The returned palette handle can be used to SelectPalette() call for selecting new palette to a device context.

HPALETTE CreatePalette(
  _In_ const LOGPALETTE *lplgpl
);

SelectPalette

SelectPalette associates a logical palette handle to a device context.

HPALETTE SelectPalette(
  _In_ HDC      hdc,
  _In_ HPALETTE hpal,
  _In_ BOOL     bForceBackground
);

RealizePalette

The RealizePalette function maps palette entries from the current logical palette to the system palette.

UINT RealizePalette(
  _In_ HDC hdc
);

GetDeviceCaps

GetDeviceCaps() returns one of the associated capabilities of device cotext given by input index. To know if the device context supports palette based color, RASTERCAPS index can be passed and RC_PALETTE bit can checked.

int GetDeviceCaps(
  _In_ HDC hdc,
  _In_ int nIndex
);

Palette Demo

We have a bitmap saved as 16 color format in paint brush

We are using CreatePalette, SelectPalette and RealizePalette in this demo.

/* Button event for drawing a 16/256 color bitmap*/
void CPaletteBmpDlg::OnPaintImageClick() 
{
	CPalette pal;
	HANDLE hBitmap = LoadImage(NULL,
								"C:\\logo.bmp",
								IMAGE_BITMAP,
								0,
								0,
								LR_LOADFROMFILE|LR_DEFAULTSIZE);
	CBitmap bmp;
	bmp.m_hObject = hBitmap;
	LoadBMPPalette("C:\\logo.bmp", &pal);
	DrawBitmap(GetDC(), bmp, &pal);

}

/* Load and Create palette from a 2/4/8/16/256 color bitmap*/
BOOL LoadBMPPalette( LPCTSTR sBMPFile, CPalette *pPal )
{
	CFile file;
	if( !file.Open( sBMPFile, CFile::modeRead) )
		return FALSE;
 
	BITMAPFILEHEADER bmfHeader;
 
	// Read file header
	if (file.Read((LPSTR)&bmfHeader, sizeof(bmfHeader)) != sizeof(bmfHeader))
		return FALSE;
 
	// File type should be 'BM'
	if (bmfHeader.bfType != ((WORD) ('M' << 8) | 'B'))
		return FALSE;
 
	// Get length of the remainder of the file and allocate memory
	DWORD nPackedDIBLen = file.GetLength() - sizeof(BITMAPFILEHEADER);
	HGLOBAL hDIB = ::GlobalAlloc(GMEM_FIXED, nPackedDIBLen);
	if (hDIB == 0)
		return FALSE;
 
	// Read the remainder of the bitmap file.
	if (file.ReadHuge((LPSTR)hDIB, nPackedDIBLen) != nPackedDIBLen )
	{
		::GlobalFree(hDIB);
		return FALSE;
	}
 
 
	BITMAPINFOHEADER &bmiHeader = *(LPBITMAPINFOHEADER)hDIB ;
	BITMAPINFO &bmInfo = *(LPBITMAPINFO)hDIB ;
 
	// If bmiHeader.biClrUsed is zero we have to infer the number
	// of colors from the number of bits used to specify it.
	int nColors = bmiHeader.biClrUsed ? bmiHeader.biClrUsed : 
						1 << bmiHeader.biBitCount;
 
	LPVOID lpDIBBits;
	if( bmInfo.bmiHeader.biBitCount > 8 )
		lpDIBBits = (LPVOID)((LPDWORD)(bmInfo.bmiColors + bmInfo.bmiHeader.biClrUsed) + 
			((bmInfo.bmiHeader.biCompression == BI_BITFIELDS) ? 3 : 0));
	else
		lpDIBBits = (LPVOID)(bmInfo.bmiColors + nColors);
 
	// Create the logical palette
	if( pPal != NULL )
	{
		// Create the palette
		if( nColors <= 256 )
		{
			UINT nSize = sizeof(LOGPALETTE) + (sizeof(PALETTEENTRY) * nColors);
			LOGPALETTE *pLP = (LOGPALETTE *) new BYTE[nSize];
 
			pLP->palVersion = 0x300;
			pLP->palNumEntries = nColors;
 
			for( int i=0; i < nColors; i++)
			{
				pLP->palPalEntry[i].peRed = bmInfo.bmiColors[i].rgbRed;
				pLP->palPalEntry[i].peGreen = bmInfo.bmiColors[i].rgbGreen;
				pLP->palPalEntry[i].peBlue = bmInfo.bmiColors[i].rgbBlue;
				pLP->palPalEntry[i].peFlags = 0;
			}
 
			pPal->CreatePalette( pLP );
 
			delete[] pLP;
		}
	}

	::GlobalFree(hDIB);
	return TRUE;
}
/* Draw bitmap using BitBlt */
void DrawBitmap(CDC* pDC, CBitmap& bitmap, CPalette *pPal )
{
	// Create a compatible memory DC
	CDC memDC;
	memDC.CreateCompatibleDC( pDC );
	memDC.SelectObject( &bitmap );
 
	// Select and realize the palette if DC supports Palette
	if( pPal != NULL && pDC->GetDeviceCaps(RASTERCAPS) & RC_PALETTE )
	{
		pDC->SelectPalette( pPal, FALSE );
		pDC->RealizePalette();
	}
 
	BITMAP bm;
	bitmap.GetBitmap( &bm );
 
	pDC->BitBlt(0, 0, bm.bmWidth, bm.bmHeight, &memDC, 0, 0,SRCCOPY);
}

About our authors: Team EQA

Further readings

Where is WinMain() function in MFC application ?

MFC hides WinMain in its framework and includes source file on WinMain(). This explains how framework calls global CWinApp::Initinstance() from entry WinMain.

What is the utility of CWinApp class?

This is constructed during global C++ objects are constructed and is already available when Windows calls the WinMain function, which is supplied by the ...

Basic steps in Win32 GUI Application with source code.

Define a custom Window class structure, Register the class name, CreateWindow, Show windows and write message get and dispatch loop statements. Define the Window CallBack procedure and write the handlers.

What is a Window CallBack procedure and what is its utility?

DispatchMessage() is a API which indirectly triggers the Window CallBack procedure. Message structure members from this function are passed to the CallBack procedure. CallBack procedure should implement event handlers depending on the need of the application.

What are LPARAM and WPARAM in window proc function?

LPARAM and WPARAM are the two parameters in Window CallBack procedure. They signifies parameters of various events. They are used in handing individual events.

What are the basic steps of a typical MFC based application?

We need to write WinMain and need to follow all these in a Win32 application. However we need not to write much if we are writing an application with MFC ...

#