Full introduction to DDB and DIB bitmap programming in Visual C ++

Source: Internet
Author: User

Author: Song Baohua

Source: Skynet

1. Basic Concepts

First, we will explain the concept of Bitmap and palette with common statements.

We know that all colors in nature can be composed of red, green, and blue (R, G, B. It can be divided into 0 ~ There are 255 levels, and different combinations of red, green, and blue are 256x256x256, so they can represent about 16 million colors. For human eyes, this is already "true color.

For each vertex (r,gand bits), the extended file name in the computer is generally .bmp. Since the quantified values of R, G, and B can be used to directly record all the pixels of a bitmap, what should we do with the color palette?

First, we can calculate the space required to use (R, G, B) combinations to store a 800 × 600 bitmap:

800 × 600 × 3 = 1440000 (bytes) = 1.37 m (bytes)

Amazing big! As a result, the palette is born, and its function is to alleviate the problem of excessive storage space of Bitmap files.

Assume that a bitmap is 16 colors, and the total number of pixels is 800 × 600. We only need to use 4 bits to store the level of each pixel of this bitmap in 16 colors, and then the color palette provides the corresponding (R, G, b) value. to store this 16-color bitmap, you only need:

800 × 600 × 4/8 = 240000 (bytes) = 0.22 m (bytes)

The overhead for storing the R, G, and B Tables (that is, the palette, also known as the color search table LUT) is only 16 × 3 = 48 bytes.

The storage space is greatly reduced!

Common bitmap types include monochrome, 16-color, 256-color, 16-bit, and 24-bit real-color. You can store the first three colors (no greater than 256 colors) in a color palette, it is not cost-effective to store 16-bit and 24-bit true colors in a color palette. They are directly stored according to the R, G, and B components.

On this basis, we analyze the DDB Bitmap (device-Dependent Bitmap, device-related Bitmap) and DIB bitmap (device-independent bitmap, device-independent Bitmap) concept and the difference between the two.

DDB depends on a specific device. It can only exist in memory (video memory or system memory). The color mode must be consistent with the specific output device and use the system color palette. Generally, only DDB bitmaps with relatively simple colors can be loaded. For color-rich bitmaps, dib must be used for long-term storage.

DiB is independent of a specific device and can be used to permanently store images. DiB is generally stored in the disk as a *. BMP file, and sometimes saved in the *. Dib file. DIB bitmap stores color information in the color table of the bitmap file. The application creates a logical color palette for DiB. Therefore, before outputting a dib bitmap, the program should select its logical palette into the context of the relevant device and implement it into the system palette.

  2. Routine description

Subsequent explanations in this article are based on such an example project. It is a dialog box-based MFC application, including two parent menus:

(1) DDB bitmap

The DDB bitmap parent menu contains two sub-menus:

A. ID: idm_loadddbpic caption: Load

Click Event: load the DDB bitmap in the resource and display it

B. ID: idm_mark_ddbpic caption: Flag

Click Event: transparently Add the Skynet logo to the DIB bitmap.

(2) DIB bitmap

The DIB bitmap parent menu contains two sub-menus:

A. ID: idm_opendibpic caption: Open

Click Event: pop-up dialog box, open the. BMP bitmap file, and display

B. ID: idm_mark_dibpic caption: Flag

Click Event: transparently Add the Skynet logo to the DIB bitmap.

The project also contains the following bitmap resources:

(1) idb_loaded_bitmap: the bitmap resource to be loaded.

(2) idb_yesky_bitmap: Skynet logo

The subsequent sections will focus on the explanation of the event message processing function in the four sub-menus. The following code shows the message ing of cbitmapexampledlg in the entire dialog box:

Begin_message_map (cbitmapexampledlg, cdialog)
// {Afx_msg_map (cbitmapexampledlg)
On_wm_syscommand ()
On_wm_paint ()
On_wm_querydragicon ()
On_command (idm_loadddbpic, onloadddbpic)
On_command (idm_mark_ddbpic, onmarkddbpic)
On_command (idm_opendibpic, onopendibpic)
On_command (idm_mark_dibpic, onmarkdibpic) //} afx_msg_map
End_message_map ()

 

3. DDB bitmap Programming

First look at the DDB loading button click event code:

Void cbitmapexampledlg: onloadddbpic ()
{
1: cbitmap BMP draw;
2: BMP draw. loadbitmap (idb_loaded_bitmap); // load the DDB bitmap to be loaded.
3: bitmap BMP Info;
4: BMP draw. getbitmap (& BMP info); // obtain the size of the DDB bitmap to be loaded.
5: CDC memdc; // defines a compatible DC
6: cclientdc (this );
7: memdc. createcompatibledc (& DC); // create compatible DC
8: cbitmap * pbmpold = memdc. SelectObject (& BMP draw); // Save the original DDB and select the new DDB into the DC

9: DC. bitblt (0, 0, BMP info. bmwidth, BMP info. bmheight, & memdc, 0, 0, srccopy );

10: memdc. SelectObject (pbmpold); // select the original DDB
}

The above code will produce the effect shown in 1. The bitmap is placed at the starting position of the (0, 0) coordinate in the dialog box.


Figure 1 Load DDB bitmap Resources

Let's parse the above code line by line to figure 1.

Lines 1st and 2 define a cbitmap object and call its member function loadbitmap to load the bitmap resource idb_loaded_bitmap in the project. Lines 3rd and 4 define the bitmap struct instance and call the cbitmap member function getbitmap to obtain the bitmap information. The bitmap struct is defined in the header file <wingdi. h> in the form:

/* Bitmap header definition */
Typedef struct tagbitmap
{
Long bmtype; // It must be 0
Long bmwidth; // The bitmap width (in pixels)
Long bmheight; // The height of the bitmap (in pixels)
Long bmwidthbytes; // The number of bytes required for each scan row, which should be an even number
Word bmplanes; // Number of color planes
Word bmbitspixel; // number of bits in the color plane
Lpvoid bmbits; // point to the array storing the pixel array
} Bitmap, * pbitmap, near * npbitmap, far * lpbitmap;

5th ~ Row 8 builds a CDC object, calls CDC: createcompatibledc to create a compatible memory device context, and then calls CDC: SelectObject to select DDB into the memory device context.

Row 3 calls the function CDC: bitblt to draw a bitmap. The prototype of CDC: bitblt is:

CDC: bitblt (int x, int y, int nwidth, int nheight, CDC * psrcdc, int xsrc, int ysrc, DWORD dwdrop)

CDC: The bitblt operation is to copy bitmap from the source DC to the Target DC. The first four parameters are the coordinates (x, y) and length and width (width, nheight) of the target region. The fifth parameter is the source DC pointer, the following parameter is the starting coordinate of the source DC, and the last parameter is the type of the grating operation.

Row 3 calls CDC: SelectObject to select the original DDB into the context of the memory device and remove the new DDB.

Another function, CDC: stretchblt, corresponds to CDC: bitblt, which has the scaling function. Its prototype is:

Bool CDC: stretchblt (int x, int y, int nwidth, int nheight, CDC * psrcdc, int
Xsrc, int ysrc, int nscwidth, int nscheight, DWORD dwrop );

This function copies the bitmap from the source rectangle to the destination rectangle. If the Source and Destination rectangles have different sizes, the bitmap function scales to adapt to the size of the destination rectangle. Most of the parameters of the function are the same as those of bitblt, but two more parameters are used to specify the width and height of the source rectangle.

If we change the row 9th in the cbitmapexampledlg: onloadddbpic () function:

Crect clientrect;
Getclientrect (& clientrect); // obtain the window size of the dialog box.
DC. stretchblt (0, 0, clientrect. Right, clientrect. Bottom, & memdc, 0, 0,
BMP info. bmwidth, BMP info. bmheight, srccopy );

Click the Load button, as shown in dialog box 2. The bitmap is stretched to the entire dialog box.


Figure 2 stretch a bitmap

CDC: The dwdrop parameter in bitblt and DC. stretchblt functions is more useful. It defines the type of grating operation. See the message processing function code of an event in the "mark" submenu under "DDB bitmap" parent menu:

Void cbitmapexampledlg: onmarkddbpic ()
{
Cbitmap BMP draw;
BMP draw. loadbitmap (idb_yesky_bitmap); // load the DDB bitmap Resource
Bitmap BMP Info;
BMP draw. getbitmap (& BMP info); // obtain the size of the Skynet logo bitmap.

CDC memdc; // defines a compatible DC
Cclientdc DC (this );
Memdc. createcompatibledc (& DC); // create a DC

Cbitmap * pbmpold = memdc. SelectObject (& BMP draw );
// Save the original DDB and input the polar network logo bitmap to the DC
DC. bitblt (0, 0, BMP info. bmwidth, BMP info. bmheight, & memdc, 0, 0, srcand );
Memdc. SelectObject (pbmpold); // select the original DDB
}

After you click this button, 3 results will be generated. The logo of Skynet is transparently added to the bitmap!


Figure 3 Add the Skynet logo to the DDB bitmap

The reason for this effect lies in the code line:

DC. bitblt (0, 0, BMP info. bmwidth, BMP info. bmheight, & memdc, 0, 0, srcand );

The srcand parameter is used (unlike srccopy in the previous code, it only means to copy the source bitmap to the destination bitmap). It means to perform and between the source and destination. We don't know how the editors of Skynet add logos to the images in the article. Maybe they use the image and logo batch processing software with the automatic and function. Indeed, we can use the principles in the routine to write a batch processing software that automatically adds a logo to a bunch of images at a time.

In addition to srcand and srccopy, dwdrop also has the following values:

Blackness: the output area is black.

Dstinvert: reverse the destination bitmap

Mergecopy: combines pattern with source bitmap with operations.

Mergepaint: uses or to combine the Reverse source bitmap with the target bitmap.

Notsrccopy: reverse the source bitmap and copy it to the destination.

NOTSRCERASE: uses or to merge source and destination bitmaps, and then reverse

Patcopy: copy the pattern to the destination bitmap.

Patinvert: use an exclusive or operation to combine the pattern with the destination bitmap.

Patpaint: use or to combine the source bitmap with the destination bitmap. Then, use or to combine the result with the destination bitmap.

Srcerase: First reverse the destination bitmap, and then combine it with the source bitmap

SRCINVERT: uses an exclusive or operation to merge the Source and Destination bitmaps.

Srcpaint: use or to combine the source bitmap and destination bitmap

Whiteness: the output area is white.

The rational use of these values will help us to produce image processing software with specific requirements.

From the above example, we can see that when using the cbitmap class in VC, bitmap must be placed into the resources of the project and loaded using the member function loadbitmap of the cbitmap class, then, the member function bitblt of the CDC class performs DC copy and other operations to achieve the display purpose. Cbitmap has the following limitations:

(1) bitmap needs to be placed into project resources, which will lead to a larger executable file of the project;

(2) Because bitmaps need to be put into engineering resources, and resources cannot contain bitmaps infinitely, applications cannot select other bitmaps automatically, and the bitmaps that can be used are very limited;

(3) cbitmap is only the encapsulation of the DDB bitmap operation API and cannot be independent from the platform.

DIB bitmap can solve the above problem. Its feature is to store image data independent of the platform in the. BMP bitmap file format. Next we will analyze it in detail.

4. DIB bitmap Programming

4.1 bitmap file format

First, analyze the format of the DIB bitmap file. Bitmap files are divided into four parts:

(1) bitmapfileheader

Bitmapfileheader is a struct with 14 bytes. It is defined:

Typedef struct tagbitmapfileheader
{
Word bftype; // file type, which must be 0x0000d, that is, string "BM"
DWORD bfsize; // file size, including 14 bytes of bitmapfileheader
Word bfreserved1; // Reserved Words
Word bfreserved2; // Reserved Words
DWORD bfoffbits; // The number of bytes from the file header to the actual bitmap data offset
} Bitmapfileheader;

(2) bitmapinfoheader

Bitmapinfoheader is also a struct with a length of 40 bytes and is defined:

Typedef struct tagbitmapinfoheader
{
DWORD bisize; // the length of this structure, 40
Long biwidth; // The image width, in pixels.
Long biheight; // The height of the image, in pixels.
Word biplanes; // It must be 1
Word bibitcount;
// Indicates the number of digits used for color, 1 (monochrome), 4 (16 colors), 8 (256 colors), 24 (true color)
DWORD bicompression;
// Specify whether the bitmap is compressed. Valid values include bi_rgb, bi_rle8, bi_rle4, and bi_bitfields. bi_rgb indicates that the bitmap is not compressed.
DWORD bisizeimage;
// The number of bytes occupied by the actual bitmap data, that is, bisizeimage = biwidth' × biheight. biwidth' is the result of biwidth adjusted according to the integer of 4.
Long bixpelspermeter; // horizontal resolution of the target device, in the unit of pixels per meter
Long biypelspermeter; // The vertical resolution of the target device. The unit is the number of pixels per meter.
DWORD biclrused; // The number of colors actually used by the bitmap. 0 indicates that the number of colors is 2 bibitcount.
DWORD biclrimportant; // number of important colors in the bitmap. 0 indicates that all colors are important.
} Bitmapinfoheader;

(3) palette

The palette is for bitmap that requires a palette, that is, a monochrome, 16-color, and 256-color bitmap. This item is not available for bitmaps that are not stored in the palette. The color palette is an array with a total of biclrused elements (if this value is 0, there are 2 bibitcount elements ). Each element in the array is an rgbquad struct with a length of 4 bytes and is defined:

Typedef struct tagrgbquad
{
Byte rgbblue; // blue weight
Byte rgbgreen; // green component
Byte rgbred; // red weight
Byte rgbreserved; // reserved value
} Rgbquad;

(4) Actual bitmap data imagedate

For bitmap that uses the color palette, the actual image data imagedate is the index value of the pixel color in the color palette. For a true color chart, the image data is the actual R, G, and B values:

A. monochrome bitmap: The color index value of a pixel can be expressed in 1 bit;

B .16 color bitmap: 4 bits can be used to represent the color index value of a pixel;

C. 256 color bitmap: one byte represents the color index value of one pixel;

D. True Color: Three bytes indicate the color R, G, and B of one pixel.

In addition, the number of bytes in each row of bitmap data must be an integral multiple of 4. If not, you need to complete it. It is strange that the data in a bitmap file is stored from bottom to top (rather than top to bottom) and from left to right.

4.2 Display of Bitmap
 
Visual c ++ MFC does not provide a special class for processing Dib bitmaps. Therefore, to facilitate the use of Bitmap files, we need to derive a CDIB class. The source code of the class is as follows:

(1) CDIB class declaration

// Dib. h: Class CDIB declaration header file
# Ifndef _ dib_h __
# DEFINE _ dib_h __
# Include <wingdi. h>
Class CDIB
{
Public:
CDIB ();
~ CDIB ();

Bool load (const char *);
Bool save (const char *);
Bool draw (CDC *, int Nx = 0, int ny = 0, int nwidth =-1, int nheight =-1, int mode = srccopy );
Bool setpalette (CDC *);

PRIVATE:
Cpalette m_palette;
Unsigned char * m_pdib, * m_pdibbits;
DWORD m_dwdibsize;
Bitmapinfoheader * m_pbih;
Rgbquad * m_ppalette;
Int m_npaletteentries;
};
# Endif

(2) Implementation of CDIB class

// Dib. cpp: Class CDIB implementation file
# Include "stdafx. H"
# Include "dib. H"

CDIB: CDIB ()
{
M_pdib = NULL;
}

CDIB ::~ CDIB ()
{
// Release the memory if the bitmap has been loaded
If (m_pdib! = NULL)
Delete [] m_pdib;
}

The following function is very important. Its function is to load bitmap, similar to the loadbitmap function of the cbitmap class:

Bool CDIB: load (const char * pszfilename)
{
Cfile CF;

// Open a bitmap file
If (! Cf. Open (pszfilename, cfile: moderead ))
Return (false );

// Obtain the bitmap file size and subtract the length of bitmapfileheader.
DWORD dwdibsize;
Dwdibsize = Cf. getlength ()-sizeof (bitmapfileheader );

// Allocate memory for DIB bitmap
Unsigned char * pdib;
Pdib = new unsigned char [dwdibsize];
If (pdib = NULL)
Return (false );

Bitmapfileheader BFH;

// Read bitmap file data
Try
{
// Whether the file format is correct or not
If (Cf. Read (& BFH, sizeof (bitmapfileheader ))! = Sizeof (bitmapfileheader) |
BFH. bftype! = 'Mb '| Cf. Read (pdib, dwdibsize )! = Dwdibsize)
{
Delete [] pdib;
Return (false );
}
}
Catch (cfileexception * E)
{
E-> Delete ();
Delete [] pdib;
Return (false );
}

// Delete the previously loaded bitmap
If (m_pdib! = NULL)
Delete m_pdib;

// Assign the temporary Dib Data Pointer and DiB size variable to the class member variable
M_pdib = pdib;
M_dwdibsize = dwdibsize;

// Assign bitmapinfoheader and palette pointer to the corresponding class member variable
M_pbih = (bitmapinfoheader *) m_pdib;
M_ppalette = (rgbquad *) & m_pdib [sizeof (bitmapinfoheader)];

// Calculate the actual color Quantity in the color palette
M_npaletteentries = 1 <m_pbih-> bibitcount;
If (m_pbih-> bibitcount> 8)
M_npaletteentries = 0;
Else if (m_pbih-> biclrused! = 0)
M_npaletteentries = m_pbih-> biclrused;

// Assign an image data pointer to the corresponding class member variable
M_pdibbits = & m_pdib [sizeof (bitmapinfoheader) + m_npaletteentries * sizeof (rgbquad)];

// Delete the previous palette
If (m_palette.getsafehandle ()! = NULL)
M_palette.deleteobject ();

// If a color palette exists in the bitmap, create logpalette and cpalette.
If (m_npaletteentries! = 0)
{
Logpalette * plogpal = (logpalette *) New char [sizeof (logpalette) + m_npaletteentries * sizeof (paletteentry)];

If (plogpal! = NULL)
{
Plogpal-> palversion = 0x300;
Plogpal-> palnumentries = m_npaletteentries;

For (INT I = 0; I <m_npaletteentries; I ++)
{
Plogpal-> palpalentry [I]. pered = m_ppalette [I]. rgbred;
Plogpal-> palpalentry [I]. pegreen = m_ppalette [I]. rgbgreen;
Plogpal-> palpalentry [I]. peblue = m_ppalette [I]. rgbblue;
}

// Create cpalette and release the logpalette memory
M_palette.createpalette (plogpal );
Delete [] plogpal;
}
}

Return (true );
}

// Function: Save the bitmap to the BMP file.
Bool CDIB: Save (const char * pszfilename)
{
If (m_pdib = NULL)
Return (false );

Cfile CF;
If (! Cf. Open (pszfilename, cfile: modecreate | cfile: modewrite ))
Return (false );

Try
{
Bitmapfileheader BFH;
Memset (& BFH, 0, sizeof (bitmapfileheader ));
BFH. bftype = 'mb ';
BFH. bfsize = sizeof (bitmapfileheader) + m_dwdibsize;
BFH. bfoffbits = sizeof (bitmapfileheader) +
Sizeof (bitmapinfoheader) + m_npaletteentries * sizeof (rgbquad );

Cf. Write (& BFH, sizeof (bitmapfileheader ));
Cf. Write (m_pdib, m_dwdibsize );
}
Catch (cfileexception * E)
{
E-> Delete ();
Return (false );
}
Return (true );
}

The following function is also very important. It is used to draw a bitmap in the CDC to which the PDC points. The starting coordinate is (NX, NY), and the width and height are nwidth and nheight, the last parameter is the grating mode:

Bool CDIB: Draw (CDC * PDC, int NX, int NY, int nwidth, int nheight, int Mode)
{
If (m_pdib = NULL)
Return (false );

// Obtain the bitmap width and height values
If (nwidth =-1)
Nwidth = m_pbih-> biwidth;
If (nheight =-1)
Nheight = m_pbih-> biheight;

// Draw a bitmap
Stretchdibits (PDC-> m_hdc, NX, NY, nwidth, nheight, 0, 0, m_pbih-> biwidth, m_pbih-> biheight, m_pdibbits, (bitmapinfo *) m_pbih, bi_rgb, mode );

Return (true );
}

// Function: Set the color palette.
Bool CDIB: setpalette (CDC * PDC)
{
If (m_pdib = NULL)
Return (false );

// Check whether there is a color palette handle. For bitmap with a color greater than 256, It is null.
If (m_palette.getsafehandle () = NULL)
Return (true );

// Select the color palette, implement it, and restore the old color palette.
Cpalette * poldpalette;
Poldpalette = PDC-> selectpalette (& m_palette, false );
PDC-> realizepalette ();
PDC-> selectpalette (poldpalette, false );

Return (true );
}

From the code of the entire CDIB class, we can see that the display of DIB bitmap must follow the steps below:

(1) read bitmap. In this class, pdib = new unsigned char [dwdibsize] is used to allocate memory for information in the bitmap. Another method is to call the API function createdibsection, for example:

M_hbitmap =: createdibsection (PDC-> getsafehdc (),
(Lpbitmapinfo) m_lpbmphdr, dib_rgb_colors,
(Lpvoid *) & m_lpdibits, null, 0 );

M_hbitmap is defined:

Hbitmap m_hbitmap;

(2) Calculate the size of the color palette Based on the read bitmap information and create a color palette;

(3) Call CDIB: setpalette (CDC * PDC) to set the color palette. The following functions are required: CDC: selectpalette and CDC: realizepalette;

(4) Call the CDIB: Draw (CDC * PDC, int NX, int NY, int nwidth, int nheight, int mode) function to draw a bitmap. In this function, the call to the stretchdibits API function is actually used to display bitmap. The stretchdibits function has the zoom function. Its last parameter is also the grating operation mode.

The following provides the function source code for opening and displaying DIB bitmap and adding the logo of Skynet to it. The "DIB bitmap" parent menu "open" sub-menu click event message processing function is (its function is to open the bitmap and display it ):

Void cbitmapexampledlg: onopendibpic ()
{
// The file dialog box is displayed to allow users to select a bitmap file.
Cfiledialog filedialog (true, "*. BMP", null, null, "bitmap file (*. BMP) | *. BMP; *. BMP | ");
If (idok = filedialog. domodal ())
{
// Load the bitmap and display it
CDIB Dib;
If (dib. Load (filedialog. getpathname ()))
{
Cclientdc DC (this );
DiB. setpalette (& DC );
DiB. Draw (& DC );
}
}
}

The "DIB bitmap" parent menu "tag" sub-menu click event message processing function is (its function is to add the Skynet logo to the bitmap ):

Void cbitmapexampledlg: onmarkdibpic ()
{
// The pop-up file dialog box allows the user to choose to mark the logo
Cfiledialog filedialog (true, "*. BMP", null, null, "mark a bitmap file (*. BMP) | *. BMP; *. BMP | ");
If (idok = filedialog. domodal ())
{
// Load the marked logo bitmap and phase it with the target bitmap
CDIB Dib;
If (dib. Load (filedialog. getpathname ()))
{
Cclientdc DC (this );
DiB. setpalette (& DC );
DiB. Draw (& DC, 0, 0,-1,-1, srcand );
}
}
}

Figure 4 shows the effect of DIB bitmap after loading the Skynet logo, which is better than the DDB bitmap after adding the Skynet logo in figure 3. Figure 4 shows the mutual result of true color bitmaps, while the color of the image in Figure 3 is reduced.


Figure 4 Add the Skynet logo to the DIB bitmap

  5. Conclusion

This article introduces the concept of Bitmap and palette, and explains the differences between DDB bitmap and DIB bitmap. On this basis, this article describes how to operate DDB bitmap and DIB bitmap. DDB Bitmap Processing is relatively simple. For Dib bitmaps, we need to define a new class CDIB that does not exist in MFC, which shields bitmap information from reading and creating technical details of the palette, applications can be conveniently used.

All the programs in this article have been debugged on Visual C ++ 6.0 and Windows XP platforms.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.