Topic : Bitmaps in MFC
Author : Unknown
Page : 1 Next >>
Go to page :


Bitmap


From this chapter we are going to deal with another GDI object bitmap, which is a very complex issue in Windows( programming. There are many topics on how to use bitmaps, how to avoid color distortion, how obtain palette from bitmap, how convert from one bitmap format to another, and how to manipulate image pixels.

Samples in this chapter are specially designed to work on 256-color palette device. To customize them for non-palette devices, we can just eleminate logical palette creation and realization procedure.

1 BitBlt and StretchBlt

DIB & DDB

There are two type of bitmaps under Windows(: device independent bitmap (DIB) and device dependent bitmap (DDB). As we know, each computer may be equipped with a different type of device, therefore may use different format to store bitmap images in the hardware. Before displaying any image on the screen, we need to convert the image data to a format that is understandable by the hardware device, otherwise the image could not be displayed correctly. This format is called device dependent bitmap format (DDB), because it is hardware dependent. However, using DDB format will cause incompatibility between different systems, because one DDB format may not be understandable by another device. To solve this problem, under Windows(, a device independent bitmap format (DIB format) is supported by all device drivers. When we call the standard function to load a device independent bitmap, the device driver will convert it to DDB that is understandable by the device.

Drawing DDB

There are several ways to include bitmap image in an application. The simplest one is to treat it as bitmap resource. To load the image, we can call function CBitmap::LoadBitmap(...) and pass the bitmap resource ID to it.

After the bitmap is loaded, we need to output it to the target device (such as screen). The procedure of outputting a bitmap to a target device is different from using a pen or brush to draw a line or fill a rectangle: we cannot select bitmap into the target DC and draw the bitmap directly. Instead, we must create a compatible memory DC and select the bitmap into it, then copy the bitmap from memory DC to the target DC.

The functions that can be used to copy a bitmap between two DCs are CDC::BitBlt(...) and CDC::StretchBlt(...). The former function allows us to copy the bitmap in 1:1 ratio, and the latter one allows us to enlarge or reduce the dimension of the original image. Lets first take a look at the first member function:

BOOL CDC::BitBlt

(

int x, int y, int nWidth, int nHeight,

CDC *pSrcDC,

int xSrc, int ySrc,

DWORD dwRop

);


There are eight parameters, first four of them specify the origin and size of the target bitmap that will be drawn. Here x and y can be any position in the target device, also, nWidth and nHeight can be less than the dimension of source image (In this case, only a portion of the source image will be drawn). The fifth parameter is a pointer to the source DC. The seventh and eighth parameters specify the origin of the source bitmap. Here, we can select any position in the source bitmap as origin. The last parameter specifes the bitmap drawing mode. We can draw a bitmap using many modes, for example, we can copy the original bitmap to the target, turn the output black or white, do bit-wise OR, AND or XOR operation between source bitmap and target bitmap.

Creating Memory DC

A memory DC used for copying bitmap image must be compatible with the target DC. We can call function CDC::CreateCompatibleDC(...) to create this type of DC. The following is the format of this function:

BOOL CDC::CreateCompatibleDC(CDC* pDC);

The only parameter to this function (pDC) must be a pointer to the target DC.

Retrieving the Dimension of Bitmap Image

We see that in order to copy the bitmap from one DC to another, we need to know the dimension of the bitmap. The bitmap size, along with other information, can be retrieved by calling function CBitmap::GetBitmap(...). If we pass a BITMAP type pointer to this function, the object will be filled with the bitmap information. The bitmap dimension is stored in members bmWidth and bmHeight of structure BITMAP.

Sample 1\GDI

Sample 1-1\GDI demonstrates how to use function CDC::BitBlt(...). It is a standard SDI application generated by Application Wizard, and its view is based on class CScrollView. In the sample, first a bitmap resource is added to the application, whose ID is IDB_BITMAP.

A CBitmap type variable is declared in class CGDIDoc, it will be used to load this bitmap:

(Code omitted)

Variable m_bmpDraw will be used to load the bitmap, and function GetBitmap() will be used to access it outside class CGDIDoc. Bitmap IDB_BITMAP is loaded in the constructor of class CGDIDoc:

(Code omitted)

In function CGDIView::OnInitialUpdate(), we need to use bitmap dimension to set the total window scroll sizes so that if the window is not big enough, we can scroll the image to see the covered portion:

(Code omitted)

The bitmap pointer is obtained from the document. By calling function CBitmap::GetBitmap(...), all the bitmap information (including its dimension) is obtained and stored in variable bm. Then the scroll sizes are set using bitmap dimension. By doing this, the scroll bars will pop up automatically if the dimension of the client window becomes smaller than the dimension of the bitmap.

Function CGDIView::OnDraw(...) is implemented as follows:

(Code omitted)

First we call CDC::CreateCompatibleDC(...) to create a compatible memory DC, then use it to select the bitmap obtained from the document. Like other GDI objects, after using a bitmap, we need to select it out of the DC. For this purpose, a local variable pBmpOld is used to store the returned address when we call CDC::SelectObject(...) to select the bitmap (pBmp) into memory DC. After the bitmap is drawn, we call this function again to select pBmpOld, this will select bitmap stored by pBmp out of the DC.

In the next step function CBitmap::GetBitmap(...) is called to retrieve all the bitmap information into variable bm, whose bmHeight and bmWidth members (represent the dimension of bitmap) will be used for copying the bitmap. Then we call CDC::BitBlt(...) to copy the bitmap from the memory DC to the target DC. The origin of the target bitmap is specified at (0, 0), also, the source bitmap and target bitmap have the same size.

Sample 1-2\GDI

Sample 1-2\GDI demonstrates how to use function CDC::StretchBlt(...) to output the bitmap image. It is based on sample 1-1\GDI. In this sample, the image is enlarged to twice of its original size and output to the client window.

Because the target image has a bigger dimension now, we need to adjust the scroll sizes. First function CGDIView::OnInitialUpdate() is modified as follows for this purpose:

(Code omitted)

The scroll sizes are set to twice of the bitmap size.

Function CDC::StretchBlt(...) has 10 parameters:

(Code omitted)

There are two extra parameters nSrcWidth and nSrcHeight here (compared to function CDC::BitBlt()), which specify the extent of original bitmap that will be output to the target. Obviously, nWidth and nSrcWidth determine the horizontal ratio of the output bitmap (relative to source bitmap). Likewise, nHeight and nSrcHeight determine the vertical ratio.

In the sample, both horizontal and vertical ratios are set to 200%, and function CGDIView::OnDraw(...) is modified as follows:

(Code omitted)

With the above modifications, we will have an enlarged bitmap image in the client window.

2 Extracting Palette from DIB

If we execute the previous two samples on a palette device, we may experience color distortion (Please open file 1-1\bitmap.bmp using a standard graphic editor and compare the results). This is because we didn't implement logic palette for displaying the bitmap, so the the colors of the bitmap pixels are mapped to the nearest colors available in the system. To avoid color distortion, we must implement logical palette before drawing the bitmap.

Another problem is that when we call function CBitmap::LoadBitmap(...) to load the bitmap resource, it will create a device dependent bitmap from the data stored in the resource. So after the the bitmap is loaded, it becomes DDB, which could only be understood by the device. To extract palette information from the bitmap data, we must use DIB format.

To avoid color distortion, we must implement logical palette for device dependent bitmap before it is drawn to the target device. Because function CBitmap::LoadBitmap(...) does not extract palette and the bitmap data stored in the resource is in the format of DIB, we must convert the bitmap to DDB and extract palette information from it by ourselves.

DIB Format

A DIB comprises three parts: bitmap information header, color table, and bitmap bit values. The bitmap information header stores the information about the bitmap such as its width, height, bit count per pixel, etc. The color table contains an array of RGB colors, it can be referenced by the color indices. The bitmap bit values represent bitmap pattern by specifying an index into the color table for every pixel. The color table can also be empty, in which case the bitmap bit vlues must be actual R, G, B combinations.

There are several type of DIBs: monocrome, 16 colors, 256 colors and 24 bit. The first three formats

Page : 1 Next >>