Sign in to follow this  
CyberSlag5k

Bitmaps off a bit

Recommended Posts

I have a bitmap class defined as follows:
struct Color3b
{
	unsigned char Red;
	unsigned char Green;
	unsigned char Blue;
};

class Bitmap
{
public:
	// Constructors and Init Method
	Bitmap(string fileName);
	Bitmap(const Bitmap& bitmap);
	void Init();

	// Destructor
	~Bitmap();

	// Operator Overloads
	Bitmap& operator = (const Bitmap& rhs);
	friend ostream& operator << (ostream& outStream, Bitmap outBitmap);

	// Methods
	void LoadFile(const string& fileName);
	void SaveFile(const string& fileName);

        // Accessors and Mutators removed for irrelevance
public:
	// Private Methods
	void Copy(const Bitmap& rhs);

	// Data Members
	short		m_Identifier;
	int			m_FileSize;
	int			m_Reserved;
	int			m_DataOffset;
	int			m_HeaderSize;
	int			m_Width;
	int			m_Height;
	short		m_Planes;
	short		m_BitsPerPixel;
	int			m_Compression;
	int			m_DataSize;
	int			m_hResolution;
	int			m_vResolution;
	int			m_Colors;
	int			m_ImportantColors;
	int*		m_Palette;
	Color3b**	m_Data;
};

I use it to load texture data and height values for maps. At the moment I'm only using 24bpp bitmaps. However it seems to be a bit off at times. For example, I was testing something so I created a simple 9 pixel bitmap, where the 8 border pixesl were black and the center pixel was green (green is positive, blue is negative for my heightmaps). The map that was loaded had the following green channel: 0 0 0 0 0 1 0 0 0 where it should have been: 0 0 0 0 1 0 0 0 0 Ok, I thought, I was off by 3 bytes. No biggie, I thought, so I did a seekg to point 57 (I normally read the data from point 57). It worked for that bitmap, but it threw off others. So I'm thinking I'm not taking something into consideration with regards to where the data is stored. Here is the method that I use to read in the data:
void Bitmap::LoadFile(const string& fileName)
{
	ifstream loadFile;
	loadFile.open(fileName.c_str(), ios::binary);
	
	if(loadFile.is_open())
	{
		loadFile.seekg(0);
		loadFile.read((char*)&m_Identifier, 2);
		loadFile.read((char*)&m_FileSize, 4);
		loadFile.read((char*)&m_Reserved, 4);
		loadFile.read((char*)&m_DataOffset, 4);
		loadFile.read((char*)&m_HeaderSize, 4);
		loadFile.read((char*)&m_Width, 4);
		loadFile.read((char*)&m_Height, 4);
		loadFile.read((char*)&m_Planes, 2);
		loadFile.read((char*)&m_BitsPerPixel, 2);
		loadFile.read((char*)&m_Compression, 4);
		loadFile.read((char*)&m_DataSize, 4);
		loadFile.read((char*)&m_hResolution, 4);
		loadFile.read((char*)&m_vResolution, 4);
		loadFile.read((char*)&m_Colors, 4);
		loadFile.read((char*)&m_ImportantColors, 4);
		loadFile.seekg(54);

		if(m_BitsPerPixel == 24)
		{
			m_Palette = NULL;

			m_Data = new Color3b*[m_Width];
			for(int i = 0; i < m_Width; i++)
			{
				m_Data[i] = new Color3b[m_Height];
				for(int j = 0; j < m_Height; j++)
				{
					loadFile.read((char*)&m_Data[i][j].Blue, 1);
					loadFile.read((char*)&m_Data[i][j].Green, 1);
					loadFile.read((char*)&m_Data[i][j].Red, 1);
				}
			}
		}
		else
		{
			string message ("Incompatable bitmap " + fileName);
			throw(exception(message.c_str()));
		}


	}
	else
	{
		string message("Could not open file " + fileName);
		throw(exception(message.c_str()));
	}
	
	loadFile.close();
}

Does that look ok? From my understanding, if it's a 24-bpp bitmap, there shouldn't be any palette data, and that's the only thing I'm not reading in according to the bitmap file formats I found online. The compression is also set to 0 for all of the bitmaps I'm using. So can anyone see why I'm off by 3 bytes on some bitmaps, but not on others? Thanks!

Share this post


Link to post
Share on other sites
Every row of a BMP file is aligned to a 32-bit boundary. If the size of a row doesn't add up to a multiple of 32-bits, then the end of the row is padded with 0s until it does. It doesn't look like you are accounting for this in your loader.

