GDI Accessories and Tools: Colors

 Overview of Colors

The color is one the most fundamental objects that enhances the aesthetic appearance of an object. The color is a non-spatial object that is added to an object to modify some of its visual aspects. The MFC library, combined with the Win32 API, provides various actions you can use to take advantage of the various aspects of colors.

Three numeric values are used to create a color. Each one of these values is 8 bits. The first number is called red. The second is called green. The third is called blue:

Bits
Red
 7 6 5 4 3 2 1 0
Green
 7 6 5 4 3 2 1 0
Blue
 7 6 5 4 3 2 1 0

Converted to decimal, each one of these numbers would produce:

27 +  26 + 25 + 24 + 23 + 22 + 21 + 20

= 128 + 64 + 32 + 16 + 8 + 4 + 2 + 1

= 255

Therefore, each number can have a value that ranges from 0 to 255 in the decimal system.

These three numbers are combined to produce a single number as follows:

Color Value
 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 Blue Green Red

Converted to decimal, this number has a value of 255 * 255 * 255 = 16581375. This means that we can have approximately 16 million colors available. The question that comes to mind is how we use these colors, to produce what effect.

You computer monitor has a surface that resembles a series of tinny horizontal and vertical lines. The intersection of a one horizontal line and a vertical line is called a pixel. This pixel holds, carries, or displays one color.

As the pixels close to each other have different colors, the effect is a wonderful distortion that creates an aesthetic picture. It is by changing the colors of pixels that you produce the effect of color variances seen on pictures and other graphics.

 The Color as a Data Type

Microsoft Windows considers that a color is a 32-bit numeric value. Therefore, a color is actually a combination of 32 bits:

Color Value
 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 0 Blue Green Red

The bits of the most significant byte (the left byte) are reserved for the operating system's internal use and must be set to 0. Based on this, each color is characterized by its combination of a red, a green, and a blue values.

When all three numbers have their lowest value, which is 0, the color is called black. When the numbers are at their highest value, which is 255, the color is called white. Not all color combinations have a name. In fact, in MS Windows programming, the names are very limited. For this reason, color are rarely called by a name and usually, a name would depend on who is using it. Nevertheless, there are popular names that most people recognize. Examples are Black, White, Red, Green, Blue, Yellow. Except for black and white, each color can assume different variations. For example, when all three numbers have the same value but neither 0 nor 255, the color is called Gray by there are more than 250 possible combinations. Sometimes the combination is called Silver (each value is 192) or Gray (values=128).

The 32-bit numeric value used to characterize a color is defined by the COLORREF data type in Microsoft Windows programming. It can be used to declare a color value. Here is an example:

```void CExoView::OnDraw(CDC* pDC)
{
COLORREF NewColor;
}```

When of after declaring such a variable, you can initialize it with a 32-bit decimal value. Here is an example:

```void CExoView::OnDraw(CDC* pDC)
{
COLORREF NewColor = 16711935;
}```

Although the above number (16711935) is a legitimate color value, it does not mean much. To create a color value, the Win32 API provides the RGB macro. Its syntax is:

`COLORREF RGB(BYTE byRed, BYTE byGreen, BYTE byBlue);`

The RGB macro behaves like a function and allows you to pass three numeric values separated by a comma. Each value must be between 0 and 255. Therefore, the above initialization can be done as follows:

```void CExoView::OnDraw(CDC* pDC)
{
COLORREF NewColor = RGB(255, 0, 255);
}```

Whether a color was initialized by a 32-bit integer or using the RGB macro, if you want to retrieve the red, green, and blue values of a color, you can use the GetRValue(), the GetGValue(), of the GetBValue() macros to extract the value of each. The syntaxes of these macros are:

 `BYTE GetRValue(DWORD rgb);` `BYTE GetGValue(DWORD rgb);` `BYTE GetBValue(DWORD rgb);`

Each macro takes a 32-bit value as argument, arg. The GetRValue() macro returns the red value of the rgb number. The GetGValue() macro returns the green value of the rgb number. The GetBValue() macro returns the blue value of the rgb number.

 Color Palettes

Device independence is the ability for an application to draw its intended figures, text, shapes, and display colors regardless of the device on which the drawing is performed. One way to take care of this is to manage colors at the operating system level so that Microsoft Windows can select the right color to render an object or portion of it. In some cases, a device, such as a monitor or a printer, may need to take care of the coloring details of the jobs it is asked to perform.

A color palette is a list of colors that a device can display. For example, one device may be able to handle only two colors; such is the case for a black and white printer. Another device could be able to use more colors than that. To control this situation, Microsoft Windows keeps track of the color palette of each device installed on the computer.

There are two types of color palettes. The default color palette is a list of colors that the operating system would use on a device unless notified otherwise. There are typically 20 reserved colors as default. A logical palette is a palette that an application creates for a specific device context.

 Coloring a Pixel

As mentioned above, a pixel is the real object that holds a color. Although it is so small, you can access a pixel and change its color. The pixels are stored in an array of [x][y] value. In fact, when you try accessing a pixel, you would be asked to provide a color for it. To change the color of a pixel, you can call the CDC::SetPixel() method. Its syntaxes are:

```COLORREF SetPixel(int x, int y, COLORREF crColor);
COLORREF SetPixel(POINT point, COLORREF crColor);```

The pixel you want to access is defined by its x and y coordinates, which can also be specified with a POINT or CPoint object as the point argument. The color you want to specify is the crColor argument.

Here is an example of using the SetPixel() function:

```void CExo2View::OnMouseMove(UINT nFlags, CPoint point)
{
HDC hDC = ::GetDC(this->GetSafeHwnd());

if( this->IsDrawing == TRUE )
SetPixel(hDC, point.x, point.y, RGB(255, 55, 5));

::ReleaseDC(this->GetSafeHwnd(), hDC);

CView::OnMouseMove(nFlags, point);
}

void CExo2View::OnLButtonDown(UINT nFlags, CPoint point)
{
this->IsDrawing = TRUE;

CView::OnLButtonDown(nFlags, point);
}

void CExo2View::OnLButtonUp(UINT nFlags, CPoint point)
{
this->IsDrawing = FALSE;

CView::OnLButtonUp(nFlags, point);
}
```
 Rectangles With 3-D Effect

Using colors, you can draw a rectangle with a 3-D effect. To do this, the CDC class provides the Draw3dRect() method. Its syntaxes are:

```void Draw3dRect(LPCRECT lpRect,
COLORREF clrTopLeft, COLORREF clrBottomRight);
void Draw3dRect(int x, int y, int cx, int cy,
COLORREF clrTopLeft, COLORREF clrBottomRight);```

The rectangle to draw can be provided by its location and size through the x, y, cx, and cy arguments. You can also pass it as a pointer to RECT or CRect for the lpRect argument.

Specify a color for the top and left sides of the rectangle as the clrTopLeft argument.

The clrBottomRight argument holds the color of the right and bottom sides of the rectangle.

Here is an example:

 ```void CExoView::OnDraw(CDC* pDC) { pDC->Draw3dRect(20, 24, 238, 108, RGB(192, 192, 192), RGB(128, 128, 128)); }```