[Repost] Working principle and how to program the palette

xiaoxiao2021-03-06  15

Palette principle

The image displayed on the PC is made up of a pixel, each pixel has its own color properties. In the display system of the PC, the color of the pixel is based on the RGB model, and the color of each pixel is combined by red (B), green (G), blue (B) three primary colors. Each original color is represented by 8 bits, such a color is 24 bits. With this, the PC's SVGA adapter can display 224 more than 1,600,000 colors at the same time. The 24-bit color is often referred to as true color, with a true color display image to achieve a very realistic effect.

However, true color display requires a lot of video memory, a 640 × 480 true color image requires about 1MB of video memory. Since the amount of data is large, the display of true color will make the overall performance of the system quickly decline. In order to solve this problem, the computer uses a palette to limit the number of colors. The palette is actually a RGB color table with 256 entries, each of the color tables is a 24-bit RGB color value. When using a palette, the 24-bit color value stored in the video memory is not stored, but the 4-bit or 8-bit index of the palette. In this way, the color of the display can be displayed simultaneously within 256 colors, which is greatly reduced to the system resources.

The display can be set to 16, 256, 64K, true color and other display mode, the first two modes require a palette. In 16 or 256-color mode, the program must correctly set the color you want to display into the palette, so that the expected color can be displayed. Figure 11.1 shows the working principle of the palette. One advantage of using the palette is that you do not have to change the value in the video memory, just change the color item of the palette, you can quickly change the color or grayscale of an image.

In DOS, there is no problem with the use of the palette. Since DOS is a single task operating system, only one program can be run at a time, so the program can exclusively palette. In the Windows environment, the situation is not that simple. Windows is a multi-task operating system that can run multiple programs at the same time. If several programs are set to set a palette, it is possible to conflict. In order to avoid this conflict, Windows uses logical palettes as buffering between applications and system palette (physical palette) using color.

Figure 11.1 Working principle of palette

In Windows, the application uses a system palette (physical palette) through one or more logical palettes. In a 256-color system palette, Windows retains 20 colors as static colors, which are used as a Windows interface, and the application generally cannot change. The default system palette only contains these 20 static colors, and other items of the palette are empty. To use the new color, you must implement the logical palette containing the desired color to the system palette. During the implementation, Windows first matches items in the logical palette with the items in the system palette. For items that cannot be fully matched in the logical palette, Windows adds it to the blank of the system palette. In the system, the system palette has a total of 236 blank items available. If the system palette is full, Windows matches the remainder of the logical palette to the system palette as close as possible.

Each device context has a logical palette, the default logical palette only 20 reserved colors, if you want to use new colors, you should create a new logical palette and select it into the device context. in. But light does not use new colors, and the program only implements the logical palette in the device context to the system palette, the new color can be implemented. When the logical palette is implemented to the system palette, Windows creates a palette mapping table. When the color drawing in the device context, the GDI draw function queries the palette map table to convert the pixel value from the logical palette index to the index of the system palette, so when the pixel is output There is a correct color value in the video memory. Figure 11.2 illustrates this mapping relationship, and readers can experience the buffer of the logical palette from the readers. In this figure, the GDI draw function draws the color in the index 1 of the logical palette, by querying the palette map table, to know that the index in the system palette is completely matched, so actually output to The pixel value in the video memory is 23. Note that the incomplete match of color, that is, index 15 and index 46 in the logical palette in the logical palette. Each window to use additional colors implements its own logical palette, each color in the logical palette has the same or similar match in the system palette. The higher the color of the palette, the higher the accuracy of the match. Windows stipulates that the logical palette of the active window (if any) has the highest implementation priority. This is because the moving window is currently interacting with the user, and should ensure that it has the best color display. The priority of the non-active window is determined in the z-order (Z order is the overlapping order of the overlapping window). The event window has the right to implement its logical palette as a foreground palette, and the non-active window can only implement background palette.

