Drawing a bitmap


Within your program, you may have three different forms of a bitmap, a device-independent bitmap (DIB), a device-dependent bitmap (DDB) and a DIB section. The DIB is essentially a representation of bitmap in a manner that is independent of any device. It contains the information to enable it to be rendered on any device. There are different versions of DIBs, the most common being version 3. The specification for version 4 has also been released but this format is not yet as prevalent. There are two drawbacks to using a DIB; there are fewer functions that handle a DIB and it takes longer to render a DIB.

The device-dependent bitmap is specific to a device and it is very unlikely that a DDB for one device can be rendered on another. One such situation is when you want to render an image from the screen to a printer. In this case you would have to change the DDB to a DIB before you try to render it onto the printer. Most of the GDI functions take a DDB as an argument instead on a DIB.

The DIB section is somewhat new and designed to alleviate some of the problems with a DIB. You can use a DIB section wherever you use a DDB and yet have access to the bitmap bits and the color information. All this preamble was basically to say that you need one function to render a DIB and another to render a DDB or a DIB section.

Function 1: DrawDIB

The DrawDIB() function uses the function SetDIBitsToDevice() for to render the image. When using this function, you should be aware that the BMP file is arranged such that the first scan line (first row of pixels) is the bottom most scan line. You could actually have the top most scan line be the first if the height of the bitmap is specified as a negative value but this is rarely used. So if you want only the top half of the bitmap drawn then the nStartScan value should be half of nNumScans.

You can also use the StretchDIBits() to render the bitmap data onto a device. The StretchDIBits() function is more versatile in that it allows the bitmap to be streched or compressed and it can use various raster operations to generate the image. The StretchDIBits() function can also be used to mirror the image.

One of the argument to the DrawDIB() function is the palette that should be used when rendering the bitmap. This information can be derived from the DIB itself but using a predefined palette can help speed things up slightly.

// DrawDIB	- Draws a DIB onto a device
// pDC		- Pointer to a device context
// hDIB		- Handle of the device-independent bitmap
// pPal		- Pointer to a palette associated with the DIB
// xDest	- x-coordinate of the upper-left corner of the destination rect
// yDest	- y-coordinate of the upper-left corner of the destination rect
void DrawDIB( CDC* pDC, HGLOBAL hDIB, CPalette *pPal, int xDest, int yDest )
{
	LPVOID  lpDIBBits;              // Pointer to DIB bits
	BOOL    bSuccess=FALSE;         // Success/fail flag
	
	BITMAPINFO &bmInfo = *(LPBITMAPINFO)hDIB ;
	int nColors = bmInfo.bmiHeader.biClrUsed ? bmInfo.bmiHeader.biClrUsed : 
				1 << bmInfo.bmiHeader.biBitCount;
	
	// Compute the address of the bitmap bits
	if( bmInfo.bmiHeader.biBitCount > 8 )
		lpDIBBits = (LPVOID)((LPDWORD)(bmInfo.bmiColors + 
			bmInfo.bmiHeader.biClrUsed) + 
			((bmInfo.bmiHeader.biCompression == BI_BITFIELDS) ? 3 : 0));
	else
		lpDIBBits = (LPVOID)(bmInfo.bmiColors + nColors);
	
	// Select and realize the palette if one supplied and if device supports it
	if( pPal && (pDC->GetDeviceCaps(RASTERCAPS) & RC_PALETTE) )
	{
		pDC->SelectPalette(pPal, FALSE);
		pDC->RealizePalette();
	}
	
	::SetDIBitsToDevice(pDC->m_hDC, 		 // hDC
		xDest,					 // DestX
		yDest,					 // DestY
		bmInfo.bmiHeader.biWidth,		 // nDestWidth
		bmInfo.bmiHeader.biHeight,		 // nDestHeight
		0,					 // SrcX
		0,					 // SrcY
		0,					 // nStartScan
		bmInfo.bmiHeader.biHeight,		 // nNumScans
		lpDIBBits,				 // lpBits
		(LPBITMAPINFO)hDIB, 			 // lpBitsInfo
		DIB_RGB_COLORS);			 // wUsage
}

Function 2: DrawBitmap