Using your example of a 3x3 24-bit BMP file, the length of a row in bits is 3 pixels * 24 bpp = 72 bits which is not a multiple of 32. The next highest multiple is 96, the difference of which just happens to be 24 bits, which is the size of one pixel, which is why your image appears to be one pixel off.

So the image data in the file is laid out like this, where p is the padding...
   0 0 0 p
0 1 0 p
0 0 0 p
but when you read it in without taking the padding (which happens to be the same size as a pixel in this case) into account you're storing it as...
   0 0 0
p 0 1
0 p 0
and the rest of the image data is ignored.

Share this post


Link to post
Share on other sites
I was not aware of that.

This is the change I made that fixed it, for anyone's future reference:


char pad[4];
int padSize;
if(m_BitsPerPixel == 24)
{
m_Palette = NULL;

m_Data = new Color3b*[m_Width];
for(int i = 0; i < m_Width; i++)
{
m_Data[i] = new Color3b[m_Height];
for(int j = 0; j < m_Height; j++)
{
loadFile.read((char*)&m_Data[i][j].Blue, 1);
loadFile.read((char*)&m_Data[i][j].Green, 1);
loadFile.read((char*)&m_Data[i][j].Red, 1);
}
padSize = 32 - ((m_Width * 24) % 32);
if(padSize > 0 && padSize < 32)
loadFile.read(pad, padSize / 8);
}
}



Thanks, Kalidor!

Share this post


Link to post
Share on other sites
Sorry to revive a 3-week old post, but rather than create a new one describing the situation, I thought I'd just re-use the existing one.

Anyway, I've corrected the row-padding issue, as Kalidor explained, but I'm still experiencing anomalies with some bitmaps. Is there perhaps a column-pad that exists as well? I'm seeing a horizontal line in a 5x6 pixel bitmap of black pixels stretching across my bitmap. If such a pad exists, is it 32 bits as well? I tried accounting for such a pad, but the problem persists.

Basically, a bitmap that should be entirely green looks like this:

GBGGGG
GGBGGG
GGGBGG
GGGGBG
GGGGGB

Where the G's are green pixels and the B's are black pixels. The current bitmap loading method is as follows:


void Bitmap::LoadFile(const string& fileName)
{
ifstream loadFile;
loadFile.open(fileName.c_str(), ios::binary);

if(loadFile.is_open())
{
loadFile.seekg(0);
loadFile.read((char*)&m_Identifier, 2);
loadFile.read((char*)&m_FileSize, 4);
loadFile.read((char*)&m_Reserved, 4);
loadFile.read((char*)&m_DataOffset, 4);
loadFile.read((char*)&m_HeaderSize, 4);
loadFile.read((char*)&m_Width, 4);
loadFile.read((char*)&m_Height, 4);
loadFile.read((char*)&m_Planes, 2);
loadFile.read((char*)&m_BitsPerPixel, 2);
loadFile.read((char*)&m_Compression, 4);
loadFile.read((char*)&m_DataSize, 4);
loadFile.read((char*)&m_hResolution, 4);
loadFile.read((char*)&m_vResolution, 4);
loadFile.read((char*)&m_Colors, 4);
loadFile.read((char*)&m_ImportantColors, 4);
// loadFile.seekg(54);

char pad[4];
int padSize;
if(m_BitsPerPixel == 24)
{
m_Palette = NULL;

m_Data = new Color3b*[m_Width];
for(int i = 0; i < m_Width; i++)
{
m_Data[i] = new Color3b[m_Height];
for(int j = 0; j < m_Height; j++)
{
loadFile.read((char*)&m_Data[i][j].Blue, 1);
loadFile.read((char*)&m_Data[i][j].Green, 1);
loadFile.read((char*)&m_Data[i][j].Red, 1);
}
padSize = 32 - ((m_Width * 24) % 32);
if(padSize > 0 && padSize < 32)
loadFile.read(pad, padSize / 8);
}
//padSize = 32 - ((m_Height * 24) % 32);
//if(padSize > 0 && padSize < 32)
// loadFile.read(pad, padSize / 8);
}
else
{
string message ("Incompatable bitmap " + fileName);
throw(exception(message.c_str()));
}
}
else
{
string message("Could not open file " + fileName);
throw(exception(message.c_str()));
}

loadFile.close();
}




Does that look right? Again, this happens with some bitmaps, but not all, so I'm thinking it is a similar issue.

Share this post


Link to post
Share on other sites
Thank you for your response, Endurion.

Sorry for the late response. I meant to try out switching the height and width, and then report how it went, but I just haven't had time. I'll get to it next week some time and post how it works out.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this