Главная страница | назад





Article #15485: 256 Color Bitmaps in WIN 16 API

 Question and Answer Database

FAQ485C.txt   256 Color Bitmaps in WIN 16 API
Category   :Windows API
Platform    :All Windows
Product    :   BC++4.5x   BC++5.x   C++Builder1.0   C++Builder3.x   TC++Win4.5

Question:
Q: How do i read a 256 color bitmap from a file? 

Answer:
the following function reads in and then displays a 256 color bitmap. (note - the bitmap is hard coded,
and the function can only read in 256 color bitmaps.  This could be easily changed.

//--------------------------------------------------------------------------------------------
//start code

BOOL LoadBitmapFromFile (HWND hwnd){

	HFILE hfile;
	BITMAPFILEHEADER BMPFileHead;
	BITMAPINFOHEADER BMPFileInfo;
	BITMAPINFO *BMPInfo;
	int BMPInfoSize;
	void *image;
	OFSTRUCT FileBuf;
	HDC hdc;
	PLOGPALETTE PaletteLog;
	PALETTEENTRY pe[256];
	HPALETTE hpal;

	if (HFILE_ERROR == (hfile = OpenFile ("winnt256.bmp", &FileBuf, OF_READ))){
		MessageBox (hwnd, "Could not open file", "ERROR!",
				 MB_OK | MB_ICONEXCLAMATION);
		return FALSE;
	}
	if (FILE_READ_ERROR == (_hread(hfile, &BMPFileHead, sizeof (BITMAPFILEHEADER)))){
		MessageBox (hwnd, "Could not read Bitmap file header", "ERROR!", MB_OK | MB_ICONEXCLAMATION);
		_lclose (hfile);
		return FALSE;
	}
	if (FILE_READ_ERROR == (_hread(hfile, &BMPFileInfo, sizeof (BITMAPINFOHEADER)))){
		MessageBox (hwnd, "Could not read Bitmap file info", "ERROR!",
				 MB_OK | MB_ICONEXCLAMATION);
		_lclose (hfile);
		return FALSE;
	}

	BMPInfoSize = (sizeof (BITMAPINFO)) + (265 * sizeof (RGBQUAD));

	BMPInfo = (BITMAPINFO*) malloc (BMPInfoSize);

	BMPInfo->bmiHeader = BMPFileInfo;
	
	if(FILE_READ_ERROR == (_hread (hfile, BMPInfo->bmiColors, 256 * sizeof (RGBQUAD)))){
		MessageBox (hwnd, "Could not read Bitmap palette", "ERROR!",
				 MB_OK | MB_ICONEXCLAMATION);
		free (BMPInfo);
		_lclose (hfile);
		return FALSE;
	}

	image = GlobalAllocPtr (GPTR, BMPFileInfo.biSizeImage + 1024);
	if(FILE_READ_ERROR == (_hread (hfile, image, BMPFileInfo.biSizeImage))){
		MessageBox (hwnd, "Could not read Bitmap bits to buffer", "ERROR!",
				 MB_OK | MB_ICONEXCLAMATION);
		free (BMPInfo);
		_lclose (hfile);
		return FALSE;
	}
	_lclose (hfile);

	PaletteLog = (PLOGPALETTE)malloc(sizeof (LOGPALETTE) * 256);
	PaletteLog->palNumEntries = 256;
	PaletteLog->palVersion = 0x300;
	for (int i = 0; i < 256; i++){
		PaletteLog->palPalEntry[i].peRed = BMPInfo->bmiColors[i].rgbRed;
		PaletteLog->palPalEntry[i].peGreen = BMPInfo->bmiColors[i].rgbGreen;
		PaletteLog->palPalEntry[i].peBlue = BMPInfo->bmiColors[i].rgbBlue;
	}

	hpal = CreatePalette (PaletteLog);

	hdc = GetDC (hwnd);

	SelectPalette (hdc, hpal, FALSE);
	RealizePalette (hdc);

	SetDIBitsToDevice (hdc, 0, 0, BMPFileInfo.biWidth, BMPFileInfo.biHeight, 0,
		 0, 0, BMPFileInfo.biHeight, image, BMPInfo, DIB_RGB_COLORS);

	GlobalFreePtr (image);
	free (BMPInfo);
	delete (PaletteLog);
	DeleteObject (hpal);
	ReleaseDC (hwnd, hdc);

	return TRUE;
}

First thing that is done is the file is opened.  

	if (HFILE_ERROR == (hfile = OpenFile ("winnt256.bmp", &FileBuf, OF_READ))){
		MessageBox (hwnd, "Could not open file", "ERROR!",
				 MB_OK | MB_ICONEXCLAMATION);
		return FALSE;
	}

If the file was opened successfully, we then stripe off the BITMAPFILEHEADER 
by reading it in.  The way a bitmap is saved is as follows:

--------------------
| BITMAPFILEHEADER |
--------------------
| BITMAPINFOHEADER |
--------------------
| RGBQUAD          |
| (bitmap colors)  |
--------------------
| actual bitmap    |
| bits             |
|                  |
|                  |
|                  |
--------------------

So we reading in the first BITMAPFILEHEADER size chunk of the file, and placing it in a
BITMAPFILEHEADER struct. 

	if (FILE_READ_ERROR == (_hread(hfile, &BMPFileHead, sizeof (BITMAPFILEHEADER)))){
		MessageBox (hwnd, "Could not read Bitmap file header", "ERROR!", 
			MB_OK | MB_ICONEXCLAMATION);
		_lclose (hfile);
		return FALSE;
	}

-(note _hread will adjust the file pointer by the number of bytes actually read) 
After we get the BITMAPFILEHEADER we then do the same thing only reading in the 
BITMAPINFOHEADER.

	if (FILE_READ_ERROR == (_hread(hfile, &BMPFileInfo, sizeof (BITMAPINFOHEADER)))){
		MessageBox (hwnd, "Could not read Bitmap file info", "ERROR!",
				 MB_OK | MB_ICONEXCLAMATION);
		_lclose (hfile);
		return FALSE;
	}

Once we got the BITMAPINFOHEADER the next thing we need to do is create a BITMAPINFO struct.  
The BITMAPINFO struct is the struct that contains the BITMAPINFOHEADER and the RGBQUAD of 
the bitmap. To create the struct we allocate space that is the size of a BITMAPINFO plus the
size of a RGBQUAD * the number of colors the bitmap contains (in this case 256).

	BMPInfoSize = (sizeof (BITMAPINFO)) + (265 * sizeof (RGBQUAD));

	BMPInfo = (BITMAPINFO*) malloc (BMPInfoSize);

Then we set the BITMAPINFO's bmi.Header to the BITMAPINFOHEADER of this bitmap.

	BMPInfo->bmiHeader = BMPFileInfo;

Then we read the RGBQUAD info from the file into the RGBQUAD info of the BITMAPINFO structure.

if(FILE_READ_ERROR == (_hread (hfile, BMPInfo->bmiColors, 256 * sizeof (RGBQUAD)))){
		MessageBox (hwnd, "Could not read Bitmap palette", "ERROR!",
				 MB_OK | MB_ICONEXCLAMATION);
		free (BMPInfo);
		_lclose (hfile);
		return FALSE;
	}

next we allocate space for the actual bits of the bitmap, and read the bits in from the file to 
the space we just allocated.  The size of the actual bitmap is stored in the biSizeImage    
property of the BITMAPINFOHEADER.

	image = GlobalAllocPtr (GPTR, BMPFileInfo.biSizeImage);
	if(FILE_READ_ERROR == (_hread (hfile, image, BMPFileInfo.biSizeImage))){
		MessageBox (hwnd, "Could not read Bitmap bits to buffer", "ERROR!",
				 MB_OK | MB_ICONEXCLAMATION);
		free (BMPInfo);
		_lclose (hfile);
		return FALSE;
	}

then close the file it is no longer needed.

	_lclose (hfile);

Now we need to set up our palette.  First we allocate space for the palette.  We need space large
enough for the LOGPALETTE * nomber of colors in the bitmap (256 in our case).  Once we have space 
our LOGPALETTE we then set its properties.  palNumEntries = number of colors in our bitmap (256),
palVersion most always = 0x300, and the palPalEntry[1] has to be filled with the colors of our
bitmap.  Since we read the colors into the BITMAPINFO.biColors space we simple transfor that out 
to palPalEntry[i] with a for loop.

	PaletteLog = (PLOGPALETTE)malloc(sizeof (LOGPALETTE) * 256);
	PaletteLog->palNumEntries = 256;
	PaletteLog->palVersion = 0x300;
	for (int i = 0; i < 256; i++){
		PaletteLog->palPalEntry[i].peRed = BMPInfo->bmiColors[i].rgbRed;
		PaletteLog->palPalEntry[i].peGreen = BMPInfo->bmiColors[i].rgbGreen;
		PaletteLog->palPalEntry[i].peBlue = BMPInfo->bmiColors[i].rgbBlue;
	}

Once we have the LOGPALETTE we call create palette witch returns a handle to our palette.

	hpal = CreatePalette (PaletteLog);

Next we need to get the DC that we are going to place the bitmap in.  
	
	hdc = GetDC (hwnd);

Then we need to Select our palette into our dc and realize the palette with the system

	SelectPalette (hdc, hpal, FALSE);
	RealizePalette (hdc);

Next we set the bits form our DIB to the hdc using the win API call SetDIBitsToDevice

	SetDIBitsToDevice (hdc, 0, 0, BMPFileInfo.biWidth, BMPFileInfo.biHeight, 0,
		 0, 0, BMPFileInfo.biHeight, image, BMPInfo, DIB_RGB_COLORS);

Then we have to clean up our handles and pointers

	GlobalFreePtr (image);
	free (BMPInfo);
	delete (PaletteLog);
	DeleteObject (hpal);
	ReleaseDC (hwnd, hdc);

If this works we return true and there will be a picture on the screen.

	return TRUE;
}
 



7/2/98 10:32:32 AM
 

Last Modified: 01-SEP-99