C reading bmp files

c bmp
Covertpyro picture Covertpyro · Nov 2, 2013 · Viewed 7.6k times · Source

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;
}

Answer

unwind picture unwind · Nov 2, 2013

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.