| Herd Software Development
|=
DaVinci Graphics Library
|==
DaVinci Documentation Home Search Order


An introduction to DIBs (Device Independent Bitmaps)

Design

DIB, or Device Independent Bitmap, is the used to describe a bitmap in a format that does not store its contents in terms which relate to a specific device's output capabilities (color depth and pixels-per-inch). While you may occasionally see .DIB files stored on disk, the term is nearly always used to refer to a DIB in a memory block. This memory block is structured in accordance with Windows API specifications for DIBs, and the actual DIB consists of a header, a color palette, and pixel data. In order to be truly called a DIB, this data must all be stored in the same block of memory. In practice, you will often deal with the palette, header, and image data as though they were three separate blocks of memory.

When programming with the API, this common block of memory is assigned using GlobalAlloc, which returns a handle to the DIB data usually referred to as type HDIB. It is from this HDIB that you will normally extract and work with the header, color table and pixel data.

Format of the DIB data block

A complete description of the data format can be found in the Windows API documentation underBITMAPINFOHEADER.

Bitmaps are normally stored on disk as .BMP files and in application resources as .DIB. In the case of .BMP files, a BITMAPFILEHEADER structure should be used when saving the image to disk. Note that the "device independent" designation of DIBs simply refers to the display resolution of the output device. It does not imply that the DIB data format doesn't account for the device's color depth.

Available color depths for DIBs are defined by Windows versions 3.0 to date using 1,4,8 or 24 bits of color depth. 16 and 32 bit color depth are both defined for use with Windows NT and Windows 95, but in practice these formats are seldom used. The 16 bit color depth is only suppored by DaVinci in a limited manner; 32 bit color is not supported.

If you're interested in learning more about DIBs and the Windows API, the "Self-Study Guide for DIBs", published by Microsoft, is available for download both from CompuServe and from the Microsoft's FTP site. The file size approximately 1MB, but unfortunately we do not know the archive name.

Unlike a Device Dependent Bitmap, a DIB contains all of the color information necessary to the display bitmap (color palette, metric resolution, see below). DIBs can be made available in 2, 16, 256 or 16,777,216 colors, and the color depth of a DIB in memory need not depend on the capabilities of the current graphics driver or graphics card. DIBs in memory are what allow graphics editors to let you process and filter TrueColor images even with your current display driver set to show only 256 colors.

Bitmapped graphics imported by DaVinci are universally converted to DIBs for use by the application. Each DIB is represented by a global memory handle. In most cases, this handle is created by a call to GlobalAlloc. Some development platforms and extensions allow you to specify the DIB handle as a property of a component or class. Although the DIB's handle is requested from Windows as an HGLOBAL, DaVinci's documentation refers to it as HDIB for documentation purposes. This shouldn't cause any confusion when developing, since to most development platforms, a handle is a handle is a handle, regardless of where it comes from.

In cases where all you need is to convert a DIB to a DDB, you'll find support functions for this in Leonardo. Note that a DDB created for a screen DC cannot be transfered to a printer with a call to BitBlt for it is device dependend.

Before you can access data in the DIB's global memory block, you will normally need to call the GlobalLock API function. This will return a pointer to the BITMAPINFOHEADER, the first structure in that block.

The principal structure of a DIB is defined by the following substructures:

In the case of DIBs in memory DIBs in a BMP file OS/2 1.x format Windows 95/NT extension
(no additional header) BITMAPFILEHEADER (often not used...many applications will save BMP files without the BITMAPFILEHEADER, which essentially makes them .DIBs, not .BMPs) BITMAPFILEHEADER BITMAPFILEHEADER
BITMAPINFOHEADER BITMAPINFOHEADER BITMAPCOREHEADER BITMAPINFOHEADER
RGBQUADs representing the image's color table (palette) RGBQUADs representing the image's color table (palette) RGBTRIPLEs representing the image's color table (palette). The RGBTRIPLE type is not normally used by Windows applications except as a convenience for supporting OS/2-created images. several RGBQUAD
Bitmapped image data Bitmapped image data Bitmapped image data Bitmap data

The number of the RGBQUAD structures is defined by the biClrUsed member of the BITMAPINFOHEADER structure. If this member is zero, biBitCount determines the number of the RGBQUAD structures. Normally, a biClrUsed value of 0 indicates a TrueColor image, but this isn't always the case, as this chart illustrates:

biBitCount Number of RGBQUAD structures

1 2

4 16

8 256

16* 0*

24 0

32* 0*

The number of RGBQUAD structures can easily be computed using this statement, in which bmi is the DIB's BITMAPINFOHEADER:

(WORD) (1 << bmi.biBitCount.).

* biBitCount values of 16 and 32 were neither defined for, nor intended for use with, Windows 3.x. They were introduced with Video for Windows and Windows NT 3.5/Windows 95. DaVinci and Leonardo support DIBs with biBitCount=16, but only in a limited way. Use the TransformDIB function to convert 16 bit DIBs to 24 bit TrueColor for easier management and higher compatibility with other applications.

Delphi and PASCAL programmers should note that Borland prefixes a "T" to most Windows structures (e.g. LOGFONT to Delphi becomes "TLOGFONT" when declared in a Delphi unit; BITMAPINFOHEADER becomes "TBITMAPINFOHEADER", etc.). Keep in mind when hunting for structure documentation in API help that these helpfiles were authored primarily for C programmers. The API helpfiles do not recognize the type names used by PASCAL when you enter them as search terms in helpfiles. If you can't find a specific structure using the type as it is defined by Delphi or Turbo Pascal, remove the "T" or "P" (some types are recast as pointers to structures in the Windows API declarations units) and re-enter the search term.

Pascal/Delphi notation

C name PASCAL name

BITMAPINFOHEADER TBitmapInfoHeader

