V. Advanced Development of GDI/GDI + Advanced Programming
In this lecture, we will focus on three aspects.
1. tiled Images
2. DC offset
3. Save the image file to a local disk.
When drawing the background image, it is found that the bitmap is not fully covered in the entire customer area. There are two ways to solve this problem: one is to stretch the bitmap, and the other is to tile the bitmap, which is easier to stretch the bitmap, call the stretchblt function to copy the bitmap to adapt to the size change of the customer zone. How to Implement Bitmap Tile? In the first lecture, bitblt was used to copy the bitmap in the memory DC to the Target DC. The bitmap used is srccopy, therefore, if the bitmap is displayed as its default size, it does not increase or decrease as the window size changes, can it be the same as the size of the customer area and the size of the default bitmap, and then fill the customer zone with the appropriate number of bitmaps?
Obviously, this method is feasible. This operation is equivalent to filling the customer area with a bitmap directly loaded in the first lecture, in the first lecture, the reason why the entire customer zone is not fully covered is that the bitmap is only filled once, that is, no matter whether or not the window needs to be re-painted, only one bitmap is filled, now we need to calculate the size of the customer zone. When the size changes, the number of filled bitmaps also needs to be changed to ensure that the entire customer zone can be fully covered.
First, we need to plot the customer zone and obtain its DC. here we can use the getdc () function to obtain the DC. In getdc (), we need to input a window handle, so that you can know which window the DC is obtained. Now, after obtaining the DC, you should plot it and perform other operations. However, you must remember to save the default DC attributes of the current system before the operation, in this way, after the operation is complete, the system will be restored without affecting other methods that call the default DC attribute of the system. For the sake of simplicity, we use savedc to save all the properties in DC at one time.
The specific operation code is as follows:
// Obtain the DC of the window
HDC = getdc (hwnd );
// Save the DC status
Int ISDC = savedc (HDC );
The operation we need to do is to overlay the bitmap across the entire customer area, so we need to load the bitmap into the memory, load the bitmap by calling loadbitmap, and save the returned bitmap handle. The loadbitmap prototype is as follows:
Hbitmap loadbitmap (
Hinstance, // handle to application instance
Lpctstr lpbitmapname // name of Bitmap Resource
);
Load Code:
Hbitmap =: loadbitmap (hinst, makeintresource (idb_bitmap1 ));
After the bitmap is loaded into the memory, it cannot be directly drawn to the Target DC, which is equivalent to printing things. For example, the process of printing things is as follows:
The first step is to copy the document to be printed to the USB flash drive,
Step 2: copy the items in the USB flash drive to the computer,
Step 3: output the content of this document on the computer to A4 in the printer through the print program.
Loading the bitmap to the memory is equivalent to copying the document to the USB flash drive.
To print this document, the second step is to copy the document to a computer. to copy the document to a computer, you must first have a computer. The bitmap must be drawn to the Target DC, first, we need to copy the data to the memory DC. to copy the data to the memory DC, we need a memory DC. Therefore, we need to create a memory DC first.
HDC hmemdc = createcompatibledc (HDC );
Then copy the object to the memory DC, and select the bitmap from the memory to the memory DC.
SelectObject (hmemdc, hbitmap );
This time we want to fill the entire customer area with bitmap tiled, so we need to know the figure and the size of the customer area, to determine whether a single bitmap can be filled up or whether n images can be filled up, we need to calculate the bitmap size and the size of the customer zone.
First, declare a bitmap variable and call GetObject () to obtain bitmap information.
Bitmap bitmap;
: GetObject (hbitmap, sizeof (Bitmap), & Bitmap );
After obtaining the bitmap information, you must obtain the size of the customer zone.
Rect;
: Getclientrect (HDC, & rect );
However, we will not plot the background of the entire customer area, but specify an area for tiled filling, because we have already implemented this function through stretching, if you use tile for this function, you need to shield the previous code. Specify a rectangle with a length of 300 and a width of 300 to fill the bitmap. How many bitmaps need to be calculated for this region to fill up?
Calculate the number of bitmaps required for a row to be filled up.
Int inumx = 300/bitmap. bmwidth + 1; this should be well understood, 300/bitmap. bmwidth is to fill in a few bitmaps in one row. Adding one pixel is a good way to draw a rectangle to check whether it is filled with the specified rectangle. Also, to calculate a column, you need to fill in several bitmaps.
Int inumy = 300/bitmap. bmheight + 1;
Now the size of the image itself has been calculated, and several bitmaps need to be calculated in the specified area. Previously, the bitmap is also selected into the memory DC, the current memory DC becomes the source DC, and then the bitmap in the source DC needs to be pasted to the specified area on the Target DC respectively.
For (INTI = 0; I <inumy; ++ I)
For (Int J = 0; j <inumx; ++ J)
Bitblt (HDC, J * bitmap. bmwidth, I * bitmap. bmheight, bitmap. bmwidth, BMP. bmheight, hmemdc, 0, 0, srccopy );
Okay. Now the bitmap has been attached to the specified rectangle. How can we see it sticking to the specified rectangle? We can draw a rectangular box of this size to help check it. If you draw a border with a paint brush, create a paint brush first, select the current DC, and then call rectangle to draw, destroy the corresponding handle.
Hpen hpenred =: cretepen (ps_solid, 1, RGB (255, 0 ));
: SelectObject (HDC, hpenred );
Draw Rectangular Box
Rectangle (HDC, 300,300 );
: Deleteobject (hpenred );
: Deleteobject (hbitmap );
: Deleteobject (hmemdc );
Recover DC after use
Restoredc (HDC, ISDC );
Note that we have obtained a DC Through getdc. If you don't need it now, remember to release it with releasedc.
Releasedc (hwnd, HDC );
When F5 is run, it is found that the rectangle box is filled by the system's default white paint brush. Therefore, you should select an empty paint brush before the rectangle is drawn to the current DC.
SelectObject (HDC, getstockobject (null_brush ));
When F5 is run, we can see the background bitmap filled in the rectangle, but we find that the bitmap is filled out of the rectangle, but we may not need it to be displayed outside the rectangle. How can we solve this problem? Here we need to introduce the concept of area reduction.
Is to edit the DC
You can use the selectcliprgn function to edit a specified area. Only the part to be edited is drawn. The prototype is as follows:
Selectcliprgn (hdchdc, hrgn );
The HDC parameter is the DC handle for editing.
The hrgn parameter is the area for editing.
The area to be edited is not necessarily the area of the rectangle, it can be the area of the rounded rectangle or the area of the circle. For example:
Createrectrgn (intx1, int Y1, int X2, int Y2,
Createroundrectrgn (intx1, int Y1, int X2, int Y2, int W, int H) is the area where the rounded rectangle is created.
Createelipticrgn (intx1, int Y2, int X2, int Y2); creates a circular area.
So how can we modify the previous Code so that the bitmap is not pasted out of the rectangle frame?
In fact, before bitblt textures, we first use hrgn to create a rectangular area, and then select this rectangular area as DC Through selectcliprgn, in this way, the content in the current DC is displayed only in the rectangle area, and the content in other places is not displayed until the DC is reached.
The specific operation code is as follows:
Hrgn = createrectrgn (0, 0, 300,300 );
Selectcliprgn (HDC, hrgn );
For (INTI = 0; I <inumy; ++ I)
......
In this way. So the above tile method is certainly a way of thinking, so there is no other way to achieve this tile function? The above is to solve this problem by calculating how many bitmaps are needed in the rectangle area and then filling in the number of bitmaps. In fact, you don't have to worry about this. You can directly create a bitmap image brush, because bitmap paint brushes support tiled objects, you do not need to calculate the size of the customer area or the bitmap.
The operation method is also:
1. Load the bitmap through loadbitmap ()
2. Call createpatternbrush () to create a texture painter Based on the loaded bitmap.
3. Select the image painter to the current DC.
4. Create a red paint brush to observe
5. Call rectangle to draw a rectangle.
6. aftercare cleaning
The Code is as follows;
Hbitmap = loadbitmap (hinst, makeintresource (idb_bitmap1 ));
Hbrush HBr = createpatternbrush (hbitmap );
SelectObject (HDC, HBr );
Hpen hpenred = createred (ps_solid, 1, RGB (255, 0 ));
SelectObject (HDC, hpenred );
Rectangle (HDC, 300,300 );
: Deleteobject (hpenred );
: Deleteobject (hbitmap );
Deleteobject (HBr );
Restoredc (HDC, ISDC );
After the bitmap is tiled, let's talk about the concept of DC offset. For example, I wrote a lot of code, but they are all based on the coordinates of 0, 0, sometimes we think that the coordinates should not start from 0 to 0. We need to modify the values in the functions in the DC, but may not be able to modify them. One is that there may be many commands, and the other is modified, second, sometimes the code for DC drawing is not written by us and cannot be modified. For example, the drawing in another dynamic library is for the upper left corner, but you need to offset it now, but the source code cannot be modified. What should I do now? In this case, you can change the value of the canvas by modifying the source point of the canvas. You can call setviewportorgex to offset the original origin to the desired position. For example, if the original origin is 0
Setviewportorgex (HDC, 300,300, null); then the current origin is 300,300. Its prototype is as follows:
Boolsetviewportorgex (
HDC, // handle todevice Context
Int X, // newx-coordinate of viewport Origin
Int y, // newy-coordinate of viewport Origin
Lppoint // original viewport Origin
);
The lppoint is the original point.
You can also use getviewportorgex (hdchdc, lppoint); to obtain the coordinates of the starting point of the current painting.
The HDC parameter is the DC handle to obtain the start coordinate of the painting.
The lppoint parameter is used to obtain the starting coordinate of the HDC currently drawn.
After the image is drawn, we usually need to save it. How can we save images? Here we save it as a BMP file. First, let's take a look at the bitmap structure information:
A bmp file consists of four parts:Bitmap File Header,Bitmap header,Color paletteAndImage Data.
Bitmap File HeaderContains the image type, image size, image data storage address, and two reserved unused fields. The prototype is as follows:
Typedef structtagbitmapfileheader {
Word bftype; // image type
DWORD bfsize; // image size
Word bfresereved1; // reserved unused fields
Word bfreserved2; // reserved unused fields
DWORD bfoffbits; // address for storing image data
} Bitmapfileheader;
Bitmap headerContains the size of the bitmap information header, image width and height, image color depth, compression instructions, image data size and other parameters.
Typedef struct tagbitmapinfoheader {
DWORD bisize; // size of the current structure
Long biwidth; // BMP Image Width
Long biheight; BMP Image Height
Word biplanes; // Number of image faces
Word bibitcount; // The color depth of the image, that is, the number of bits in a pixel.
DWORD bicompression; // compression mode. For example, 0 indicates no compression, 1 indicates rle8 compression, and 2 indicates rle4 compression.
DWORD bisizeimage; // size of BMP image data.
Long bixpelspermeter; // horizontal resolution
Long biypelspermeter; // vertical resolution
DWORD biclrused; // the color of the BMP image. 0 indicates that all colors are used. For bitmap 256, this value is 256.
DWORD biclrimportant; // number of important colors. When this value is 0, all colors are important. For BMP images using the color palette, when the video card cannot display all colors, this value is colored by the secondary driver.
} Bitmapinfoheader;
The color palette is unique to a monochrome, 16-color, and 256-color image file. The size of the corresponding color palette is 2, 16, and 256. The color palette is in 4 bytes, each 4 bytes stores a color value. The image data points to the palette index.
The color palette is used when the colors are not full.
Data structure definition of the palette:
Typedef struct tagrgbquad {
Byte rgbblue; // blue value
Byte rgbgreen;
Byte rgbred;
Byte rgbreserved;
} Rgbquad;
Bitmap data: if the image is monochrome, 16, and 256 colors, the bitmap data follows the color palette, And the bitmap data points to the index sequence number of the color palette.
If the image is a 16-bit, 24-bit, and 32-bit color, the color palette is not retained in the file, that is, there is no color palette, and the color of the image is given directly in the bitmap data.
A 16-bit image uses two bytes to store color values. There are two common formats: 5-bit red, 5-Bit green, 5-bit blue, and 5-bit red, 6-Bit green, and 5-bit blue, that is, the 555 format and the 565 format. The 555 format uses only 15 bits, and the last bits are retained, set to 0.
The 24-bit image uses three bytes to save the color value. Each byte represents a color, which is arranged in red, green, and blue.
The 32-bit image uses 4 bytes to save the color value. Each byte represents a color, in addition to the original red, green, blue, and Alpha channels, that is, the transparent color.
Here we want to save a 24-bit BMP image file, so we first set the variable with 24 bytes for each pixel
Word wbitcount = 24;
Then define the size of pixel bytes in the bitmap, the size of the bitmap file, and the number of bytes written to the file. The value is initialized to 0.
DWORD dwbmbitsize = 0, dwdibsize = 0, dwwritten = 0;
Next, declare the bitmap attribute structure.
Bitmap bitmap;
Declare bitmap file header Structure
Bitmapfileheader bmfhdr;
Declare bitmap information header Structure
Bitmapinfoheader Bi;
Declares a pointer to the bitmap information header structure.
Lpbitmapinfoheader lpbi;
Declare a file handle and a memory handle
Handle FH, hdib;
Then calculate the number of bytes occupied by each pixel in the bitmap file.
HDC = getdc (null );
GetObject (hbitmap, sizeof (Bitmap), (lpstr) & Bitmap );
Bi. bisize = sizeof (bitmapinfoheader );
Bi. biwidth = bitmap. bmwidth;
Bi. biheight = bitmap. bmheight;
Bi. biplanes = 1;
Bi. bibitcount = wbitcount;
Bi. bicompression = bi_rgb;
Bi. bisizeimage = 0;
Bi. bixpelspermeter = 0;
Bi. biypelspermeter = 0;
Bi. biclrimportant = 0;
Bi. biclrused = 0;
Dwbmbitsize = (bitmap. bmwidth * wbitcount + 31)/32) * 4 * bitmap. bmheight;
Hdib = globalalloc (ghnd, dwbmbitsize + sizeof (bitmapinfoheader ));
Lpbi = (lpbitmapinfoheader) globallock (hdib );
* Lpbi = Bi;
Getdibits (HDC, hbitmap, 0, (uint) bitmap. bmheight, (lpstr) lpbi + sizeof (bitmapinfoheader), (bitmapinfo *) lpbi, dib_rgb_colors );
Releasedc (null, HDC );
FH = createfilea (L "C: \ image.bmp", generic_write, 0, null, create_always, file_attribute_normal | file_flag_sequential_scan, null );
If (invalid_handle_value = FH)
{
Showerrmsg ();
Return false;
}
// Set the bitmap file header
Bmfhdr. bftype = 0x4d42; // "BM"
Dwdibsize = sizeof (bitmapfileheader) + sizeof (bitmapinfoheader) + dwbmbitsize;
Bmfhdr. bfsize = dwdibsize;
Bmfhdr. bfreserved1 = 0;
Bmfhdr. bfreserved2 = 0;
Bmfhdr. bfoffbits = (DWORD) sizeof (bitmapfileheader) +
(DWORD) sizeof (bitmapinfoheader );
// Write the bitmap file header writefile (FH, (lpstr) & bmfhdr, sizeof (bitmapfileheader), & dwwritten, null );
// Write the remaining contents of the bitmap file
Writefile (FH, (lpstr) lpbi, dwdibsize, & dwwritten, null );
// Clear
Globalunlock (hdib );
Globalfree (hdib );
Closehandle (FH );
When F5 runs to drive C, isn't there a saved image.bmp file? What's going on? No error is reported. There is no error prompt. Why is it not saved? If you change disk C to another disk, you can see that the file is saved. What is the problem? It doesn't matter. We can use the getlasterror () function and the formatmessage function to get the corresponding error information. The Code is as follows:
Void showerrmsg ()
{
Tchar szbuf [80];
Lpvoid lpmsgbuf;
Dword dw = getlasterror ();
Formatmessage (
Format_message_allocate_buffer |
Format_message_from_system,
Null,
DW,
Makelangid (lang_neutral,
Sublang_default
),
(Lptstr) & lpmsgbuf,
0, null );
Wsprintf (szbuf, _ T ("% sfailed: getlasterror returned % u \ n "),
Lpmsgbuf, DW );
MessageBox (null, (lpcwstr) szbuf, _ T ("error"), mb_ OK );
Localfree (lpmsgbuf );
}
Then we call this error code and find that the error code 5 indicates access is denied? Oh, you cannot write data to drive C because you do not have the permission. The solution is to right-click the project properties, select the list file, select UAC execution level, select requireadministrator, save the configuration, and then run F5, disk C shows the saved file.
// Start ///////// tile method A ///// // * int isdcfa = savedc (HDC ); hbitmap hbitmapfa =: loadbitmapw (hinst, makeintresource (outputs); HDC hmemdcfa =: createcompatibledc (HDC); SelectObject (hmemdcfa, hbitmapfa); bitmap BMP fa ;:: getobjecta (hbitmapfa, sizeof (Bitmap), & bmp fa); int inumx = 300/BMP fa. bmwidth + 1; int inumy = 300/BMP fa. bmheight + 1; hrgn =: createrectrgn (300,300,); selectcliprgn (HDC, hrgn); For (INT I = 0; I <inumy; ++ I) for (Int J = 0; j <inumx; ++ J) bitblt (HDC, J * BMP fa. bmwidth, I * BMP fa. bmheight, BMP fa. bmwidth, BMP fa. bmheight, hmemdcfa, 0, 0, srccopy); Hpen hpenred =: createpen (ps_solid, 1, RGB (255, 0); SelectObject (HDC, hpenred); SelectObject (HDC, getstockobject (null_brush); rectangle (HDC, 300,300,);: deleteobject (hpenred);: deleteobject (hmemdcfa);: deleteobject (hbitmapfa); restoredc (HDC, isdcfa ); * // end // tiled Mode A // start ////// //// bitmap image paid B /////////// int ISDC = savedc (HDC );: histogram (HDC, null); hbitmap =: loadbitmapw (hinst, makeintresource (idb_bitmap1); hbrush hbrfb =: histogram (hbitmap); SelectObject (HDC, hbrfb); Hpen hpenred = createpen (ps_solid, 1, RGB (300,300, 0); SelectObject (HDC, hpenred); rectangle (HDC );:: deleteobject (hbitmap);: deleteobject (hbrfb);: deleteobject (hpenred); restoredc (HDC, ISDC ); // end //////// bitmap painting/tile mode B /////////////