I'm trying to read in a bmp file to my program and I'm having some issues. After reading in the file if i tell it to print the pBmp->header.fileSize it says 16 but if i look at it in a hex editor the file size portion has F6 7A 10 00 if I modify the value to the correct file size in the hex it will say F6 7A F6 7A 10 00 but that is running into the resv1 which should always be zero. I know that this is only reading in 1 pixel of data another issue I have is when I try to use a while loop to read in the pixels until the end of file I get a segmentation fault. I've literally spent hours googling trying to figure this out but I'm not having much luck.
// The BMPHEADER structure.
typedef struct {
byte sigB;
byte sigM;
int32_t fileSize;
int16_t resv1;
int16_t resv2;
int32_t pixelOffset;
} tBmpHeader;
// The BMPINFOHEADER structure.
typedef struct {
int32_t size;
int32_t width;
int32_t height;
int16_t colorPlanes;
int16_t bitsPerPixel;
byte zeros[24];
} tBmpInfoHeader;
typedef uint8_t byte;
typedef struct {
byte blue;
byte green;
byte red;
} tPixel;
// A BMP image consists of the BMPHEADER and BMPINFOHEADER structures, and the 2D pixel array.
typedef struct {
tBmpHeader header;
tBmpInfoHeader infoHeader;
tPixel **pixel;
} tBmp;
tPixel **BmpPixelAlloc(int pWidth, int pHeight)
{
tPixel **pixels = (tPixel **)malloc (pHeight * sizeof(tPixel *));
for (int row = 0; row < pHeight; ++row)
{
pixels[row] = (tPixel *)malloc(pWidth * sizeof(tPixel));
}
printf("pixelAlloc\n");
return pixels;
}
pBmp->pixel = BmpPixelAlloc(pBmp->infoHeader.width, pBmp->infoHeader.height);
if(FileRead(file, &pBmp->pixel, sizeof(tPixel), 1)!=0)
{
errorCode = ErrorFileRead;
}
Check the padding of the structure for the header. You may find that the compiler has aligned the fileSize
value in the struct
to a 4-byte boundary within the structure. You can see this if you put in some debug printf
's of the structure element addresses.
I ran an example using your struct
here:
typedef struct {
byte sigB;
byte sigM;
int32_t fileSize;
int16_t resv1;
int16_t resv2;
int32_t pixelOffset;
} tBmpHeader;
tBmpHeader hdr;
int main(int argc, char *argv[])
{
printf("%d\n", sizeof(tBmpHeader) );
printf("%p hdr\n", &hdr);
printf("%p sigB\n", &hdr.sigB);
printf("%p sigM\n", &hdr.sigM);
printf("%p fileSize\n", &hdr.fileSize);
printf("%p resv1\n", &hdr.resv1);
printf("%p resv2\n", &hdr.resv2);
printf("%p pixelOffset\n", &hdr.pixelOffset);
}
With the output:
16
0x8049788 hdr
0x8049788 sigB
0x8049789 sigM
0x804978c fileSize
0x8049790 resv1
0x8049792 resv2
0x8049794 pixelOffset
There is a 4-byte offset between the beginning of hdr
and the fileSize
element, so there are two bytes of padding before fileSize
.
The thing to do is read the header a date item at a time. You can maintain some "structure" to the code by encapsulating the reads in a single function (e.g., "readBmpHeader(...)"). You can keep the struct
but read each field separately. So, you would do (I leave off the return value checks for clarity of example):
FileRead(file, &pBmp->header.sigB, sizeof(byte), 1)
FileRead(file, &pBmp->header.sigB, sizeof(byte), 1)
FileRead(file, &pBmp->header.fileSize, sizeof(int32_t), 1)
FileRead(file, &pBmp->header.resv1, sizeof(int16_t), 1)
FileRead(file, &pBmp->header.resv2, sizeof(int16_t), 1)
FileRead(file, &pBmp->header.pixelOffset, sizeof(int32_t), 1)