LPBITMAPINFOHEADER PBitmapInfoHeader

RGBQUAD TRgbQuad

LPRGBQUAD PRgbQuad

The actual bitmap data in the DIB begins at the tail end of the RGBQUAD structures. While most Windows functions refer vertical dimensions from the top down, using the top as 0, bitmap data is stored in a DIB with the lowest scan line at the start of the bitmapped data block. Between the end of each line and the beginning of the next, you'll find some filler bytes which are used to align the start of the line to an address divisible by 4. Here's how to calculate the number of bytes in a scanline, which may very well be different from the number of pixels of width in the image:
WidthBytes = (bih.biWidth * bih.biBitCount + 31) / 32 * 4;

Data bits

1-Bit format (mono chrome)

Monochrome bitmaps are essentially two colors (usually, but not always, black and white) and will return biBitCount == 1. They store on disk to such small sizes because each byte of the bitmapped data block can represent eight pixels. The color palette for the image must contain two entries, but they don't have to be black and white. (However, be aware that most applications which see a biBitCount == 1 when evaluating the header will skip the palette completely and assume that the image is black and white.)

Each bit in the bitmap array represents a pixel. If the bit is clear, the pixel is displayed with the color of the first entry in the bmciColors table. If the bit is set, the pixel has the color of the second entry in the table.

In order to address a specific bit within a line of pixels in a monochrome DIB, adapt the following example to your application:
UINT	XInLine;
HPBYTE	hpStartOfLine;

HPBYTE	hpPixelInLine = hpStartOfLine + XInLine / 8;
BYTE	PixelInByte   = 7 - (XInLine % 8);
BOOL	IsPixelSet;

IsPixelSet = (*hpPixelInLine >> PixelInByte) & 1;

// Next Pixel:
if (PixelInByte)
	PixelInByte--;
else 
{
	hpPixelInLine++;
	PixelInByte = 7;
}
4 bit format (VGA or 16 color)

In this case each byte of image data represents two pixels (biBitCount == 4). Bits represent the color of the pixel in descending order; i.e. the first pixel is stored in bits 7-4 of the byte, the second pixel in bits 3-0. The four bits specify the number of the color palette entry (color 0 through color 15).

8 bit format (256 colors)

This format offers a maximum of 256 colors, and the bmciColors member contains 256 entries. In this case, each byte in the image's bitmap data array represents a single pixel. The value of that byte is the number of the color palette entry to be used (from 0 to 255).

24 bit format (TrueColor)

These bitmaps can have a maximum of 2^24 colors (biBitCount == 24). The color palette array in a TrueColor image is actually empty. Each three-byte sequence in the bitmap data array represents the relative intensities of the three primary hues of a pixel. The hues are described as values ranging from 0 to 255 and are stored in the three bytes in the order Blue, Green and Red. This is an important distinction, because most references to colors in Windows use the opposite order: Red/Green/Blue, so think "BGR" when working with TrueColor images instead of "RGB". A color palette can be specified to accelerate the drawing process for Windows, in which case biClrUsed will not be 0. But as you can see, it's not needed, since the pixel data itself contains the color information.

32 bit format

Like TrueColor, 32 bit images have a maximum of 2^24 colors (biBitCount == 24). Once again, the color palette array is empty. And once again, each three-byte sequence in the bitmap array represents the relative intensities of the blue, green and red hues, and there is one unused byte. A color palette can be specified in addition in order to accelerate the character process for Windows, biClrUsed is not 0 in this case. (See also: 32 bit DIB processing made easy)

Retrieving structures in a DIB data block

Before you can perform meaningful work on DIB data, applications need to compute pointers to the various structures stored in the DIB as follows:
LPBITMAPINFOHEADER lpbmi = (LPBITMAPINFOHEADER) GlobalLock( hDIB );
LPRGBQUAD            lprgbquad = (LPRGBQUAD) ((LPSTR) lpbmi + lpbmi->biSize);
LPSTR                lpBitmapBits = ((LPSTR) lprgbquad)+DIBPaletteSize(lpbmi);
int                  WidthOfLineInBytes = (lpbmi->biWidth * lpbmi->biBitCount + 31) / 32 * 4;
LPSTR                lpStartOfLine = lpBitmapBits + y * WidthOfLineInBytes,
                     lpStartOfPixel = lpStartOfLine + x * lpbmi->biBitCount / 8;

HUGE pointer addressing in Delphi 1

Since DIB memory areas often contain a great deal more than 64 KB of data, you'll need to use "huge" pointers to address the DIB data. Even though the 16 bit Windows API provides functions for addressing large blocks of memory, Delphi 1.0 does not support huge pointers and in fact doesn't even include API functions such as hread in its Winprocs unit. (Don't try to fix this by manually adding hread or other undeclared API functions to WINPROCS.PAS, though...the System unit isn't set up to handle large blocks of memory anyway.)

So before you can work with a DIB at the API level in Delphi 1, you need some way to get Delphi to deal with this much data at once. Abstracted Delphi components often use TStreams, but the use of TStreams isn't strictly necessary, as you'll discover in the sample GETDIB.PAS and GETTEST.PAS units. There you'll find a useful means of "forcing" Delphi 1 to cope with larger blocks of data than its internals seem to indicate that it can handle.

History of the DIB specifications

The original DIB data format specification introduced with Windows 3.0 was pretty basic, and has since been extended on several occasions by Microsoft. Here's a brief history of revisions to the original specification. Note that not all current applications support these new extensions, although some of the extensions (e.g. RLE decompression) are supported internally by Windows itself.

Windows NT 3.1 and video For Windows 1.1 below Windows 3.1
Windows NT 4.0 and Windows 95

See also:

Þ 32 bit DIB processing made easy