Tip: The term activity window (Foreground Window) refers to a window that is currently interacting with the user. The top of the active window is highlighted, and the title bar of the non-active window is gray. The activity window is definitely a top window (top window means that there is no parent window or the parent window is a window window, which typically has title and border, which mainly includes a frame window and dialog. The term overlapping window refers to a window as an application main window, we can regard the dialog as a special overlapping window.

Figure 11.2 Mapping relationship of the palette

11.1.2 Creation and implementation of the palette

The MFC's CPALETTE class encapsulates the logical palette. The member function CreatePalette of this class is responsible for creating a logical palette, the function of the function is:

Bool CreatePalette (LPLOGPALETTE LPLOGPALETTE); // Returns True.

The parameter LPLOGPALETTE is a pointer to the LPLOGPALETTE structure, which describes the content of the logical palette, which is defined as:

Typedef struct taglogpalette {

Word Palversion; // windows version number, usually 0x300

Word PalNumentries; // Number of color entries in the palette

Paletteentry Palpalent [1]; // Color and use of each entry

Logpalette;

The most important member of the structure is a PaletteEntry array, and the number of item items is specified by the PalNuMentries member. The PaletteEntry structure describes a color entries for the palette that the definition of this structure is:

Typedef struct tagpaletteentry {

Byte pered; // Red strength (0 ~ 255, the same below)

Byte pegreen; // Green strength

Byte peblue; // blue strength

Byte peflags;

} Paletteentry;

Members PeFlags illustrate the method of use of color entries, null in general applications, if the reader is interested in PEFLAGS, you can view the online help of Visual C . It can be seen that the key to creating a palette is to specify the color to use in the PaletteEntry array. These colors can be special colors specified by the program, or can be loaded from the DIB bitmap. The size of the logical palette can be determined according to the number of colors used by the user, generally not more than 256 color entries.

CreatePalette just creates a logical palette. At this time, the palette is just an isolated color table, and it is not impact on the system. The program must call CDC :: SelectPalette to select the logical palette to the device context to use, and then call CDC: RealizePalette to implement the logical palette into the system palette. The declaration of the function is:

CPALETTE * SELECTPALETTE (CPALETTE * PPALETTE, BOOL BFORCEBACKGROUND);

This function selects the specified palette to the device context. Parameters PPALETTE points to a cPalette object. Parameters BFORCEBACKGROUND If it is true, the selected palette is always used as a background palette. If BFORCEBACKGROUND is false and the device context is attached to a window, then when the window is a sub-window of the active window or active window The selected palette will be implemented as the foreground palette, otherwise it is achieved as a background palette. If the palette is used is a memory device context, the parameter is ignored. The function returns the palette used in the device context. If you go wrong, return NULL.

Uint realizepalette ();

This function implements the logical palette in the device context into the system palette. The return value of the function indicates how many items in the palette map are changed.

If a window is to display a special color, you should generally implement your own logical palette when processed the WM_PAINT message. That is, before the onpaint or ondraw function, you want to call SelectPalette and REALIZEPALETTE. If the color of the window is more important, you should specify the bforcebackground parameter to false when calling SelectPalette.

The prospect palette has the highest priority using the color, which has the power of the system palette (except 20 reserved colors), that is, if necessary, the foreground palette will cover 236 of the system palette. Entries, regardless of whether these items are being used by other windows. Background palette does not destroy the use items in the system palette.

Readers should pay attention to the foreground palette should be unique. If a moving window is simultaneously implemented, only one palette is implemented as the foreground palette, that is, when calling CDC :: SelectPalette, there can be only one bforcebackground is specified as false, other BfortBackground must be true. Usually, the palette of the window with input focus is achieved as the foreground palette, and the other windows can only use the background palette. If the sub-window of the active window all uses the foreground palette, it will cause the program's dead loop.

Tip: Please read the reader to pay attention to distinguish between the event window and the window with input focus. The window with input focus is either an active window itself or the sub-window of the active window. That is, the movable window does not necessarily have an input focus. When the sub-window of the active window gets the input focus, the active window will lose the input focus.

11.1.3 Three methods using colors

When calling a GDI function drawing, you can select a color with a different method. Windows uses the ColorRef data type to represent the color, the length of the ColorRef value is 4 bytes, where the highest bit byte can take three different values, respectively correspond to three methods of using colors. Table 11.1 lists these different values ​​and its meaning. Table 11.1 The meaning of the highest bit byte of the colorRef value

Value meaning

0x00 Specifies RGB reference. At this time, the three low bytes contain red, green, blue intensity, and Windows will jitter 20 reserved colors to match the specified colors, regardless of whether the program implements its own palette.

0x01 Specifies the palette index reference. At this time, the lowest bit byte contains the index of the logical palette, and Windows finds the desired color in the logical palette according to the index.

0x02 Specifies the palette RGB reference. At this time, the three low bytes contain red, green, blue strength, and Windows will find the most matching color in the logical palette.

For the convenience of users, Windows provides three macro to build three different colorref data, which are:

ColorRef RGB (Byte Bred, Byte Bgreen, Byte Bblue); // RGB reference

ColorRef PaletteIndex (Word WPALETTEINDEX); / / Toner Index Reference

ColorRef Palettergb (Byte Bred, Byte Bgreen, // Toner RGB reference

BYTE BBLUE);

For example, we can specify the color of the brush with the above three methods. The following code creates a brush with red in the system palette:

CBRUSH brush;

Brush.createsolidbrush (RGB (255, 0, 0);

PDC-> SelectObject (& brush);

The following code creates a brush with the colors of the logical palette index 2:

PDC-> SELECTPALETTE (& M_Palette, False);

PDC-> RealizePalette ();

CBRUSH brush;

Brush.createsolidbrush (PaletteIndex (2));

PDC-> SelectObject (& brush);

The following code creates a brush with the most matching dark gray in the logical palette:

PDC-> SELECTPALETTE (& M_Palette, False);

PDC-> RealizePalette ();

CBRUSH brush;

Brush.createsolidbrush (Palettergb (20, 20, 20));

PDC-> SelectObject (& brush);

11.1.4 Messages related to the system palette

In order to coordinate the use of the system palette, Windows will send a message WM_QueryNewPalette and WM_Palettechanged to the top window and overlapping window when necessary.

When a top or overlap window (such as the main frame window) is activated, the WM_QueryNewPalette message will be received, and the message will be received at the beginning of the window, which will arrive at the WM_PAINT message to the window. If the active window is to use special colors, you should implement your own logical palette and redraw the window when you receive the message. If the window implements a logical palette, the process function of the WM_QUERYNEWPALETTE message should return True. Usually the window should be a window (such as a view) that has an input focus after receiving the message, but if the program feels that the color it displays is not important, then the logical palette can be used after receiving the message. As a background palette (specified CDC :: SelectPalette function's bforcebackground parameter True), this program has lost the highest priority using the system palette.

When the active window implements its foreground palette and changes the system palette, Windows sends a WM_PALETTECHANGED message to all top windows and overlapping windows including the active window, and contains changing system in the WPARAM parameter of the message. Handle of the window of the color plate. Other windows If you use your own logical palette, you should re-implement its logical palette and redraw the window. This is because the system palette has been changed, and must re-establish the palette mapping table and redraw, otherwise the error of the error may be displayed. Of course, the non-active window can only use the background palette, so the color of the display is definitely not in the front desk. Note that only WM_PALETTECHANGED messages are generated when the foreground palette is implemented in the active window and changes the system palette. That is, if the window specifies the BForcebackground parameter to True when calling CDC: SelectPalette, then a WM_PALETTECHANGED message is not generated. In short, the WM_QUERYNEWPALETTE message provides an opportunity to implement the foreground palette for the active window, while the WM_PALETTECHANGED message provides a window that adapts to the system palette changes.

It should be noted that the sub-window is not received with a message related to the palette. Therefore, if the sub-window (such as a view) uses its own logical palette, the top window or overlapping window should prompt the sub-window to associate with the palette.

11.1.5 Specific example

Let us now look at a demo program using a palette. The program is named TestPal, as shown in Figure 11.3, the program shows two sets of red squares, each set of 16 × 16 total 256. This set of blocks on the left is drawn with a logical palette. The intensity of the red is increasing from 0 to 255. As a contrast, 256 incremental red squares are drawn in the right with RGB. The reader can compare the color quality of the two sets of squares to experience the palette index reference and the difference between RGB references. The program also focuses on the reader to demonstrate the method of processing a palette message.

Figure 11.3 TestPal program

First, readers please build a MFC single text application called TestPal with AppWizard. Then, use classWizard to add the WM_QUERYNEWPALETTE and WM_QALETTECHANGED messages to the CMAINFRAME class, use the default function name. Next, add the following line before the definition of class ctestpalapp in the testpal.h file:

#define WM_DOREALIZE WM_USER 200

When a palette message is received, the main frame window will send a user-defined WM_DOREALIZE message notification view.

Finally, please read by modify the program by Listing 11.1 and 11.2.

Some code of the list 11.1 CMAINFRAME class

Bool CMAINFRAME :: ONQUERYNEWPALETTE ()

{

// Todo: add your message handler code here and / or call default

GetActiveView () -> SendMESSAGE (WM_DOREALIZE);

Return true; // Returns true indicates a logical palette

}

Void CMAINFRAME :: OnPalettechanged (CWND * PFOCUSWND)

{

CframeWnd :: OnPalettechanged (pfocuswnd);

// Todo: Add your message Handler Code Here

IF (getActiveView ()! = pfocusWnd)

GetActiveView () -> SendMESSAGE (WM_DOREALIZE);

}

Some code of the list 11.2 CTestPalView class

// TestPalView.h: interface of the ctestpalview ClassClass CTestPalview: Public CVIEW

{

.

protected:

CPALETTE M_PALETTE;

.

AFX_MSG LRESULT ONDOREALIZE (WPARAM WPARAM, LPARAM LPARAM);

Declare_message_map ()

}

// TestPalView.cpp: Implementation of the CTestPalView Class

Begin_MESSAGE_MAP (CTestPalView, CVIEW)

.

ON_MESSAGE (WM_DOREALIZE, ONDOREALIZE)

END_MESSAGE_MAP ()

CTestPalView :: ctestpalview ()

{

// Todo: Add Construction Code Here

LPLOGPALETTE PLOGPAL;

PLOGPAL = (LPLOGPALETTTE) Malloc (Sizeof (Logpalette)

SizeOf (Paletteentry) * 256);

PLOGPAL-> paRversion = 0x300;

PLOGPAL-> PALNUMENTRIES = 256;

For (int i = 0; i <256; i )

{

PLOGPAL-> PALPALENTRY [i] .pered = i; // initialized to red

PLOGPAL-> PALPALENTRY [i] .pegreen = 0;

PLOGPAL-> PALPALENTRY [i] .peblue = 0;

PLOGPAL-> PALPALENTRY [I] .peflags = 0;

}

IF (! m_palette.createpalette (plogpal))

AfxMessageBox ("Can't create Palette!");

}

Void CTestPalView :: OnDraw (CDC * PDC)

{

CTestPaldoc * pdoc = getDocument ();

Ask_VALID (PDOC);

// Todo: Add Draw Code for Native Data HERE

CBRUSH Brush, * Poldbrush;

INT X, Y, I;

PDC-> SELECTPALETTE (& M_Palette, False);

PDC-> RealizePalette ();

PDC-> SelectStockObject (Black_pen);

For (i = 0; i <256; i )

{

X = (i% 16) * 16;

Y = (I / 16) * 16;

Brush.createsolidbrush (PaletteIndex (i)); // Palette index reference

Poldbrush = PDC-> SelectObject (& brush);

PDC-> Rectangle (X, Y, X 16, Y 16);

PDC-> SELECTOBJECT (POLDBRUSH);

Brush.deleteObject ();

}

For (i = 0; i <256; i )

{

X = (i% 16) * 16 300;

Y = (I / 16) * 16;

Brush.createsolidbrush (RGB (i, 0, 0)); // RGB reference

Poldbrush = PDC-> SelectObject (& brush);

PDC-> Rectangle (X, Y, X 16, Y 16); PDC-> SelectObject (Poldbrush);

Brush.deleteObject ();

}

}

LResult CtestPalview :: Ondorealize (WPARAM WPARAM, LPARAM)

{

CClientDC DC (this);

Dc.selectPalette (& M_Palette, False);

IF (DC.RealizePalette ()) // Refresh by if the palette mapping is changed

GetDocument () -> UpdateAllViews (NULL);

Return 0L;

}

A logical palette containing 256 increasing red is created in the constructor of the CTestPalView.

When it is changed to the active window and the window creation, the main frame window of the TestPal program receives the WM_QueryNewPalette message. The handler ONQUERYNEWPALETTE is responsible for sending a WM_DOREALIZE message notification view and returns True to indicate that the active window implements a logical palette. The processing function of the WM_DOREALIZE message CTestPalView :: Octorealize implements a foreground palette, which is a judging statement to improve the efficiency of the program run: if the CDC: RealizePalette return value is greater than zero, then the palette map is displayed. The change must be refreshed at this time, otherwise the color in the drawing will distort. If REALIZEPALETTE returns zero, it means that the palette mapping has not changed, and there is no need to refresh the view.

Whether TestPal or other applications implement the foreground palette and change the system palette, the main frame window of the TestPal program receives the WM_PALETTECHANGED message. Note that the message is handled by the message, CMAINFRAME: ONPALETTECHANGED has a PFOCUSWND parameter, which indicates which window changes the system palette. The function is determined by pfocusWnd. If other applications implemented the foreground palette, the notification view calls the ONDOREALIZE to implement its logical palette, note that although the cdc :: selectpalette's bfortebackground parameter is false, but this time the logic of the view The plate is achieved as a background palette. If it is a TestPal's own view to implement the foreground palette, there is no need to call ONDOREALIZE.

Please set the current display mode of Windows to 256 colors, then compile and run TestPal, compare the effect of the RGB reference and the palette index reference, the reader is not difficult to find that the color of the palette index in the left is better than the right. many. Through the program, we can see that even if rich red is enriched in the system palette, the red refer to RGB is still 20 shake color of 20 reserved colors.

The reader can open a Windows brush program and open a 256-color bitmap (such as Forest.BMP under the Windows directory) in the program. Switching between the brush and the TestPal program, the reader can see that due to the correct palette messages correctly, the application in the front desk always has the best color display, while the color of the background program is Some distortion, but it is more satisfactory.

It should be noted that the TestPal program only uses a logical palette, so it handles the method of palette messages relatively simple. If the program uses multiple logical palette, then some new measures need to be used to ensure that only one logical palette is used as the foreground palette.

转载请注明原文地址:https://www.9cbs.com/read-46172.html

New Post(0)