DIB Orientation

The most frustrating thing about working with DIBs is that DIBs are usually oriented with the bottommost scanline stored first in memory, the exact opposite of the usual device-dependent bitmap orientation. This standard type of Windows DIB is called a bottom-up DIB.

WinG hides the orientation of DIBs from an application unless the application wants to know. Drawing into a WinGDC using GDI functions and blting the WinGDC to the display using either of the WinG DIB copy commands (WinGStretchBlt or WinGBitBlt) results in an image that is almost identical to one created using GDI to draw directly onto a display DC. See the Using GDI With WinGDCs article for more information.

If you don't plan on writing custom drawing routines and will not be using existing Windows 3.1 DIB-to-screen functions (such as StretchDIBits or SetDIBitsToDevice), you can skip the rest of this section

If you do plan on writing custom drawing routines or just want to know how they work, this section will begin to alleviate the confusion. The Microsoft Technical Articles "DIBs and Their Use" by Ron Gery and "Animation in Windows" by Herman Rodent will flesh out the ideas presented here, provide helpful advice, and describe DIBs in depth. The DOGGIE sample in the WinG SDK and the TRIQ sample from Microsoft's GDI Technical Notes show how to draw into a memory DIB. TRIQ is listed in the section Further Reading.

Confusion with bottom-up DIBs inevitably stems from the fact that the bottommost scanline is stored first in memory, giving a coordinate space where (0, 0) is the lower left corner of the image. Windows uses (0, 0) as the upper left corner of the display and of device dependent bitmaps, meaning that the Y coordinates of bottom-up DIBs are inverted. In the diagram below, the smiling face casts its gaze towards the DIB origin, but when translated to the display with WinGStretchBlt or WinGBitBlt, it looks away from the display origin.

Bottom-Up DIBs are flipped when copied to the display

WinGStretchBlt, WinGBitBlt, StretchDIBits, and SetDIBitsToDevice invert the bottom-up DIB as they draw it to the screen.

For an 8-bit bottom-up DIB, the address in memory from which the screen pixel (X, Y) is retrieved can be found with these equations:

// Calculate actual bits used per scan line

DibWidthBits = (UINT)lpBmiHeader->biWidth *

(UINT)lpBmiHeader->biBitCount);

// And align it to a 32 bit boundary

DibWidthBytes = ((DibWidthBits + 31) & (~31)) / 8;

pPixelXY = DibAddr + (DibHeight - 1 - Y) * DibWidthBytes + X

where DibAddr is the base address of the DIB, DibHeight is the height of the DIB, lpBmiHeader is a pointer to a BITMAPINFOHEADER describing the DIB, and DibWidthBytes is the DWORD-aligned offset of bytes in memory from any X in one scanline to any X in the next scanline. In DIBs, every scanline begins at a DWORD-aligned memory address, with extra bytes added as needed at the end of the previous scanline.

Top-Down DIBs

Another kind of DIB, called a top-down DIB, is stored with the same orientation as most device-dependent bitmaps: the first scanline in memory is the top of the image. Top-down DIBs are identified by a negative biHeight entry in their BITMAPINFOHEADER structures.

Sometimes, WinG can greatly improve the speed of a DIB-to-screen copy by using a top-down DIB because it can avoid inverting the DIB to a device-dependent format. When this is the case, WinGRecommendDIBFormat will return a negative value in the biHeight field of the passed BITMAPINFOHEADER structure.

If you are writing custom DIB drawing routines, you will have to handle top-down DIBs for best performance because there is a good chance that WinG will recommend them with WinGRecommendDibFormat.

WinGStretchBlt and WinGBitBlt recognize top-down DIBs and handle them correctly, but Windows 3.1 functions such as StretchDIBits and SetDIBitsToDevice will not work properly with top-down DIBs unless you intentionally mirror the image.

Top-Down DIBs are copied directly to the display

For an 8-bit top-down DIB, the memory address of the pixel (X, Y) can be found with this equation:

PixelAddr = DibAddr + Y * DibWidthBytes + X

where DibAddr is the base address of the DIB and DibWidthBytes is the DWORD-aligned offset of bytes in memory from the beginning of one scanline to the next.

The PALANIM sample application (in the SAMPLES\PALANIM subdirectory of the WinG development kit) includes a routine to draw horizontal lines into a DIB. To do this, it determines the orientation of the target DIB and performs its calculations accordingly.

The DOGGIE sample application (in the SAMPLES\DOGGIE subdirectory of the WinG development kit) includes a routine to copy one DIB into another with a transparent color. The assembly function that does this also behaves well with both DIB orientations.