Don't completely understand - Bitmap issue

Started by
5 comments, last by Endurion 19 years, 3 months ago
At the moment I'm reading Sams teach yourself game programming in 24 hours. In this book at some point you will be creating your own bitmap class. The thing is, this bitmap class is supposed to be for 256 colour bitmap images. Now it gets even weirder, the bitmaps supplied with the book are 256 colour bitmap images and they work perfectly. But as soon as I would add something with plain old ms paint and save it again as a 256 colour bitmap image, it suddenly gets weird on the bottom if I run the game like you're having some codec problem and the rest is like placed the other way around, the left part is placed on the right end and the right end is pushed to the left. To make it even more weird, as soon as I save it as a 24bits colour bitmap image, it suddenly works perfect again :S. To make my question short, how come my own 256 colour images are resulting into these sort of problems and what makes 24bits images work in a class which is designed for 256 colour bitmap images?
Advertisement
It's not a greyscale picture is it? If it is then you probably need a 24-bit image and it only uses one of the color channels.

The only other explanation I can see is that some of your info is wrong.
"In order to understand recursion, you must first understand recursion."
My website dedicated to sorting algorithms
The left/right issue is probably due to not padding the lines to 32 bit boundaries. Every line of the bitmap needs to be padded to complete 32 bit.

Why the 24bit images work i can't say without knowing/seeing the bitmap class code. My guess it with 24 bit depth the line is padded right.

Fruny: Ftagn! Ia! Ia! std::time_put_byname! Mglui naflftagn std::codecvt eY'ha-nthlei!,char,mbstate_t>

@Endurion: I'm telling all that I know, but here you have the code.

The bitmap class code:
//-----------------------------------------------------------------// Bitmap Object// C++ Source - Bitmap.cpp//-----------------------------------------------------------------//-----------------------------------------------------------------// Include Files//-----------------------------------------------------------------#include "Bitmap.h"//-----------------------------------------------------------------// Bitmap Constructor(s)/Destructor//-----------------------------------------------------------------Bitmap::Bitmap()  : m_hBitmap(NULL), m_iWidth(0), m_iHeight(0){}// Create a bitmap from a fileBitmap::Bitmap(HDC hDC, LPTSTR szFileName)  : m_hBitmap(NULL), m_iWidth(0), m_iHeight(0){  Create(hDC, szFileName);}// Create a bitmap from a resourceBitmap::Bitmap(HDC hDC, UINT uiResID, HINSTANCE hInstance)  : m_hBitmap(NULL), m_iWidth(0), m_iHeight(0){  Create(hDC, uiResID, hInstance);}// Create a blank bitmap from scratchBitmap::Bitmap(HDC hDC, int iWidth, int iHeight, COLORREF crColor)  : m_hBitmap(NULL), m_iWidth(0), m_iHeight(0){  Create(hDC, iWidth, iHeight, crColor);}Bitmap::~Bitmap(){  Free();}//-----------------------------------------------------------------// Bitmap Helper Methods//-----------------------------------------------------------------void Bitmap::Free(){  // Delete the bitmap graphics object  if (m_hBitmap != NULL)  {    DeleteObject(m_hBitmap);    m_hBitmap = NULL;  }}//-----------------------------------------------------------------// Bitmap General Methods//-----------------------------------------------------------------BOOL Bitmap::Create(HDC hDC, LPTSTR szFileName){  // Free any previous bitmap info  Free();  // Open the bitmap file  HANDLE hFile = CreateFile(szFileName, GENERIC_READ, FILE_SHARE_READ, NULL,    OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);  if (hFile == INVALID_HANDLE_VALUE)    return FALSE;  // Read the bitmap file header  BITMAPFILEHEADER  bmfHeader;  DWORD             dwBytesRead;  BOOL bOK = ReadFile(hFile, &bmfHeader, sizeof(BITMAPFILEHEADER),    &dwBytesRead, NULL);  if ((!bOK) || (dwBytesRead != sizeof(BITMAPFILEHEADER)) ||    (bmfHeader.bfType != 0x4D42))  {    CloseHandle(hFile);    return FALSE;  }  BITMAPINFO* pBitmapInfo = (BITMAPINFO*)(new BITMAPINFO_256);  if (pBitmapInfo != NULL)  {    // Read the bitmap info header    bOK = ReadFile(hFile, pBitmapInfo, sizeof(BITMAPINFOHEADER),      &dwBytesRead, NULL);    if ((!bOK) || (dwBytesRead != sizeof(BITMAPINFOHEADER)))    {      CloseHandle(hFile);      Free();      return FALSE;    }    // Store the width and height of the bitmap    m_iWidth = (int)pBitmapInfo->bmiHeader.biWidth;    m_iHeight = (int)pBitmapInfo->bmiHeader.biHeight;    // Skip (forward or backward) to the color info, if necessary    if (pBitmapInfo->bmiHeader.biSize != sizeof(BITMAPINFOHEADER))      SetFilePointer(hFile, pBitmapInfo->bmiHeader.biSize - sizeof        (BITMAPINFOHEADER), NULL, FILE_CURRENT);    // Read the color info    bOK = ReadFile(hFile, pBitmapInfo->bmiColors,      pBitmapInfo->bmiHeader.biClrUsed * sizeof(RGBQUAD), &dwBytesRead,      NULL);    // Get a handle to the bitmap and copy the image bits    PBYTE pBitmapBits;    m_hBitmap = CreateDIBSection(hDC, pBitmapInfo, DIB_RGB_COLORS,      (PVOID*)&pBitmapBits, NULL, 0);    if ((m_hBitmap != NULL) && (pBitmapBits != NULL))    {      SetFilePointer(hFile, bmfHeader.bfOffBits, NULL, FILE_BEGIN);      bOK = ReadFile(hFile, pBitmapBits, pBitmapInfo->bmiHeader.biSizeImage,        &dwBytesRead, NULL);      if (bOK)        return TRUE;    }  }  // Something went wrong, so cleanup everything  Free();  return FALSE;}BOOL Bitmap::Create(HDC hDC, UINT uiResID, HINSTANCE hInstance){  // Free any previous DIB info  Free();  // Find the bitmap resource  HRSRC hResInfo = FindResource(hInstance, MAKEINTRESOURCE(uiResID), RT_BITMAP);  if (hResInfo == NULL)    return FALSE;  // Load the bitmap resource  HGLOBAL hMemBitmap = LoadResource(hInstance, hResInfo);  if (hMemBitmap == NULL)    return FALSE;  // Lock the resource and access the entire bitmap image  PBYTE pBitmapImage = (BYTE*)LockResource(hMemBitmap);  if (pBitmapImage == NULL)  {    FreeResource(hMemBitmap);    return FALSE;  }  // Store the width and height of the bitmap  BITMAPINFO* pBitmapInfo = (BITMAPINFO*)pBitmapImage;  m_iWidth = (int)pBitmapInfo->bmiHeader.biWidth;  m_iHeight = (int)pBitmapInfo->bmiHeader.biHeight;  // Get a handle to the bitmap and copy the image bits  PBYTE pBitmapBits;  m_hBitmap = CreateDIBSection(hDC, pBitmapInfo, DIB_RGB_COLORS,    (PVOID*)&pBitmapBits, NULL, 0);  if ((m_hBitmap != NULL) && (pBitmapBits != NULL))  {    const PBYTE pTempBits = pBitmapImage + pBitmapInfo->bmiHeader.biSize +      pBitmapInfo->bmiHeader.biClrUsed * sizeof(RGBQUAD);    CopyMemory(pBitmapBits, pTempBits, pBitmapInfo->bmiHeader.biSizeImage);    // Unlock and free the bitmap graphics object    UnlockResource(hMemBitmap);    FreeResource(hMemBitmap);    return TRUE;  }  // Something went wrong, so cleanup everything  UnlockResource(hMemBitmap);  FreeResource(hMemBitmap);  Free();  return FALSE;}BOOL Bitmap::Create(HDC hDC, int iWidth, int iHeight, COLORREF crColor){  // Create a blank bitmap  m_hBitmap = CreateCompatibleBitmap(hDC, iWidth, iHeight);  if (m_hBitmap == NULL)    return FALSE;  // Set the width and height  m_iWidth = iWidth;  m_iHeight = iHeight;  // Create a memory device context to draw on the bitmap  HDC hMemDC = CreateCompatibleDC(hDC);  // Create a solid brush to fill the bitmap  HBRUSH hBrush = CreateSolidBrush(crColor);  // Select the bitmap into the device context  HBITMAP hOldBitmap = (HBITMAP)SelectObject(hMemDC, m_hBitmap);  // Fill the bitmap with a solid color  RECT rcBitmap = { 0, 0, m_iWidth, m_iHeight };  FillRect(hMemDC, &rcBitmap, hBrush);  // Cleanup  SelectObject(hMemDC, hOldBitmap);  DeleteDC(hMemDC);  DeleteObject(hBrush);  return TRUE;}void Bitmap::Draw(HDC hDC, int x, int y, BOOL bTrans, COLORREF crTransColor){  if (m_hBitmap != NULL)  {    // Create a memory device context for the bitmap    HDC hMemDC = CreateCompatibleDC(hDC);    // Select the bitmap into the device context    HBITMAP hOldBitmap = (HBITMAP)SelectObject(hMemDC, m_hBitmap);    // Draw the bitmap to the destination device context    if (bTrans)      TransparentBlt(hDC, x, y, GetWidth(), GetHeight(), hMemDC, 0, 0,        GetWidth(), GetHeight(), crTransColor);    else      BitBlt(hDC, x, y, GetWidth(), GetHeight(), hMemDC, 0, 0, SRCCOPY);    // Restore and delete the memory device context    SelectObject(hMemDC, hOldBitmap);    DeleteDC(hMemDC);  }}


//-----------------------------------------------------------------// Bitmap Object// C++ Header - Bitmap.h//-----------------------------------------------------------------#pragma once//-----------------------------------------------------------------// Include Files//-----------------------------------------------------------------#include <windows.h>//-----------------------------------------------------------------// Custom Data Types//-----------------------------------------------------------------struct BITMAPINFO_256{  BITMAPINFOHEADER  bmiHeader;  RGBQUAD           bmiColors[256];};//-----------------------------------------------------------------// Bitmap Class//-----------------------------------------------------------------class Bitmap{protected:  // Member Variables  HBITMAP m_hBitmap;  int     m_iWidth, m_iHeight;  // Helper Methods  void Free();public:  // Constructor(s)/Destructor  Bitmap();  Bitmap(HDC hDC, LPTSTR szFileName);  Bitmap(HDC hDC, UINT uiResID, HINSTANCE hInstance);  Bitmap(HDC hDC, int iWidth, int iHeight, COLORREF crColor = RGB(0, 0, 0));  virtual ~Bitmap();  // General Methods  BOOL Create(HDC hDC, LPTSTR szFileName);  BOOL Create(HDC hDC, UINT uiResID, HINSTANCE hInstance);  BOOL Create(HDC hDC, int iWidth, int iHeight, COLORREF crColor);  void Draw(HDC hDC, int x, int y, BOOL bTrans = FALSE,    COLORREF crTransColor = RGB(255, 0, 255));  int  GetWidth() { return m_iWidth; };  int  GetHeight() { return m_iHeight; };};

[Edit: Because scrolling the entire page for some code is not cool. - Oluseyi]

@iMalc: It's not a greyscale picture.

[Edited by - Oluseyi on January 7, 2005 10:53:51 PM]
My first instinct would be to suggest that the use of Paint to edit the image is the problem... Paint does some weird things, IME, in the name of its IMHO very strange idea of "user friendliness".

Are you resizing the image when you edit it?

Have you tried hex-editing the original and modified BMPs to see if things are as you would expect (same header and colour table data)?

Have you tested the code with a blank (or solid-colour) image?
Eww. You don't want to restrict your image type to something that silly.

Try a different bitmap handling class. In fact... I have one right here:

First the header file:
// BitMapObject.h#ifndef BITMAPOBJECT_H#define BITMAPOBJECT_H#pragma once// we need this for window stuff#include <windows.h>class BitMapObject{private:	// memory dc	HDC hdcMemory;		// new bitmap!	HBITMAP hbmNewBitMap;	// old bitmap.	HBITMAP hbmOldBitMap;	// width & height as integers.	int iWidth;	int iHeight;public:	// constructor	BitMapObject();	// destructor	~BitMapObject();	// loads bitmap from a file	void Load(HDC hdcCompatible, LPCTSTR lpszFilename);	// creates a blank bitmap	void Create(HDC hdcCompatible, int width, int height);	// destroys bitmap and dc	void Destroy();	// return width	int GetWidth();	// return height	int GetHeight();	// converts to HDC	operator HDC();};#endif


And for the sister source file:
#include "bitmapobject.h"BitMapObject::BitMapObject(){	hdcMemory = NULL;	hbmNewBitMap = NULL;	hbmOldBitMap = NULL;	iWidth = 0;	iHeight = 0;}BitMapObject::~BitMapObject(){	// if the hdcMemory hasn't been destroyed, do so	if(hdcMemory)		Destroy();}void BitMapObject::Load(HDC hdcCompatible, LPCTSTR lpszFilename){	// if hdcMemory isn't null, make it so captain!	if(hdcMemory)		Destroy();	// create memory dc.	hdcMemory = CreateCompatibleDC(hdcCompatible);	// load the bitmap	hbmNewBitMap = (HBITMAP)LoadImage(NULL, lpszFilename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);	// shove the image into the dc	hbmOldBitMap = (HBITMAP)SelectObject(hdcMemory, hbmNewBitMap);	// grab the bitmap's properties	BITMAP bmp;	GetObject(hbmNewBitMap, sizeof(BITMAP), (LPVOID) &bmp);	// grab the width & height	iWidth = bmp.bmWidth;	iHeight = bmp.bmHeight;}void BitMapObject::Create(HDC hdcCompatible, int width, int height){	// if hdcMemory isn't null, blow it up!	if(hdcMemory)		Destroy();	// create the memory dc.	hdcMemory = CreateCompatibleDC(hdcCompatible);	// create the bitmap	hbmNewBitMap = CreateCompatibleBitmap(hdcCompatible, width, height);	// shove the image into the dc	hbmOldBitMap = (HBITMAP)SelectObject(hdcMemory, hbmNewBitMap);	// change the width and height.	iWidth = width;	iHeight = height;}void BitMapObject::Destroy(){	// restore old bitmap	SelectObject(hdcMemory, hbmOldBitMap);	// delete new bitmap.	DeleteObject(hbmNewBitMap);	// delete device context.	DeleteDC(hdcMemory);	//set members to 0/NULL	hdcMemory = NULL;	hbmNewBitMap = NULL;	hbmOldBitMap = NULL;	iWidth = 0;	iHeight = 0;}BitMapObject::operator HDC(){	//return hdcMemory.	return(hdcMemory);}int BitMapObject::GetWidth(){	// return width	return(iWidth);}int BitMapObject::GetHeight(){	// return height	return(iHeight);}


I'm not going into too much detail about how things work. I went into more detail here on it, though not as much as I could have.

Anyway, you want to know the usage. Ok.

//BitMapObject named SpriteBitMapObject Sprite;//loads the bitmap sprite.bmp in the local directory for easy useSprite.Load(NULL,"sprite.bmp");//paints the image contained in Sprite with a width of 'x' and a height of 'y'BitBlt(0,0,x,y,Sprite,0,0,SRCPAINT);//unloads bitmap in memorySprite.Destroy();//...you won't use it as much but here's an exampleHDC hdc=GetDC(hWindowMain)Sprite.Create(hdc,x,y); //creates a 'blank' sprite of width 'x' and height 'y'ReleaseDC(hWndMain, hdc);


-Greven
I'd say that bitmap class from the book could actually load all kinds of bitmaps, but it forces the bitmapheader_256 on all files, which simply won't work. As soon as there's something stored differently, it'll mix up the header with the bitmap data.

The loader code doesn't take care of all the nice extra thingies which might be inside a valid .bmp file.

I suggest Evil_Greven's class, looks pretty solid to me, and let's Windows handle everything.

Fruny: Ftagn! Ia! Ia! std::time_put_byname! Mglui naflftagn std::codecvt eY'ha-nthlei!,char,mbstate_t>

This topic is closed to new replies.

Advertisement