The DrawBitmap() function can be used with both a DDB and a DIB section. This function does take into account that the destination device context might have a map mode other than MM_TEXT. This might not work always or the effect may not be what you want.
// DrawBitmap	- Draws a bitmap (DDB & DIB section) onto a device
// pDC		- Pointer to a device context
// hBitmap	- Handle of the bitmap
// hPal		- Handle of a logical palette associated with the bitmap
// xDest	- x-coordinate of the upper-left corner of the destination rect
// yDest	- y-coordinate of the upper-left corner of the destination rect
void DrawBitmap( CDC *pDC, HBITMAP hBitmap, HPALETTE hPal, int xDest, int yDest )
{
	// Get logical coordinates
	BITMAP bm;
	::GetObject( hBitmap, sizeof( bm ), &bm );
	CPoint size( bm.bmWidth, bm.bmHeight );
	pDC->DPtoLP(&size);

	CPoint org(0,0);
	pDC->DPtoLP(&org);

	// Create a memory DC compatible with the destination DC
	CDC memDC;
	memDC.CreateCompatibleDC( pDC );
	memDC.SetMapMode( pDC->GetMapMode() );
	
	//memDC.SelectObject( &bitmap );
	HBITMAP hBmOld = (HBITMAP)::SelectObject( memDC.m_hDC, hBitmap );
	
	
	// Select and realize the palette
	if( hPal && pDC->GetDeviceCaps(RASTERCAPS) & RC_PALETTE)
	{
		SelectPalette( pDC->GetSafeHdc(), hPal, FALSE );
		pDC->RealizePalette();
	}
	pDC->BitBlt(xDest, yDest, size.x, size.y, &memDC, org.x, org.y, SRCCOPY);

	::SelectObject( memDC.m_hDC, hBmOld );
}

Function 3: DrawDIBSection

Although we can use the DrawBitmap() function to draw a DIB section as well, this functions takes the color information of the bitmap into consideration and will create and use an appropriate palette when needed. Note that since this function may create a palette in each call, it might be better, for performance reasons, to create an appropriate palette from the DIB section and use the DrawBitmap() function instead. The DrawDIBSection() is handy if DIB section's color information is modified before displaying it.
// DrawDIBSection	- Draws a DIB section onto a device
// hDC		- Handle to a device context
// hBitmap	- Handle of the DIB Section
// xDest	- x-coordinate of the upper-left corner of the destination rect
// yDest	- y-coordinate of the upper-left corner of the destination rect
void DrawDIBSection( HDC hDC, HBITMAP hBitmap, int xDest, int yDest )
{
	HPALETTE hPal;

	HDC hDCMem = ::CreateCompatibleDC( hDC );

	// Create a logical palette for the bitmap
	DIBSECTION ds;
	BITMAPINFOHEADER &bmInfo = ds.dsBmih;
	if( ::GetObject(hBitmap, sizeof(ds), &ds ) == 0 )
		return;			// Not a DIB Section
	
	HGDIOBJ hBmpOld =  ::SelectObject(hDCMem, hBitmap);

	int nColors = bmInfo.biClrUsed ? bmInfo.biClrUsed : 1 << ds.dsBm.bmBitsPixel;
	
	if( ::GetDeviceCaps(hDC, RASTERCAPS) & RC_PALETTE )
	{
		// Create a halftone palette if colors > 256. 
		if( nColors > 256 )
			hPal = ::CreateHalftonePalette(hDC);
		else
		{
			// Create the palette
			RGBQUAD *pRGB = new RGBQUAD[nColors];
			
			::GetDIBColorTable( hDCMem, 0, nColors, pRGB );
			
			UINT nSize = sizeof(LOGPALETTE) + (sizeof(PALETTEENTRY) * nColors);
			LOGPALETTE *pLP = (LOGPALETTE *) new BYTE[nSize];
			
			pLP->palVersion = 0x300;
			pLP->palNumEntries = nColors;
			
			for( int i=0; i < nColors; i++)
			{
				pLP->palPalEntry[i].peRed = pRGB[i].rgbRed;
				pLP->palPalEntry[i].peGreen = pRGB[i].rgbGreen;
				pLP->palPalEntry[i].peBlue = pRGB[i].rgbBlue;
				pLP->palPalEntry[i].peFlags = 0;
			}
			
			hPal = ::CreatePalette( pLP );
			
			delete[] pLP;
			delete[] pRGB;
		}

		HPALETTE hPalOld = ::SelectPalette(hDC,hPal,FALSE);
		::RealizePalette(hDC);
		BitBlt(hDC,xDest,yDest,bmInfo.biWidth,bmInfo.biHeight,hDCMem,0,0,SRCCOPY);

		::SelectPalette(hDC,hPalOld,FALSE);
		// delete GDI objects
		::DeleteObject(hPal);
	}
	else
		BitBlt(hDC,xDest,yDest,bmInfo.biWidth,bmInfo.biHeight,hDCMem,0,0,SRCCOPY);

	::SelectObject(hDCMem, hBmpOld);
	::DeleteDC(hDCMem);
}



