-
Loading a bmp file
I'm having trouble with this one, as easy as the format is, I'm doing something wrong. I have a function here to load a bmp file, taking the filename:
Code:
LIMAGE BMPLoader::loadBMP(const char* filename) {
struct {
unsigned short int type;
unsigned int filesize;
unsigned short int reserved;
unsigned short int reserved2;
unsigned int offset;
} header;
struct {
unsigned int headersize;
unsigned long int width, height;
unsigned short int planes;
unsigned short int bitsppx;
unsigned int compression, imagesize;
unsigned long int hres, vhres;
unsigned int numcolors, importantcols;
} infoheader;
unsigned char temp;
char* palette = 0;
char* imaged = 0;
LIMAGE image = {0, 0, 0, 0};
if (filename == 0) return image;
FILE* file = 0;
file = fopen(filename, "rb");
if (file == 0) return image;
fread(&header, sizeof(header), 1, file);
if (header.type != BMP_HEAD) {
fclose(file);
return image;
}
fread(&infoheader, sizeof(infoheader), 1, file);
if (infoheader.compression != 0) return image; // don't deal with compressed BMPs
image.bpp = infoheader.bitsppx;
image.width = infoheader.width;
image.height = infoheader.height;
if (infoheader.bitsppx < 16) {
palette = new char[infoheader.numcolors*4];
fread(palette, 1, infoheader.numcolors*4, file);
} else {
imaged = new char[(image.width*image.height)*(image.bpp/8)];
fseek(file, header.offset, SEEK_SET);
fread(imaged, 1, infoheader.imagesize, file);
}
/*for (int i=0;i<infoheader.imagesize;i+=3) {
temp = imaged[i];
imaged[i] = imaged[i+2];
imaged[i+2] = temp;
}*/
fclose(file);
image.image = imaged;
delete [] imaged;
return image;
}
LIMAGE is a struct defined in another header which contains 3 ints (bpp, height, width) and a char*, the actual image data. The commented out for loop causes a problem with memory therefore is commented out for now lol.. if you find something wrong with my function or structs or whatever tell me that'd be great, but my problem is, everything I read in (height, width, bpp, etc) gets assigned the value of these characters: ( then what looks like a b but the vertical line extends further downward and a ". Then I output the values to a file. as a decimal it came to 0 and as a string it came to ˜ý". Any idea why it's not reading values correctly? Thanks in advance
Note: the function isn't complete, it doesn't read in images with a bpp of less than 16. The image i used to test was 24 and because it doesn't read the value right it thinks it's less than 16.
-
I found that, when reading the Bitmap File Header and Bitmap Info Header (preceding the pixel data), that I could not read it all in as one header:
Code:
fread(&header, sizeof(header), 1, file);
Even though that is what everyone suggested, and it makes sense that it should work properly, I found I had to resort to reading every value in line by line:
Code:
void CompleteHeader(CUSTOMBITMAPHEADER *BitmapHeader, FILE *BinaryIFile)
{
fread(&(BitmapHeader->Type), sizeof(BitmapHeader->Type), 1, BinaryIFile);
fread(&(BitmapHeader->Size), sizeof(BitmapHeader->Size), 1, BinaryIFile);
fread(&(BitmapHeader->Reserved1), sizeof(BitmapHeader->Reserved1), 1, BinaryIFile);
fread(&(BitmapHeader->Reserved2), sizeof(BitmapHeader->Reserved2), 1, BinaryIFile);
fread(&(BitmapHeader->OffBits), sizeof(BitmapHeader->OffBits), 1, BinaryIFile);
fread(&(BitmapHeader->RemainingSize), sizeof(BitmapHeader->Size), 1, BinaryIFile);
fread(&(BitmapHeader->Width), sizeof(BitmapHeader->Width), 1, BinaryIFile);
fread(&(BitmapHeader->Height), sizeof(BitmapHeader->Height), 1, BinaryIFile);
fread(&(BitmapHeader->Planes), sizeof(BitmapHeader->Planes), 1, BinaryIFile);
fread(&(BitmapHeader->BitCount), sizeof(BitmapHeader->BitCount), 1, BinaryIFile);
fread(&(BitmapHeader->Compression), sizeof(BitmapHeader->Compression), 1, BinaryIFile);
fread(&(BitmapHeader->SizeImage), sizeof(BitmapHeader->SizeImage), 1, BinaryIFile);
fread(&(BitmapHeader->XPelsPerMeter), sizeof(BitmapHeader->XPelsPerMeter), 1, BinaryIFile);
fread(&(BitmapHeader->YPelsPerMeter), sizeof(BitmapHeader->YPelsPerMeter), 1, BinaryIFile);
fread(&(BitmapHeader->ClrUsed), sizeof(BitmapHeader->ClrUsed), 1, BinaryIFile);
fread(&(BitmapHeader->ClrImportant), sizeof(BitmapHeader->ClrImportant), 1, BinaryIFile);
}
Also, to avoid any dependancies on Windows.h (it seemed un-necessary to me), I just defined my own structure:
Code:
struct CUSTOMBITMAPHEADER
{
unsigned short Type;
unsigned long Size;
unsigned short Reserved1;
unsigned short Reserved2;
unsigned long OffBits;
unsigned long RemainingSize;
unsigned long Width;
unsigned long Height;
unsigned short Planes;
unsigned short BitCount;
unsigned long Compression;
unsigned long SizeImage;
unsigned long XPelsPerMeter;
unsigned long YPelsPerMeter;
unsigned long ClrUsed;
unsigned long ClrImportant;
};
A detailed description of the fields can be found on www.brackeen.com, in the VGA Tutorials (Bitmaps and Palettes) Section.
-
Yeah I'm avoiding windows dependencies because i wanna make a whole image loader to support multiple filetypes that I'm also gonna use on linux. Anyway, I'll try that and see what happens, thanks.
-
Your problem is the structure packing alignment. You need to consult your compiler documentation and determine how you can change the alignment to a 1 byte boundary.
-
> Even though that is what everyone suggested, and it makes sense that it should work properly
Indeed, your approach solves the alignment problem but it would still fall down on a machine with a different endian-ess. To fix that, you'd have to read the file one byte at a time and assemble each short/long by hand.
Since the OP is using dev-c++, then the struct packing can be achieved with
Code:
struct __attribute__ ((__packed__)) {
unsigned short int type;
unsigned int filesize;
unsigned short int reserved;
unsigned short int reserved2;
unsigned int offset;
} header;
You might want to check sizeof(header)==14 before trying to read the file, just to make sure that the struct is packed properly.