11.04.2014 Views

Advanced MFC Programming

Advanced MFC Programming

Advanced MFC Programming

SHOW MORE
SHOW LESS

Create successful ePaper yourself

Turn your PDF publications into a flip-book with our unique Google optimized e-Paper software.

Chapter 10. Bitmap<br />

is no way for us to prevent a pixel from being drawn, because functon ::SetDIBitsToDevice(…) will<br />

simply copy every pixel contained in an image to the target device (It does not provide different drawing<br />

mode such as bit-wise AND, OR, or XOR).<br />

To draw image with transparency, we need to prepare two images, one is normal image and the other is<br />

mask image. The mask image has the same dimension with the normal image and contains only two colors:<br />

black and white, which indicate if a corresponding pixel contained in the normal image should be drawn or<br />

not. If a pixel in the normal image has a corresponding black pixel in the mask image, it should be drawn.<br />

If the corresponding pixel is white, it should not be drawn. By doing this, any image can be drawn with<br />

transparency.<br />

A DDB image can be painted with various drawing modes: bit-wise AND, OR, XOR, etc. Different<br />

drawing modes will combine the pixels in the source image and the pixels in the target device differently.<br />

Special effects can be made by applying different drawing modes consequently.<br />

When drawing a DDB image, we can use bit-wise XOR along with AND operation to achieve<br />

transparency. First, the normal image can be output to the target device by using bit-wise XOR mode. After<br />

this operaton, the output pattern on the target device is the XORing result of its original pattern and the<br />

normal image. Then the mask bitmap is output to the same position using bit-wise AND mode, so the<br />

background part (corresponding to white pixels in the mask image) of the device still remains unchanged (it<br />

is still the XORing result of the original pattern and the normal image), however, the foreground part<br />

(corresponding to black pixels in the mask image) becomes black. Now lets ouput the normal image to the<br />

target device using bit-wise XOR mode again. For the background part, this is equivalent to XORing the<br />

normal image twice with the original pattern on the target device, which will resume its original pattern<br />

(A^B^A = B). For the foreground part, this operation is equivalent to XORing the normal image with 0s,<br />

which will put the normal image to the device (0^B = B).<br />

Although the result is an image with a transparent background, when we implement the abovementioned<br />

drawings, the target device will experience pattern changes (Between two XOR operations, the<br />

pattern on the target device is neigher the original pattern nor the normal image, this will cause flickering).<br />

So if we do all these things directly to the device, we will see a very short flickering every time the image is<br />

drawn. To make everything perfect, we can prepare a bitmap in the memory and copy the pattern on the<br />

target device to it, then perform XOR and AND drawing on the memory bitmap. After the the drawing is<br />

complete, we can copy the memory bitmap back to the device. For the memory bitmap, since its<br />

background portion has the same pattern with that of the target device, we will not see any flickering.<br />

To paint a DDB image, we need to prepare a memory DC, select the bitmap into it, then call function<br />

CDC::BitBlt(…) or CDC::StretchBlt(…) to copy the image from one device to another.<br />

In order to draw an image with transparent background, we need to prepare three DDBs: the normal<br />

image, the mask image, and the memory bitmap. For each DDB, we must prepare a memory DC to select<br />

it. Also, because the DDB must be selected out of DC after drawing, we need to prepare a CBitmap type<br />

pointer for each image.<br />

Since the usr can load a new image when there is an image being displayed, we need to check the<br />

states of variables that are used to implement DCs and bitmaps. Generally, before creating a new memory<br />

DC, it would be safer to check if the DC has already been initialized. If so, we need to delete the current<br />

DC and create a new one. Before deleting a DC, we further need to check if there are objects (such as<br />

bitmap, palette) currently being selected. All the objects created by the user must be selected out before a<br />

DC is delected. The DC can be deleted by calling function CDC::DeleteDC(). Also, before creating a<br />

bitmap, we need to check if the bitmap has been initialized. If so, before creating a new bitmap, we need to<br />

call function CGDIObject::DeleteObject() to destroy the current bitmap first.<br />

Functions CBitmap::CreateBitmap(…) and CDC::CreateCompatibleDC(…) will fail if CBitmap and CDC<br />

type variables have already been initialized.<br />

If a logical palette is implemented, we must select it into every DC before performing drawing<br />

operations. Before the application exits, all the objects selected by the DCs must be selected out, otherwise<br />

it may cause the system to crash.<br />

Although we can prepare normal image and mask image separately, it is not the most convenient way<br />

to implement transparent background. The mask image can also be generated from the normal image so<br />

long as all the background pixels of the normal image are set to the same color (For example, white). In this<br />

situation, pixel in the mask image can be set by examing the corresponding pixel in the normal image: if it<br />

is the background color, the pixel in the mask image should be set to white, otherwise it should be set to<br />

black.<br />

316

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!