How Windows uses colors?

Though XGA is gaining ground fast, VGA and SVGA still remain the most commonly used video adapters today. Of these, the VGA adapter uses 4 bits to represent a pixel, whereas, the SVGA and XGA use 8 and 24 bits respectively. Let us understand how these adapters manage colors.

In VGA the display memory is organized in four planes—Red, Green, Blue and Intensity. One bit from each of these planes contributes towards one pixel value. The VGA adapter has several registers which together makes up its programming interface. Of these, the ones that are of our interest here are the palette registers, color select registers, and the DAC registers. The 4-bit pixel value from display memory is used as the address of one of the 16 palette registers. For example, a pixel value of 0 selects palette register 0, a pixel value of 1 selects palette register 1 and so on. Each palette register is 8 bits long of which 6 bits are used. Once the palette register has been chosen, the 6-bit value in it is combined with a 2-bit value from a color select register, resulting into an 8- bit value. The 8-bit value is used as the address of one of the 256 DAC (Digital to Analog Converter) registers. Each DAC register contains an 18-bit value which represents the color. The 18-bit value is organized in 6-bit red, green and blue color components. This value is sent to the analog conversion circuitry, which converts it into three proportional analog signals and sends them to the monitor. Since each DAC register is 18-bit long, a pixel can have any of the 2,62,144 values ( 218 ).

VGA supports several graphics modes. The two popular ones are: 640 x 480, 16-color mode and a 320 x 200, 256-color mode. In the former, the color select register bits always have a value 0. Hence, in this mode only the first 64 DAC registers get used. As a result, only 64 out of the possible 2,62,144 color values can be used. And since there are only 16 palette registers, only 16 out of the 64 DAC registers can get selected. Thus in this graphics mode we can use any 16 out of the 2,62,144 colors.

In the 256-color mode, the 2-bits from the color select register can take values like 00, 01, 10 and 11. This combined with 64 possible values from the palette registers permit us to select one of the 256 DAC registers. As a result we can use 256 out of possible 2,62,144 color values.

As said earlier, SVGA uses 8 bits to represent a pixel. In SVGA there are 256 palette registers. Thus, using the 8-bit pixel value it can access 256 palette registers. Each value in the palette register can further access 256 DAC registers. Each DAC register is 24 bits long. Hence, in SVGA we can choose 256 colors simultaneously out of the possible 16,77, 716 (224) colors.

Let us now see how Windows utilizes the color capabilities of these adapters. When you pass a color to the windows GDI, you pass a COLORREF value, containing 8 bits each for red, green and blue. The RGB macro combines individual red, green and blue values into a single COLORREF value. For example, the statement

COLORREF c = RGB ( 128, 128, 0 ) ;

creates a COLORREF value named c. We can use this COLORREF value while building pens and brushes. When we pass this COLORREF value on XGA adapter (which uses 24 bits per pixel) the 24-bit value is translated directly into colors on the screen. However, as we saw earlier, The VGA and the SVGA support a wide range of colors but can display only a limited amount of colors at one time. For example, a VGA running at a resolution of 640 x 480 pixels can display only 16 colors at a time out of the possible 2,62,144 colors. Similarly, a SVGA we can display only 256 colors at a time out of the possible 16,777,16 colors. Note that 16 or the 256 colors that can be displayed on these adapters are determined by the contents of the DAC Registers. The pixel value is merely an index into the palette registers and the palette register value is an index into the DAC registers.

Windows handles VGA and SVGA devices by preprogramming a standard selection of colors into the adapter’s DAC registers. The SVGA adapter is preprogrammed with 20 colors shown in the following table. These colors are known as static colors.

Color

R

G

B

Black

0

0

0

Dark black

128

0

0

Dark green

0

128

0

Dark yellow

128

128

0

Dark blue

0

0

128

Dark magenta

128

0

128

Dark cyan

0

128

128

Light gray

192

192

192

Money Green

192

220

192

Sky blue

166

202

240

Cream

251

251

240

Intermediate gray

160

160

164

Medium gray

128

128

128

Red

255

0

0

Green

0

255

0

Yellow

255

0

255

Magenta

255

0

255

Blue

0

0

255

Cyan

0

255

255

White

255

255

255

Table 1

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.

In this article we will see a program that 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 \nChange 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[1] ;

} 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( ).

Download

No comments: