Question

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;
}
Was it helpful?

Solution 2

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)

OTHER TIPS

You should never use direct I/O with structures: just because you've declared your struct in the same order as the BMP headers, there's no guarantee that your compiler has the fields end-to-end with nothing in between.

Compilers frequently adhere to a platform's alignment restrictions, which might cause them to add padding bytes between fields to make sure e.g. a large field's starting address is aligned.

You need to either use compiler-specific magic to force the structure to be "packed", or byte-by-byte I/O into the structure.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top