Displaying Bitmaps With GDIRemember when I told you that bitmaps are easy to work with, because they're native to Windows? Well now we're going to find out just how easy it is. :) There are four basic steps to displaying a bitmap with GDI:
You already know how to do the first step. I alluded to the second one last time, but didn't go over it. I said that there was a function called LoadBitmap() that retrieves a handle to a bitmap resource. However, this function is obsolete now; it has been superseded by LoadImage(), which is much more flexible. So that's what we'll be using. Here she is:
The function returns NULL if it fails. Otherwise, you get a handle to the bitmap, which can either be loaded from a resource or from an external file. Notice that since this function can be used for bitmaps, cursors, or icons, the return type is simply HANDLE. In Visual C++ 6.0, you'll need to include a typecast to HBITMAP or the compiler will become angry with you. Here are the parameters for the function: HINSTANCE hinst: This should be the instance of your application if you're loading a resource, or NULL if you want to load from an external file. LPCTSTR lpszName: This is either the resource identifier -- remember to use MAKEINTRESOURCE() if you're using numerical constants -- or the full filename of the image you want to load. UINT uType: Depending on what you want to load, this should be set to either IMAGE_BITMAP, IMAGE_CURSOR, or IMAGE_ICON. int cxDesired, cyDesired: These are the desired dimensions for the image to be loaded. If you set them to zero, the image's actual dimensions will be used. UINT fuLoad: Like everything else we've done today, this is one or more of a series of flags which can be logically combined with the | operator. Here are the useful flags:
For loading bitmaps you should use LR_CREATEDIBSECTION, and LR_LOADFROMFILE if it is appropriate. Now that you have obtained a handle to your image, you must create a device context and load the bitmap into it. The first step is taken by calling CreateCompatibleDC(), as follows:
The parameter is a DC with which to make the new DC compatible. If you pass NULL, the DC will be made compatiable with the display screen, which is what we want. The return value is a handle to a memory device context -- not a display device context! This means that the contents of this DC won't be visible. If the function fails, the return value is NULL. Now, to get the bitmap into the memory device context, we use this:
The type HGDIOBJ is more general than our HBITMAP, so never fear, they're compatible without any tricks on our part. Here are the parameters: HDC hdc: This is a handle to the device context which we want to fill with an object. For loading bitmaps, this must be a memory device context. HGDIOBJ hgdiobj: And this is a handle to that object. This function is used with bitmaps, brushes, fonts, pens, and regions; but the only one that concerns us is bitmaps. The return value is a handle to the object that is being replaced in the DC, or NULL if an error occurs. The return values are different for regions, but like I said, we don't care about regions. :) Now you've got a bitmap loaded into a DC, and you need only take the last step: copying the contents of the memory device context to our display device context. However, it's necessary to obtain some information about the bitmap, such as its dimensions, which must be used in the function call that will display the image. For that, we need the GetObject() function, which is used for obtaining information about graphical objects such as bitmaps.
The return value is the number of bytes successfully obtained, or 0 for function failure. The parameters for the function are the following: HGDIOBJ hgdiobj: The handle to the graphics object we want information on. In this case, pass the handle to the bitmap we loaded. int cbBuffer: This is the size of the structure receiving the information. In the case of loading bitmaps, the receiving structure is of type BITMAP, so set this to sizeof(BITMAP). LPVOID lpvObject: Pass the address of the structure receiving the information. You need to define a variable of type BITMAP, and with a quick call to the GetObject() function, you'll have the information you need. Since the BITMAP structure is new to us, I'll show you what it looks like:
There aren't too many members to this thing, and we're really only interested in two of them, but I'll list them all here anyway. LONG bmType: This is the bitmap type and must be set to zero. Useful, isn't it? LONG bmWidth, bmHeight: These are the two we're after -- the width and height of the bitmap, in pixels. LONG bmWidthBytes: Specifies the number of bytes in each line of the bitmap. Note that the number of bytes per pixel can be obtained by dividing this value by bmWidth. LONG bmPlanes: This is the number of color planes. LONG bmBitsPixel: This is the number of bits required to represent one pixel. It would appear that the note I left about figuring this out is useless. :) LPVOID bmBits: If you want to access the actual image data, this is a pointer to the bit values for the bitmap. All right, almost done! Now we have the bitmap in a memory device context, and we know its dimensions. All we have to do is copy it from one DC to the other, and that only takes a single function call. See, I told you bitmaps were easy to deal with. There are actually two options you can use here. I'll show you both of them.
The return value is TRUE or FALSE based on whether the function succeeds. You've seen that plenty of times before. There are a lot of parameters, but most of them are pretty easy to figure out. HDC hdcDest: The destination device context handle. In our case, this will be the display device context for our window.
int nXDest, nYDest: The coordinates of the upper-left hand corner of the region where the bitmap will end up. Remember that for our DC, these coordinates are client coordinates -- relative to the client area of our window. int nWidth, nHeight: These are the width and height of the destination and source rectangles, since this function doesn't perform scaling. Pass the dimensions of the bitmap. HDC hdcSrc: This is the source device context handle. In our case, this is the memory device context that our bitmap is currently residing in. int nXSrc, nYSrc: The x- and y- coordinates of the source rectangle's upper-left corner. In this case you would use (0, 0), but this may not always be the case, depending on what you're using the source DC for, or if you only want to copy a part of the image. DWORD dwRop: There are a lot of operation codes you can use here, most of them dealing with Boolean operations on the data in the two device contexts. The only one we're interested in is SRCCOPY, which copies the contents of the source DC directly to the destination DC. That's about all there is to it! The other option you have is to use StretchBlt(), which requires you to specify the width and height for both the source and destination rectangles. StretchBlt() then scales the image in the source DC to fit in the rectangle specified on the destination DC. This can be useful for scaling images, but as always, since BitBlt() has fewer capabilities to worry about, it's faster. Here is the prototype for StretchBlt():
The parameters are basically the same as those in BitBlt(), so I shouldn't have to go through them again. The raster operation codes for StretchBlt() are the same as those for BitBlt(); just set it to SRCCOPY. Now, the last thing you need to know is a little bit of cleanup. Creating a DC like we did for this example is not quite like getting a DC for the display device. Instead of calling ReleaseDC(), you must call DeleteDC(). It looks basically the same:
The parameter is simply the device context to delete, and the return value is a BOOL again, and we all know what that means, right? All right, are you feeling pretty good about all this stuff? Just for the sake of tying all these steps together, I'll show you a function you can use for loading and displaying a bitmap resource using all GDI functions. For this example, I'm assuming you have saved the handle to the instance of the application in a global called hinstance.
|
|||||||