The information in this article applies to:
SUMMARYThe following is the text of the article "DIBs and Their Uses". This article is available in Windows Help file format in the Microsoft Software Library in addition to the text presented below. MORE INFORMATIONThe following files are available for download from the Microsoft
Download Center. Click the file names below to download the files: http://www.microsoft.com/downloads/search.aspand then click How to use the Microsoft Download Center. This article discusses the DIB (device-independent bitmap) concept from definition and structure to the API that uses it. Included is a small sample application that illustrates some of the most common methods of using DIBs to display and manipulate digital images. Functions discussed are GetDIBits(), SetDIBits(), CreateDIBitmap(), SetDIBitsToDevice(), StretchDIBits(), and CreateDIBPatternBrush(). This article does not discuss using palettes with DIBs. OVERVIEWA device-independent bitmap (DIB) is a format used to define device- independent bitmaps in various color resolutions. The main purpose of DIBs is to allow bitmaps to be moved from one device to another (hence, the device-independent part of the name). A DIB is an external format, in contrast to a device-dependent bitmap, which appears in the system as a bitmap object (created by an application using CreateBitmap(), CreateCompatibleBitmap(), CreateBitmapIndirect(), or CreateDIBitmap()). A DIB is normally transported in metafiles (usually using the StretchDIBits() function), BMP files, and the Clipboard (CF_DIB data format).A DIB consists of two parts: the bits themselves and a header that describes the format of the bits. The header contains the color format, a color table, and the size of the bitmap. The current DIB format supports four color resolutions: 1 bit, 4 bit, 8 bit, and 24 bit. In 1-bit, 4-bit, and 8-bit DIBs, the pixels are defined by indexes (of the appropriate bit resolution) into the color table; 24-bit pixels are described as 24-bit values, 1 byte each for red, green, and blue. The DIB functions are:
DEVICE INDEPENDENCE - WHAT'S IT GOOD FOR?Transferring color bitmaps from one device to another was not possible in versions of the Microsoft Windows graphical environment earlier than 3.0. With DIBs, each device displays the image to the extent of its color resolution. An application can store an image in the DIB format and then display it, regardless of the output device; an application need no longer create a version of each image for each type of device.This image transfer ability can be used to print halftone images. For example, the StretchDIBits() function can pass a DIB directly to an intelligent printer driver. Given the full color information of the image instead of simply a monochrome version (the traditional method), the driver can use halftones to print a realistic picture. Because the DIB format is publicly defined, an application can manipulate it on the fly. In fact, an application can build an image without any interaction with Windows. If Windows lacks a drawing primitive, the application can simulate it directly into the DIB instead of using the existing graphics device interface (GDI) primitives. Unfortunately, under Windows versions 3.0 and 3.1, GDI cannot perform output operations directly to a DIB. BMP FILE FORMATSThe file extension of a Windows DIB file is BMP. The file consists of a BITMAPFILEHEADER structure followed by the DIB itself. Unfortunately, because the BITMAPFILEHEADER structure is never actually passed to the API, not every application that generates BMP files fills out the data structure carefully. To add to this confusion, the "proper" definition of the structure is at odds with the documentation. Properly, the data structure contains the following fields:
The DIB header immediately follows the BITMAPFILEHEADER structure.
For a code sample that reads a BMP file, see the sample program. The DIB HeaderThe header actually consists of two adjoining parts: the header proper and the color table. Both are combined in the BITMAPINFO structure, which is what all DIB APIs expect.Windows version 3.0 supports two varieties of headers: BITMAPINFOHEADER and BITMAPCOREHEADER. If at all possible, applications should use only BITMAPINFOHEADERs. The BITMAPCOREHEADER definition is based on the bitmap definition from Presentation Manager version 1.1 and is supported for compatibility. During a DIB setting operation, most fields are already filled in by whoever generated the DIB. Doing a GetDIBits() call, however, provides more control. The way the header is filled in for this operation defines the resulting DIB, particularly its color resolution. BITMAPINFOHEADER contains the following fields:
The color table immediately follows the header information. No color table
is defined for 24-bit DIBs. The table consists of an array of RGBQUAD data
structures. (The table for the BITMAPCOREINFO format is built with the
RGBTRIPLE data structure.) Red, green, and blue bytes are in reverse order (red swaps position with blue) from the Windows convention. This is another leftover from Presentation Manager compatibility.
The size of the color table depends on the biBitCount value (and can be overwritten using the biClrUsed field; see above):
Most DIBs floating around currently have biClrUsed set to 0, but if any
full-fledged DIB bashing is planned, it is a good idea to set it properly.
If biClrUsed is nonzero, a color table with 24-bit DIBs is possible. GDI
does not use this color table, but the application can use it to determine
the important colors used in the DIB.
All DIB functions include a wUsage parameter, which can affect the definition of the color table. This article avoids using palettes with DIBs, and thereby assumes that wUsage is always set to DIB_RGB_COLORS and that the color table is therefore always composed of RGB values. When DIB_PAL_COLORS is used, the color table consists of WORD values that are indexes into the currently selected logical palette. (This topic is discussed in detail in the "Using DIBs with Palettes" article.) Bit FormatsThe header defines the format of the bits, but all formats share the following rules:
USING THE DIB APIGetDIBits() and SetDIBits()These two functions are used to convert device-independent bitmaps into device-dependent bitmaps and vice versa. SetDIBits() converts a DIB to a device-dependent bitmap, and GetDIBits() generates a DIB from a device-dependent bitmap.The device driver referenced by the hDC passed into both calls performs the actual translation. Some device drivers may not have this functionality (for example, a Windows version 2.0 driver or a primitive Windows version 3.0 driver). In this case, GDI simulates the translation, but only in monochrome -- color information is converted to black and white. For the most part, however, this is not a concern. All self-respecting display drivers support this functionality, and only a few printer drivers do not provide the translation, usually monochrome drivers for which the GDI simulations suffice. GetDeviceCaps(hDC, RASTERCAPS) returns a WORD value with flags set indicating which DIB functions the driver supports. RC_DI_BITMAP indicates support of GetDIBits() and SetDIBits(), RC_DIBTODEV indicates support of SetDIBitsToDevice(), and RC_STRETCHDIB indicates support of StretchDIBits(). Any function not supported can be simulated, although the simulations are often not as useful as the real thing (mainly because color information is lost). A device may be unable to support the full functionality even if a bit is set. For example, a device could support StretchDIBits but only for integral stretches. Unfortunately, an application has no way to determine the completeness of the implementation. In these cases, GDI simulates the function. The parameters are the same for both GetDIBits() and SetDIBits():
Using SetDIBits() is reasonably straightforward. A DIB is taken from
somewhere (for example, from the Clipboard or from a disk file) and is
converted to a bitmap object, which can then be selected into a DC and
blted to the screen for display. This is the simplest way to display a
DIB.
NOTE: For many printers that can do halftones, this method is not preferred; StretchDIBits (discussed in the following) is far more useful. The following is a simple display of a DIB to a DC (with no error handling):
Using GetDIBits() is more complex because the application can choose
what kind of DIB to generate. The size of the source bitmap regulates
the DIB's dimensions (a piece can be extracted by blting into a
smaller bitmap), but the application's need can dictate the color
resolution.
For GetDIBits() to work properly, the application needs to set the following fields in the header:
Also, the space allocated for the color table must be sufficient to
hold a full-size table:
The space allocated for lpBits also needs to be large enough to hold
nNumScans of data. The call fills in the following fields of the
structure:
The application's goals for the DIB determine what color resolution to choose. The usual approach is to generate a DIB that preserves the color information of the source device-dependent bitmap. Choosing a lesser resolution results in a loss of color information, which is usually undesirable. Always using 24-bit resolution is unnecessary, however, because doing so adds no more color resolution if the source has 8-bit or less resolution.
The bitmap's resolution calculation must take into account that some
device-dependent bitmaps are planar (notably EGA and VGA). DIBs, on
the other hand, are always "packed pixel," with only 1 plane per pixel
(biPlanes = 1).
The nStartScan and nNumScans parameters (a residue of Presentation Manager compatibility) are designed to be used for banding. If not enough memory is available to load the entire DIB into memory in one piece, lpBits can be made to point to only a portion of the bits. Consider the following example:
The Set code takes the given band, translates it, and puts the
translated band in its proper location, accounting at all times for
the upside-down nature of DIBs. Notice how biHeight does not change at
any time because the band is placed in the bitmap based on the height
of the full bitmap. nStart is based on the height of the full image
(defined by biHeight).
CreateDIBitmap()The following code demonstrates calling CreateDIBitmap() with the usual case:
This is equivalent to:
GDI's implementation skips the SetDIBits() part if the third parameter is not set with the CBM_INIT flag. This function makes for nice
shortcut coding of the conversion from DIB to device-dependent bitmap.
SetDIBitsToDevice()SetDIBitsToDevice() allows an application to set a DIB directly to a device surface. Because this function is a holdout from early development, its interface is not as polished as it could be. StretchDIBits() is a far more powerful function than SetDIBitsToDevice(). StretchDIBits() does all that SetDIBitsToDevice() does and has a nicer interface. SetDIBitsToDevice() is limited in the way it handles metafiles because it does not scale, and banding with the nStartScan and nNumScans parameters is nontrivial at best. StretchDIBits() does not allow the banding.The following code performs the SetDIBitsToDevice() functionality on the full bitmap (no banding) using StretchDIBits:
Assuming that nStartScan is set to 0 and that nNumScans is set to
lpInfo->biHeight (that is, no banding), the function is basically a
BitBlt with SRCCOPY as the ROP and with a DIB as the source. SrcX and
SrcY are in the DIB's space and are therefore upside down in relation
to the DC (Y = 0 is at the bottom of the image).
Dealing with the upside-down DIB is tricky when doing a partial setting. For example, if an application wants to get the bottom third of a DIB that is w by h pixels to the device at (x, y), the call would resemble the following:
A device-dependent bitmap would have a SrcY of 2h/3 for the bottom
third, but with the upside-down system of the DIB, a SrcY of h/3
points to the proper place relative to Windows coordinates.
StretchDIBits()This function is the do-all darling for displaying a DIB on the surface of a device. It is especially nice for metafiling and for printing, for which the ability to stretch is important.The one critical hole in the current implementation of StretchDIBits() is that StretchDIBits() is supported by printer drivers and not by many display drivers. Therefore, using this function repeatedly to stretch a DIB to the screen is significantly slower than using SetDIBits (to get a device-dependent bitmap) followed by repeated StretchBlt() calls. The implementation of this function in GDI is very straightforward. If the device driver can handle the call itself, it does. If not, and the call is 1-to-1 and the device supports SetDIBitsToDevice(), the call is converted to a SetDIBitsToDevice() call to the driver. (This works only with SRCCOPY as the ROP.) If neither of these methods is possible, CreateDIBitmap() is used to make a device-dependent version of the bitmap, and StretchBlt is called to do the actual work. The parameters for StretchDIBits() are basically the same as for StretchBlt() (with the source hDC replaced by lpBits and lpInfo). This function does not have the nStartScan and the nNumScans parameters of the other DIB functions, so lpBits always points to the first scan of the DIB. When using this function for anything other than full bitmap stretches, remember that all of the source coordinates (the ones relating to the DIB) are in an upside-down system. The function will appropriately flip the image, but the source rectangle is defined with Y=0 at the bottom and extents going up. Fortunately, the x-coordinates use the same conventions as Windows. Printer drivers that do support this functionality (for example, PSCRIPT and HPPCL) usually use a halftone algorithm to output good color images. Therefore, maintaining DIBs at the highest meaningful color resolution possible (usually 8 bit) is desirable even if the output device is monochrome, because the color information is still useful for good output. Unfortunately, most printer drivers do not support any ROP other than SRCCOPY. CreateDIBPatternBrush()This function allows an application to create a pattern brush by specifying a DIB instead of a device-dependent bitmap, as used in the CreatePatternBrush() function. A brush created using this function is used similar to any other brush. The DIB is turned into a device-dependent bitmap at SelectObject() time for use by the device. This brush resembles a standard pattern brush to the device.DIBS IN THE CLIPBOARDTwo basic mechanisms for placing DIBs in the Clipboard are using the CF_DIB data format or placing the DIB into a metafile and using the CF_METAFILEPICT data format.The CF_DIB format uses a packed DIB, in which the bits follow immediately after the header and the color table. When reading or creating a packed DIB, an application must properly calculate the size of the color table to ensure that the bits are in the proper place. Because all DIB functions expect the DIB as two pointers, one to the header and one to the bits, the bits pointer must be calculated before use. (For color table size computations, see the code sample in the color table description above.) The simplest way to place a DIB into a metafile is to use StretchDIBits():
This approach generates a metafile that when played back displays the
DIB to the destination. This method also scales the image to fit the
current mapping scheme if needed. Using metafiles for transfer enables
even applications that are not DIB-aware to paste the contents of the
Clipboard without losing the DIB information.
RLE FORMATSWhen the biCompression field in a DIB's header is set to either BI_RLE4 (for biBitCount = 4) or BI_RLE8 (for biBitCount = 8), the image has been run-length encoded. A description of the encoding schemes can be found in the "Microsoft Windows Software Development Kit Reference Volume 2," in the "BITMAPINFOHEADER" section of the "Data types and Structures" chapter. The basic scheme involves compressing multiple, horizontally adjacent, identical pixels into a run encoding. For example, 10 pixels of color index 17 are encoded as a run of length 10 and of index 17. Codes for end-of-scan and for delta moves are also provided, in which an X and a Y offset are provided for the next pixel.This type of encoding usually compresses the bitmap and is also useful for creating sprite-type animations, in which only a small part of an image changes in each frame. The animation capabilities are accomplished by using delta codes to limit the number of pixels actually being set. Pixels skipped by a delta move are left untouched. The main limitations of RLE DIBs are that an application can neither easily determine the size of the bitmap in bytes nor point to a certain scanline without decoding the bitmap from the first scan. The biSizeImage field is useful in solving the first problem. Decoding, encoding, and generally manipulating the RLE format is slower and more complicated than the noncompressed (BI_RGB) format. Some applications -- for example, Paintbrush -- refuse to read RLE DIBs. Although all APIs accept them, RLE DIBs will probably not become a universally supported format. Also, because of the relative rarity of these formats, some device drivers might not have fully tested support for the encoding and decoding processes. To generate an RLE DIB, GetDIBits() is called with biCompression set to the desired type of encoding. The amount of memory needed to store the bits is not easily computed. If GetDIBits() is called with lpBits set to NULL, the amount of memory needed for the bits is returned in biSizeImage. A subsequent call with lpBits pointing to a properly sized block of memory returns an encoded bitmap. Translating an RLE DIB into a device-dependent form requires no special processing. Any of the Set functions can be used normally with a header containing the proper biSizeImage and biCompression values to match the bits. SHORTCOMINGS OF DIBSProbably the biggest limitation of DIBs is that they are slower than device-dependent bitmaps. Translating DIBs into a device-dependent form before they can actually be displayed requires extra processing, resulting in additional overhead. In an ideal world, a 1-to-1 StretchDIBits() would be as fast as a BitBlt(). This speed would allow an application to operate effectively in the realm of the logical bitmap, with full color and full access to each and every pixel, regardless of the physical device's limitations.DIBs are based in a coordinate system that is upside down relative to Windows, making coding a bit frustrating and not intuitive. Always remembering this quirkiness should help limit the number of iterations needed to get bitmaps properly lined up. You can get full color using 24-bit DIBs, but they are very slow to decode, read, and write. This is especially true on 8-bit palette devices, in which translation literally can take minutes. Also, the sheer size of 24-bit DIBs makes them a bit unwieldy for general use. DIB-RELATED PROBLEMS IN WINDOWS VERSION 3.0Metafile recording of StretchDIBits() calls that use BITMAPCOREHEADER causes a UAE. Convert all headers to the BITMAPINFO style to avoid this problem. This workaround is recommended for general DIB processing.The SetDIBits() simulation code for greater than 64K monochrome DIBs causes crashes or erroneous printouts when using a SetDIBits(), a SetDIBitsToDevice(), or a StretchDIBits() to a driver that does not support SetDIBits(). Copyright 1992 by Microsoft Corporation. All rights reserved. Additional query words: 0 softlib DIBS2.EXE
Keywords : kbfile kbsample kb16bitonly kbWinOS310 kbDSupport kbWinOS300 GdiBmp |
Last Reviewed: December 3, 1999 © 2000 Microsoft Corporation. All rights reserved. Terms of Use. |