Creating a bitmap object from a BMP file


To create a CBitmap object from a BMP file you essentially have to read the file into memory, use CreateDIBitmap() to get an HBITMAP and then attach this handle to the CBitmap object. The problem however, is to get the colors right. The following code can handle bitmaps with 256 colors or less.

Although we needn't really create a bitmap object to draw the image, the benefit of doing so is that the bitmap we create is a device dependent bitmap (DDB) as apposed to the device independent bitmap (DIB) help in the BMP file. This reduces the time it takes to render the bitmap onto the device.

The BMP file holds a device independent bitmap and sometimes uses the extension DIB. It is composed of four sections. The first is BITMAPFILEHEADER. This contains the bitmap file signature, the size of the bitmap and the offset to the array of bits that define the bitmap image. The next section is the BITMAPINFOHEADER. This contains information such as the height and widht of the bitmap and the number of colors used. This section is followed by the color table. The color table contains two or more RGBQUAD structures The final section is the actual bits that define the bitmap image.

Step 1: Create the bitmap object

The LoadBMPImage() function given below will read in a BMP file, create a device dependent bitmap of it and attach it to the CBitmap object passed in as an argument. It can also create a logical palette if a pointer to a CPalette object is supplied.

This function basically reads in the BMP file, creates a logical palette and calls CreateDIBitmap() to create the GDI bitmap object. Note that when you supply a pointer to a CPalette object, the function creates a logical palette and uses the palette when creating the bitmap object.
// LoadBMPImage	- Loads a BMP file and creates a bitmap GDI object
//		  also creates logical palette for it.
// Returns	- TRUE for success
// sBMPFile	- Full path of the BMP file
// bitmap	- The bitmap object to initialize
// pPal		- Will hold the logical palette. Can be NULL
BOOL LoadBMPImage( LPCTSTR sBMPFile, CBitmap& bitmap, CPalette *pPal )
{
	CFile file;
	if( !file.Open( sBMPFile, CFile::modeRead) )
		return FALSE;

	BITMAPFILEHEADER bmfHeader;

	// Read file header
	if (file.Read((LPSTR)&bmfHeader, sizeof(bmfHeader)) != sizeof(bmfHeader))
		return FALSE;

	// File type should be 'BM'
	if (bmfHeader.bfType != ((WORD) ('M' << 8) | 'B'))
		return FALSE;

	// Get length of the remainder of the file and allocate memory
	DWORD nPackedDIBLen = file.GetLength() - sizeof(BITMAPFILEHEADER);
	HGLOBAL hDIB = ::GlobalAlloc(GMEM_FIXED, nPackedDIBLen);
	if (hDIB == 0)
		return FALSE;

	// Read the remainder of the bitmap file.
	if (file.ReadHuge((LPSTR)hDIB, nPackedDIBLen) != nPackedDIBLen )
	{
		::GlobalFree(hDIB);
		return FALSE;
	}


	BITMAPINFOHEADER &bmiHeader = *(LPBITMAPINFOHEADER)hDIB ;
	BITMAPINFO &bmInfo = *(LPBITMAPINFO)hDIB ;

	// If bmiHeader.biClrUsed is zero we have to infer the number
	// of colors from the number of bits used to specify it.
	int nColors = bmiHeader.biClrUsed ? bmiHeader.biClrUsed : 
						1 << bmiHeader.biBitCount;

	LPVOID lpDIBBits;
	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);

	// Create the logical palette
	if( pPal != NULL )
	{
		// Create the palette
		if( nColors <= 256 )
		{
			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 = bmInfo.bmiColors[i].rgbRed;
				pLP->palPalEntry[i].peGreen = bmInfo.bmiColors[i].rgbGreen;
				pLP->palPalEntry[i].peBlue = bmInfo.bmiColors[i].rgbBlue;
				pLP->palPalEntry[i].peFlags = 0;
			}

			pPal->CreatePalette( pLP );

			delete[] pLP;
		}
	}

	CClientDC dc(NULL);
	CPalette* pOldPalette = NULL;
	if( pPal )
	{
		pOldPalette = dc.SelectPalette( pPal, FALSE );
		dc.RealizePalette();
	}

	HBITMAP hBmp = CreateDIBitmap( dc.m_hDC,		// handle to device context 
				&bmiHeader,	// pointer to bitmap size and format data 
				CBM_INIT,	// initialization flag 
				lpDIBBits,	// pointer to initialization data 
				&bmInfo,	// pointer to bitmap color-format data 
				DIB_RGB_COLORS);		// color-data usage 
	bitmap.Attach( hBmp );

	if( pOldPalette )
		dc.SelectPalette( pOldPalette, FALSE );

	::GlobalFree(hDIB);
	return TRUE;
}

Step 2: Drawing the bitmap

The DrawBitmap() function given below is a very simple function that will draw the given bitmap to the top left corner of the device context. It will also use a logical palette to draw the image if you supply one. You can easily extend this function to specify where to draw the bitmap or even whether to tile the bitmap or extend it to cover the device context.
void DrawBitmap(CDC* pDC, CBitmap& bitmap, CPalette *pPal )
{
	// Create a compatible memory DC
	CDC memDC;
	memDC.CreateCompatibleDC( pDC );
	memDC.SelectObject( &bitmap );

	// Select and realize the palette
	if( pPal != NULL && pDC->GetDeviceCaps(RASTERCAPS) & RC_PALETTE )
	{
		pDC->SelectPalette( pPal, FALSE );
		pDC->RealizePalette();
	}

	BITMAP bm;
	bitmap.GetBitmap( &bm );

	pDC->BitBlt(0, 0, bm.bmWidth, bm.bmHeight, &memDC, 0, 0,SRCCOPY);
}



Comments

  • raw image data -> picturebox in vb6

    Posted by Legacy on 01/27/2004 12:00am

    Originally posted by: Defcon31

    I receive a the address of a pointer to my image data from a dll. how do i display raw image data (1 byte per grayscale pixel) in a picturebox in visual basic.

    • I receive my image data as BYTE array from a VC++ dll. how do i display raw image data (1 byte per grayscale pixel) in a picturebox in visual basic.

      Posted by billy_bill on 09/19/2007 08:34am

      I tried above mentioned solution but unable to show image. Can please some-one help me.

      Reply
    • Use SetDIBits API

      Posted by weizhen77 on 10/30/2004 11:30pm

      Below is a sample code. The code read a 24-bit BMP file, store the raw data into a memory block "bp" and display onto the PictureBox. For your case instead of 24-bit pixel data, change the code to 8-bit data per pixel.
      
      Option Explicit
      Private Declare Function SetDIBits Lib "gdi32" (ByVal hdc As Long, ByVal hBitmap As Long, ByVal nStartScan As Long, ByVal nNumScans As Long, lpBits As Any, lpBI As BITMAPINFO, ByVal wUsage As Long) As Long
      
      Private Type BITMAPINFOHEADER '40 bytes
          biSize As Long
          biWidth As Long
          biHeight As Long
          biPlanes As Integer
          biBitCount As Integer
          biCompression As Long
          biSizeImage As Long
          biXPelsPerMeter As Long
          biYPelsPerMeter As Long
          biClrUsed As Long
          biClrImportant As Long
      End Type
      Private Type RGBQUAD '4 bytes
          rgbBlue As Byte
          rgbGreen As Byte
          rgbRed As Byte
          rgbReserved As Byte
      End Type
      Private Type BITMAPINFO '44 bytes
          bmiHeader As BITMAPINFOHEADER
          bmiColors As RGBQUAD
      End Type
      
      Private Const DIB_RGB_COLORS = 0&
      Private Const BI_RGB = 0&
      
      Private Sub Command1_Click()
        Dim i As Long
        Dim bp() As Byte
        Dim bmppath As String
        Dim bm As BITMAPINFO
        
        bm.bmiHeader.biSize = Len(bm.bmiHeader)
        bmppath = App.Path & "\test.bmp"
        Open bmppath For Binary As #1
          Get #1, 3, bm.bmiHeader.biSizeImage 'Not a reliable data
          Get #1, 19, bm.bmiHeader.biWidth 'Use negative height to scan top-down.
          Get #1, 23, bm.bmiHeader.biHeight
          Get #1, 27, bm.bmiHeader.biPlanes
          Get #1, 29, bm.bmiHeader.biBitCount 'Bits per pixel
          Get #1, 31, bm.bmiHeader.biCompression 'BI_RGB
          ReDim bp(bm.bmiHeader.biSizeImage - 1) As Byte
          Get #1, 55, bp
        Close #1
        
        Picture1.Width = bm.bmiHeader.biWidth
        Picture1.Height = bm.bmiHeader.biHeight
        
        i = SetDIBits(Picture1.hdc, _
            Picture1.Image, _
            0, _
            bm.bmiHeader.biHeight, _
            bp(0), _
            bm, _
            DIB_RGB_COLORS)
        
        Debug.Print i
          
        Picture1.Visible = True
        Picture1.Refresh
        
      End Sub

      Reply
    Reply
  • HOW DO I USE THIS WITH HDC OR LPCSTR

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

    Originally posted by: Lloyd

    I'm trying to understand this all, I'm new to this area of programming. The program I'm building, I am opening a bitmap and setting it as the background of a "transparent" animated gif. I can set a background I import into my program as a bitmap. But, because the screen changes, and what's on the screen is what I need as the background, I'm having to do a screen capture to a file, which is successful. Now, unless there's a better way to do this and someone could help me, I need to open this bitmap file and set it to the background. 
    
    

    The function allows for either one of these two...

    HDC hSourceDC

    OR

    LPCTSTR lpBitmapName...

    I'm not sure what exactly it's asking for. How can I incorporate your code, opening the bitmap, and then putting it to one of these?

    Thanks in advance,
    Lloyd

    Reply
  • source code for displaying BMP 256-bits colour 640x480 in windows mode using C++

    Posted by Legacy on 12/23/2002 12:00am

    Originally posted by: hewcm

    is there anyone can help me? i need source code for displaying BMP 256-bits colour 630x480 in windows mode using c++.
    

    Reply
  • Read Pixel by Piexl

    Posted by Legacy on 11/04/2002 12:00am

    Originally posted by: Hubert

    I want to read the RGB value of a bitmap file pixel by pixel. Are there any simple solution? Do I neccessart load the file into a piettle? Thanks.

    Reply
  • I use Borland c++ compiler. CFile - ???

    Posted by Legacy on 08/30/2002 12:00am

    Originally posted by: ILYA

    My compiler can not create CFile object.
    I do not have h-file with defenishen of CFile.
    I use CreateFile, ReadFile ....
    What must I do read BitMap with shuch function?
    (sorry for my Engl.)

    Reply
  • Memory leak ???

    Posted by Legacy on 06/28/2002 12:00am

    Originally posted by: Loan Ng.

    Does anyone have memory leak when try using this code?

    Reply
  • Problem using DrawBitmap to the printer device context

    Posted by Legacy on 06/11/2002 12:00am

    Originally posted by: Pablo

    I tried to use DrawBitmap but it is no working. It showed the printer dialog, It said it was printing all the pages but all I obtained was white pages, only my header in them.

    There is something else to do in order to use this function for printing?

    Thanks,

    Pablo

    Reply
  • How do I add a bmp image through a file to a list control?

    Posted by Legacy on 05/20/2002 12:00am

    Originally posted by: Dj

    I want to add a bmp image after reading from a file, onto the list control.

    I am using LoadImage() and able to load a bmp from a file. After that I am even able to draw in OnDraw() using memory device context.

    However, How do I go about doing the same in my List Control?


    Reply
  • I made it working several times without problem

    Posted by Legacy on 05/16/2002 12:00am

    Originally posted by: PJ

    I'd obtained Assert messages every second time I invoked "LoadBMPImage" in the "bitmap.Attach( hBmp );" instruction.

    I don�t know what exactly means the CBitmap.Attach definition ("Attaches a Windows GDI object to a CGdiObject object."). But if I have problem with "Attach" may be I can solve it with "Detach".

    So, I inserted "bitmap.Detach();" just before the "bitmap.Attache( hBmp );" instruction and it seems to be working Ok.

    The problem is, Do you know if this "solution" may produce side effects in memory, pointers, etc.?

    Thanks,

    PJ

    Reply
  • how to load a 256 color bitmap file in simple SDI application

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

    Originally posted by: aaqib sharif

    if any body could help me in this manner. plz do help me. i want to load the bitmap file through Loadbitmap() and then i have to use Getpixel() function for my OCR project.

    Reply
  • Loading, Please Wait ...

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

Top White Papers and Webcasts

  • You may already know about some of the benefits of Bluemix, IBM's open platform for developing and deploying mobile and web applications. Check out this webcast that focuses on building an Android application using the MobileData service, with a walk-through of the real process and workflow used to build and link the MobileData service within your application. Join IBM's subject matter experts as they show you the way to build a base application that will jumpstart you into building your own more complex app …

  • A modern mobile IT strategy is no longer an option, it is an absolute business necessity. Today's most productive employees are not tied to a desk, an office, or a location. They are mobile. And your company's IT strategy has to be ready to support them with easy, reliable, 24/7 access to the business information they need, from anywhere in the world, across a broad range of communication devices. Here's how some of the nation's most progressive corporations are meeting the many needs of their mobile workers …

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds