Converting DDB to DIB


A device-dependent bitmap (DDB) is structured in such a way that it matches very closely the form in which the bitmap is finally displayed by the device driver. For this reason the DDB is unlikely to be compatible with other display devices. A device-independent bitmap (DIB) on the other hand has a logical layout and can be decifered by any device driver. The disadvantage with DIB though is that it is much slower to render onto the device as compared to a DDB.

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:

  1. 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.
  2. 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.
  3. 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).
  4. Given the final size of the bitmap bits, reallocate the memory block to hold the bitmapinfoheader, the color table and the bitmap bits.
  5. 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:29pm

    The '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?

    • A bug near 'nColors'

      Posted by sswater on 05/19/2006 02:35am

      The '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( bi.biBitCount > 8 )' instead of 'if( nColors > 256 )',
      isn't it?

      Reply
    Reply
  • Bug with GMEM_MOVEABLE!!!

    Posted by luongomi on 04/05/2006 11:41am

    After 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.

    Reply
  • How to Get Bitmap informations from Bitmap handle in Win Ce?

    Posted by p_srini18 on 01/09/2006 05:12am

    I have a Bitmap handle and I need access to the RGB data, I have the bitmap handle
    (HBITMAP) but I cannot work out how to get the pointer to the RGB data.
    I would normally use GetDIBits but it looks like its unsupported. I have to capture the screen od pocket pc..
    
    Pls give me any ideas?

    Reply
  • Scan from top to bottom

    Posted by Fluxay2008 on 12/25/2005 11:50pm

    Hi,this can scan a bitmap from bottom to top, and writes it out, but how to make it scan from top to bottom? I try to do as this :bi.biHeight = -bm.bmHeight; but failed, so can you help me ?

    Reply
  • how to access a BMP file through C program

    Posted by Legacy on 02/12/2004 12:00am

    Originally posted by: saifi

    sir
    plz send me the code forto access a BMP file through C program

    Reply
  • Wavelet Compression - how to proceed further?

    Posted by Legacy on 07/18/2003 12:00am

    Originally posted by: Jayam

    Sir,
    
    I have completed haar transform as the first step in the wavelet compression of gray level images. Will you please guide me what is the next step?

    • haar transform

      Posted by raedkingdom on 03/31/2005 08:06am

      i would like to add haar transform to my project . would you send me haar transformation source code?

      Reply
    Reply
  • trying to save a DDB to DIB in vb.net CE

    Posted by Legacy on 06/24/2003 12:00am

    Originally posted by: Pete

    Hello everyone,
    
    

    this area is very interesting, I am
    looking to save an image drawn in a vb.net for CE
    application as a DIB so that it can be copied over to the
    PC. Idealy i would like to save it to the SQL CE database.
    Does anyone out there know how to do this. I can use C# to
    create a dll if I have to.

    Cheers Pete.

    Reply
  • Why does GetDIBits() not work from C#???

    Posted by Legacy on 06/01/2003 12:00am

    Originally 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

    Reply
  • 16 bit grayscale

    Posted by Legacy on 05/08/2003 12:00am

    Originally 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??

    Reply
  • GetDIBits Fails

    Posted by Legacy on 05/07/2003 12:00am

    Originally 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)


    Reply
  • Loading, Please Wait ...

Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • The explosion in mobile devices and applications has generated a great deal of interest in APIs. Today's businesses are under increased pressure to make it easy to build apps, supply tools to help developers work more quickly, and deploy operational analytics so they can track users, developers, application performance, and more. Apigee Edge provides comprehensive API delivery tools and both operational and business-level analytics in an integrated platform. It is available as on-premise software or through …

  • Java developers know that testing code changes can be a huge pain, and waiting for an application to redeploy after a code fix can take an eternity. Wouldn't it be great if you could see your code changes immediately, fine-tune, debug, explore and deploy code without waiting for ages? In this white paper, find out how that's possible with a Java plugin that drastically changes the way you develop, test and run Java applications. Discover the advantages of this plugin, and the changes you can expect to see …

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds