Converting DDB to DIB
Posted
by Zafir Anjum
on August 5th, 1998
One situation where we need to convert a DDB to a DIB is when we want to save the bitmap to a file. The BMP files are infact just composed of a short header followed by information in a DIB.
The steps involved in creating the DIB are:
- Initialize a BITMAPINFOHEADER data structure. We use information in the bitmap to determine the widht, height and the bit count. The compression field is set based on the argument passed into the function. It's best to use the BI_RGB compression for greater portability and faster rendering.
- Select and realize the logical palette associated with the bitmap. This is passed in as the last argument to the function. If a palette is not provided use the default palette.
- Determine the number of bytes required for the bitmap bits. First allocate enough memory for BITMAPINFOHEADER and the color table and then call GetDIBits() to size. Supplying a NULL for the lpBits parameter instructs GetDIBits() to biSizeImage field in the bitmapinfoheader. Sometimes, this does not work (depending on the device driver) in which case we make our own estimate. We can compute this since we already know the width, height, the number of bits per pixel and the fact that each row of pixels will occupy a multiple of 4 bytes (32 bits).
- Given the final size of the bitmap bits, reallocate the memory block to hold the bitmapinfoheader, the color table and the bitmap bits.
- Finally call the GetDIBits() again to get the bitmap bits.
// DDBToDIB - Creates a DIB from a DDB
// bitmap - Device dependent bitmap
// dwCompression - Type of compression - see BITMAPINFOHEADER
// pPal - Logical palette
HANDLE DDBToDIB( CBitmap& bitmap, DWORD dwCompression, CPalette* pPal )
{
BITMAP bm;
BITMAPINFOHEADER bi;
LPBITMAPINFOHEADER lpbi;
DWORD dwLen;
HANDLE hDIB;
HANDLE handle;
HDC hDC;
HPALETTE hPal;
ASSERT( bitmap.GetSafeHandle() );
// The function has no arg for bitfields
if( dwCompression == BI_BITFIELDS )
return NULL;
// If a palette has not been supplied use defaul palette
hPal = (HPALETTE) pPal->GetSafeHandle();
if (hPal==NULL)
hPal = (HPALETTE) GetStockObject(DEFAULT_PALETTE);
// Get bitmap information
bitmap.GetObject(sizeof(bm),(LPSTR)&bm);
// Initialize the bitmapinfoheader
bi.biSize = sizeof(BITMAPINFOHEADER);
bi.biWidth = bm.bmWidth;
bi.biHeight = bm.bmHeight;
bi.biPlanes = 1;
bi.biBitCount = bm.bmPlanes * bm.bmBitsPixel;
bi.biCompression = dwCompression;
bi.biSizeImage = 0;
bi.biXPelsPerMeter = 0;
bi.biYPelsPerMeter = 0;
bi.biClrUsed = 0;
bi.biClrImportant = 0;
// Compute the size of the infoheader and the color table
int nColors = (1 << bi.biBitCount);
if( nColors > 256 )
nColors = 0;
dwLen = bi.biSize + nColors * sizeof(RGBQUAD);
// We need a device context to get the DIB from
hDC = GetDC(NULL);
hPal = SelectPalette(hDC,hPal,FALSE);
RealizePalette(hDC);
// Allocate enough memory to hold bitmapinfoheader and color table
hDIB = GlobalAlloc(GMEM_FIXED,dwLen);
if (!hDIB){
SelectPalette(hDC,hPal,FALSE);
ReleaseDC(NULL,hDC);
return NULL;
}
lpbi = (LPBITMAPINFOHEADER)hDIB;
*lpbi = bi;
// Call GetDIBits with a NULL lpBits param, so the device driver
// will calculate the biSizeImage field
GetDIBits(hDC, (HBITMAP)bitmap.GetSafeHandle(), 0L, (DWORD)bi.biHeight,
(LPBYTE)NULL, (LPBITMAPINFO)lpbi, (DWORD)DIB_RGB_COLORS);
bi = *lpbi;
// If the driver did not fill in the biSizeImage field, then compute it
// Each scan line of the image is aligned on a DWORD (32bit) boundary
if (bi.biSizeImage == 0){
bi.biSizeImage = ((((bi.biWidth * bi.biBitCount) + 31) & ~31) / 8)
* bi.biHeight;
// If a compression scheme is used the result may infact be larger
// Increase the size to account for this.
if (dwCompression != BI_RGB)
bi.biSizeImage = (bi.biSizeImage * 3) / 2;
}
// Realloc the buffer so that it can hold all the bits
dwLen += bi.biSizeImage;
if (handle = GlobalReAlloc(hDIB, dwLen, GMEM_MOVEABLE))
hDIB = handle;
else{
GlobalFree(hDIB);
// Reselect the original palette
SelectPalette(hDC,hPal,FALSE);
ReleaseDC(NULL,hDC);
return NULL;
}
// Get the bitmap bits
lpbi = (LPBITMAPINFOHEADER)hDIB;
// FINALLY get the DIB
BOOL bGotBits = GetDIBits( hDC, (HBITMAP)bitmap.GetSafeHandle(),
0L, // Start scan line
(DWORD)bi.biHeight, // # of scan lines
(LPBYTE)lpbi // address for bitmap bits
+ (bi.biSize + nColors * sizeof(RGBQUAD)),
(LPBITMAPINFO)lpbi, // address of bitmapinfo
(DWORD)DIB_RGB_COLORS); // Use RGB for color table
if( !bGotBits )
{
GlobalFree(hDIB);
SelectPalette(hDC,hPal,FALSE);
ReleaseDC(NULL,hDC);
return NULL;
}
SelectPalette(hDC,hPal,FALSE);
ReleaseDC(NULL,hDC);
return hDIB;
}

Comments
A bug near 'nColors'
Posted by sswater on 05/14/2006 08:29pmThe 'nColors' may be not right if 'bi.biBitCount == 32': ------------------------------------------------------- int nColors = (1 << bi.biBitCount); if( nColors > 256 ) nColors = 0; ------------------------------------------------------- If 'bi.biBitCount == 32', the 'nColors' is '1' again. But the 'nColors' should be '0'. It should be: 'if( nColors > 256 )' => 'if( bi.biBitCount > 8 )', isn't it?
-
Reply
ReplyA bug near 'nColors'
Posted by sswater on 05/19/2006 02:35amBug with GMEM_MOVEABLE!!!
Posted by luongomi on 04/05/2006 11:41amAfter you reallocate the buffer to GMEM_MOVEABLE you cast it as if it is a fixed block of memory. After you reallocate it as moveable you should lock/unlock the memory to get a raw pointer. -Mike Luongo luongomi@ (big ten college "msu.edu") From msdn: If GlobalReAlloc reallocates a movable object, the return value is a handle to the memory object. To convert the handle to a pointer, use the GlobalLock function.
ReplyHow to Get Bitmap informations from Bitmap handle in Win Ce?
Posted by p_srini18 on 01/09/2006 05:12amScan from top to bottom
Posted by Fluxay2008 on 12/25/2005 11:50pmhow to access a BMP file through C program
Posted by Legacy on 02/12/2004 12:00amOriginally posted by: saifi
sir
Replyplz send me the code forto access a BMP file through C program
Wavelet Compression - how to proceed further?
Posted by Legacy on 07/18/2003 12:00amOriginally posted by: Jayam
-
Reply
Replyhaar transform
Posted by raedkingdom on 03/31/2005 08:06amtrying to save a DDB to DIB in vb.net CE
Posted by Legacy on 06/24/2003 12:00amOriginally posted by: Pete
ReplyWhy does GetDIBits() not work from C#???
Posted by Legacy on 06/01/2003 12:00amOriginally posted by: Sunil
I am trying to call GetDIBits from my C# code and it simply returns me a 0, GetLastError() also returns a 0 i dont understand what is the problem. as of now i am trying to write a wrapper fr it in VC++ but the native API should resolve.
Help me if you have done this....using C# is imortant and the operatin has t be time cretical as i am using it for a screen capture software i am writing..
regards Sunil
Reply16 bit grayscale
Posted by Legacy on 05/08/2003 12:00amOriginally posted by: Trond78
Hi i got a 16 bit grayscale DDB i want to make a DIB. I set the folowing parameters:
bi.biPlanes = 1;
bi.biBitCount = 16;
What must hPal be??
ReplyGetDIBits Fails
Posted by Legacy on 05/07/2003 12:00amOriginally posted by: Tom Hanks
Great looking function DDBToDIB, thanks to Zafir for providing it. But for me (and several of others) it is not working due a NULL return from GetDIBits().
Actually GetDIBits does work if I am using a monchrome bitmap. Not good enough for me - but maybe a clue to someone knowledgable?
bmp.CreateBitmap(w, h, 1, 8, NULL); // DDBToDIB fails in GetDIBits on 8 bit bmp
bmp.CreateBitmap(w, h, 1, 24, NULL); // DDBToDIB fails in GetDIBits on 24 bit bmp
bmp.CreateBitmap(w, h, 1, 1, NULL); // DDBToDIB *doesn't* fail in GetDIBits on 1 bit bmp
My environment is XP and VC++6 (SP3)
ReplyLoading, Please Wait ...