BMP reading problems....

Started by
5 comments, last by Anon Mike 16 years ago
why doesn't this work, i played around with it for a while now, but the last fread is failing.....data is all zero's, which it's not. this line fails.... fread(data,size,1,fp); the header

#pragma once

struct BMP_HEADER
{
   //int Type;
   int bfSize;
   char bfReserved1;
   char bfReserved2;
   int bfOffBits;
};

struct BMP_INFO_HEADER {
    unsigned long biSize;
    long biWidth;
    long biHeight;
    unsigned short biPlanes;
    unsigned short biBitCount;
    unsigned short biCompression;
    unsigned short biSizeImage;
    short biXPelsPerMeter;
    short biYPelsPerMeter;
    unsigned long biClrUsed;
    unsigned long biClrImportant;
};

struct Color
{
	int r;
	int g;
	int b;
};

class BMP
{
public:

	BMP();
	~BMP();

	bool loadBMP(char *file);

	int getWidth();
	int getHeight();
	unsigned char *getData();

private:
	BMP_INFO_HEADER bmp_info;
	BMP_HEADER bmp_header;
	unsigned char *data;
};


the cpp file

#include "bmp.h"
#include <iostream>

using namespace std;

BMP::BMP()
{
	data = NULL;
}

BMP::~BMP()
{
	if(data)
		delete [] data;
}

bool BMP::loadBMP(char *file)
{
	if(data)
		delete [] data;

	FILE *fp = fopen(file,"r+");

	if(fp)
	{
		char bm[2] = {'B','M'};
		char tmp[2] = {0};
		fread(&tmp,1,2,fp);

		if(strcmp(bm,tmp))
		{
			fread(&bmp_header,1,sizeof(BMP_HEADER),fp);
			fread(&bmp_info,1,sizeof(BMP_INFO_HEADER),fp);

			//fseek(fp,bmp_header.bfOffBits,SEEK_SET);

			int size = bmp_info.biWidth*bmp_info.biHeight*3;
			//data = new unsigned char[size+1];
			//Color *c = new Color[size+1];
			data = new unsigned char[size+1];


			//fseek(fp,bmp_header.bfOffBits+1,SEEK_SET);

			if(bmp_info.biBitCount == 24)
			{
				fread(data,size,1,fp);

				for(int i = 0; i < size; i+=3)
				{
					/*data2[i+2] = (unsigned char)fgetc(fp);
					data2[i+1] = (unsigned char)fgetc(fp);
					data2 = (unsigned char)fgetc(fp);*/
					unsigned char temp=data;
					data=data[i+2];
					data[i+2]=temp;
				}
			}

			fclose(fp);

			return true;
		}
		else
			return false;
	}

	fclose(fp);

	return false;
}


int BMP::getWidth()
{
	return bmp_info.biWidth;
}

int BMP::getHeight()
{
	return bmp_info.biHeight;
}
unsigned char *BMP::getData()
{
	return data;
}


Advertisement
Obvious stuff...

1. You're not opening the file in binary mode, try "r+b" instead of "r+".
2. The check "strcmp(bm,tmp)" is operating on non-NULL terminated strings.
3. Your "size" calculation is completely wrong for anything other than 24bpp.
4. Even for 24bpp it's wrong because it doesn't take into account DWORD alignment.
5. You don't read in the color table, but it looks like you haven't completed that anyway.
-Mike
			fread(&bmp_header,1,sizeof(BMP_HEADER),fp);			fread(&bmp_info,1,sizeof(BMP_INFO_HEADER),fp);

Aswell as the problems pointed out by Anon Mike the above is probably another source of the problem as your structs are not packed.
For an example of the packing required see http://www.liamdevine.co.uk/code/bitmap.php the code is old and not the best but its free :)
Quote:Original post by Anon Mike
Obvious stuff...

1. You're not opening the file in binary mode, try "r+b" instead of "r+".
2. The check "strcmp(bm,tmp)" is operating on non-NULL terminated strings.
3. Your "size" calculation is completely wrong for anything other than 24bpp.
4. Even for 24bpp it's wrong because it doesn't take into account DWORD alignment.
5. You don't read in the color table, but it looks like you haven't completed that anyway.


what do you mean for 4 and 5?

i fixed the other ones.
Basically, padding causes the way the structure members are aligned in memory to differ from how they are aligned on disk. The fix is to tell your compiler to force byte alignment for structures you want to read or write.

How you do that is compiler-specific, unfortunately. Take a look at the code in dmail's link for an example.
Quote:Original post by 31337noob
Quote:Original post by Anon Mike
Obvious stuff...

1. You're not opening the file in binary mode, try "r+b" instead of "r+".
2. The check "strcmp(bm,tmp)" is operating on non-NULL terminated strings.
3. Your "size" calculation is completely wrong for anything other than 24bpp.
4. Even for 24bpp it's wrong because it doesn't take into account DWORD alignment.
5. You don't read in the color table, but it looks like you haven't completed that anyway.


what do you mean for 4 and 5?
4. Scanlines in a BMP file are aligned on a 4-byte boundary. If you have a 11px wide image, a scanline is 11*3 = 33 bytes, but the next scanline (row of pixels) has to start on a multiple of 4 bytes, so there'll be 3 bytes of padding at the end of that scanline.

5. BMP files have a colour table (palette) after the header, before the image data. The bfOffBits member is the offset to the start of the image data, which you should use instead of assuming the image data comes imediately after the header.
Right. The width of a scan line in bytes is:

stride = ((pixel_width * bpp + 31) & ~31) / 8

This is assuming nothing wierd (but legal) like RLE encoding or more than one plane.
-Mike

This topic is closed to new replies.

Advertisement