• Advertisement
Sign in to follow this  

Don't completely understand - Bitmap issue

This topic is 4791 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

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?

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
@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 file
Bitmap::Bitmap(HDC hDC, LPTSTR szFileName)
: m_hBitmap(NULL), m_iWidth(0), m_iHeight(0)
{
Create(hDC, szFileName);
}

// Create a bitmap from a resource
Bitmap::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 scratch
Bitmap::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]

Share this post


Link to post
Share on other sites
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?

Share this post


Link to post
Share on other sites
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 Sprite
BitMapObject Sprite;

//loads the bitmap sprite.bmp in the local directory for easy use
Sprite.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 memory
Sprite.Destroy();

//...you won't use it as much but here's an example
HDC hdc=GetDC(hWindowMain)
Sprite.Create(hdc,x,y); //creates a 'blank' sprite of width 'x' and height 'y'
ReleaseDC(hWndMain, hdc);




-Greven

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement