When we draw on a SVGA the GDI maps each COLORREF value to the nearest static color using a color matching algorithm. For many applications this form of color mapping is acceptable. But in an application where a more accurate color output is required 20 colors are too little to choose from. In such cases we can use a logical palette to add 236 more colors to the DAC registers. We, of course, cannot program the DAC registers directly because the same VDU is being shared amongst several applications running in memory. Hence, to get our jobs done we have to use a GDI object called logical palette. A logical palette is nothing but a table of RGB color values. The process of adding the colors in the logical palette to the DAC registers (often called Hardware Palette) is known as realizing the palette. This article shows how to create a logical palette and realize it. The program displays a window containing 24 rectangles drawn with a solid pen of thickness 8 pixels. The first 12 rectangles are drawn using different shades of red color. As mentioned earlier, these colors are mapped to the nearest out of the 20 static colors. As a result, all 12 shades mapped to one of the two shades of red colors present in the list of static colors (Refer Table 1). The next 12 rectangles have been drawn after realizing the palette. Hence you can notice 12 distinct shades of red. In MFC, to create logical palette we have to use the CPalette class's member functions. Once a logical palette is created it can be selected into a device context and realized with CDC member functions. In our program once the window is created the myframe::OnCreate( ) function gets called. Here we have first ascertained whether using a logical palette will improve color output, by calling CDC::GetDeviceCaps( ) as shown below.
if ( ( d.GetDeviceCaps ( RASTERCAPS ) & RC_PALETTE ) == 0 )
MessageBox ( "Palette is not supported by this device \n Change Settings", "Sorry" ) ;
return -1 ;
It is a good idea to perform this check. If you are running the application on XGA then you don't need a logical palette because in a XGA, perfect color output is available free. If you are running the application on a VGA, palettes are meaningless since the system palette is initialized with 16 static colors that leave no room for colors in logic palette. It is when the application is run on SVGA, we can get more color accuracy by using a logical palette. Hence the check. Next we have created 12 pens for drawing the first 12 rectangles. Then we have created a logical palette through the statement,
m_palette.CreatePalette ( pLP ) ;
Before we call CPalette::CreatePalette( ) we have to fill in a LOGPALETTE structure with information describing the palette colors. The LOGPALETTE structure has been defined as follows.
typedef struct tagLOGPALETTE
WORD palVersion ;
WORD palNumEntries ;
PALETTEENTRY palPlaEntry ;
} LOGPALETTE ;
palVersion specifies the LOGPALETTE version number; in all current releases of Windows, it should be set to 0x300. palNumEntires specifies the number of colors in logical palette. palPalEntry is an array of PALETTEENTRY structures defining the colors themselves. The number of elements in the array should equal the value of palNumEntries. PALETTEENTRY is defined as follows:
typedef struct tagPALETTEENTRY
BYTE peRed ;
BYTE peGreen ;
BYTE peBlue ;
} PALETTEENTRY ;
peRed, peGreen and peBlue specify a color's 8-bit RGB components. peFlags contains zero or more bit flags describing the type of palette entry. The PLAETTENETRY array in the LOGPALETTE structure is declared with just one array element because Windows has no way of anticipating how many colors a logical palette will contain. As a result, you cannot just declare an instance of LOGPALETTE on the stack and fill it in; instead, we have to allocate memory for it based on numbers of PALETTEENTRY structures it contains. Once the palette has been created it needs to be selected into the device context and then realized. Since this must be done before any drawing takes place we have done these two tasks in the OnPaint( ) handler. Note that palette is selected with CDC::SelectPalette( ) instead of CDC::SelectObject( ). CDC::RealizePalette( ) realizes the palette that is currently selected into the device context by asking the palette manager to map colors from logical palette to the system palette. Once the palette has been realized we are ready to start drawing. If we use CDC::BitBlt( ) to display a bitmap, the realized colors are used automatically. However, if we are using a pen or a brush and are using the RGB macro, the GDI maps the COLORREF value only to the static colors. Since we want the GDI to use all the palette colors we must use the PALETTERGB( ) macro instead of RGB( ).