Comments

  • DrawDIB() doesn't work

    Posted by Gorthaur on 02/05/2008 01:00pm

    IMHO DrawDIB() code has an error. As I know you cannot do such things as :
       BITMAPINFO &bmInfo = *(LPBITMAPINFO)hDIB;
    
      It's wrong because HANDLE is not the same as void* ,it is just declared so. If you do so, bmInfo is filled in with garbage. If you want to get access to the real pointer to data of handle - must use GlobalLock() function 
    
    It can be like that:
    
       ...
       PVOID pDIB = GlobalLock(hDIB);
       if(!pDIB)
       {
          //Memory error
          ...
       };
       BITMAPINFO &bmInfo = *(LPBITMAPINFO)pDIB;
       ...
       ...
       ...
       GlobalUnlock(hDIB);

    Reply
  • Display a " *.Bmp"

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

    Originally posted by: nizom

    I'm a newbee at Visual C++ and i just want to know how to put a bmp file on the screen of my programs. tell me the libraries that i would need to u too.

    Reply
  • BITMAP

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

    Originally posted by: nizom

    Code for transferring a BMP file to another user

    Reply
  • What if RC_PALETTE & pDC->GetDeviceCaps(RASTERCAPS) == 0

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

    Originally posted by: Peter Zhou

    I want to show a bitmap with a palette which has 256 gray colors. I wrote your codes in OnDraw() function but it doesn't work.

    I found out that
    RC_PALETTE & pDC->GetDeviceCaps(RASTERCAPS) is always zero.

    Can anyone tell me whether I shouldn't write my codes in OnDraw function or it's a problem of my adapter driver?

    Cheers.

    Reply
  • Resizing the View and frame according to the bitmap size

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

    Originally posted by: Datta Kandalkar Kondaji

    How can i resize the view and frame size accordint to the bitmap size. i.e. when i load a bitmap i want the view and the fram size to be adjusted according to the size of bitmap. If the bitmap is very big i.e biggier then the normal size of the view then scroll bar should be added. I am using SDI in MFC. How should i achieve this.

    Thanking in advance

    Reply
  • Bitmap

    Posted by Legacy on 09/03/2003 12:00am

    Originally posted by: panduka

    How can I Loard Bimap when Run time.I need Full Programe Using MFC Visuall C++ Dialog Base project.

    Reply
  • Dialogs animated icon

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

    Originally posted by: kmnaveed

    i want to an animaed icon on my dialog instead of MFC standard icon Plz help me.Thank you.
    

    Reply
  • Animation required

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

    Originally posted by: saima

    I want to create animation using bitmap .I do heard about bitblt and others but no onw helps in getting starting .Plz i need help .So,any one knows he's welcome.i want to show moving wavforms in mine animation with time on x-axis and voltages on y-axis.
    thanx

    Reply
  • Header files?

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

    Originally posted by: Christina

    Hi, could anyone tell me if there are supposed to be header files included, and what are they? Otherwise, what are the types CDC, HGLOBAL, and CPallete?
    Thank you

    Reply
  • I could not see the pictures with color

    Posted by Legacy on 04/02/2003 12:00am

    Originally posted by: Raju Selvaraj

    Dear friend i tried this code but when GetBitampAndPallete function call is encountered in OnPaint function,the "GetBitampAndPallete " is not called .So iam able to see only the black & white Images.Can u help me.
    
    iam working in VC++6.

    Reply
  • Loading, Please Wait ...

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

Top White Papers and Webcasts

  • Live Event Date: November 20, 2014 @ 2:00 p.m. ET / 11:00 a.m. PT Are you wanting to target two or more platforms such as iOS, Android, and/or Windows? You are not alone. 90% of enterprises today are targeting two or more platforms. Attend this eSeminar to discover how mobile app developers can rely on one IDE to create applications across platforms and approaches (web, native, and/or hybrid), saving time, money, and effort and introducing apps to market faster. You'll learn the trade-offs for gaining long …

  • IBM Worklight is a mobile application development platform that lets you extend your business to mobile devices. It is designed to provide an open, comprehensive platform to build, run and manage HTML5, hybrid and native mobile apps.

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds