reading a .bmp file in c++
Asked Answered
L

3

8

I'm trying to load a bmp file for reusing it in opengl. I've found some code via google on how to load a bmp file. I took this code and put in a class Bitmap in my project. The class is far away from being finished but already the reading of the file headers goes wrong. After reading the bytes for INFOHEADER and FILEHEADER there aren't the right values in my structs. Some ideas?

//
//  Bitmap.h
//

#ifndef LaserMaze_Bitmap_h
#define LaserMaze_Bitmap_h

typedef struct                       /**** BMP file header structure ****/
{
    unsigned short bfType;           /* Magic number for file */
    unsigned int   bfSize;           /* Size of file */
    unsigned short bfReserved1;      /* Reserved */
    unsigned short bfReserved2;      /* ... */
    unsigned int   bfOffBits;        /* Offset to bitmap data */
} BITMAPFILEHEADER;

#  define BF_TYPE 0x4D42             /* "MB" */

typedef struct                       /**** BMP file info structure ****/
{
    unsigned int   biSize;           /* Size of info header */
    int            biWidth;          /* Width of image */
    int            biHeight;         /* Height of image */
    unsigned short biPlanes;         /* Number of color planes */
    unsigned short biBitCount;       /* Number of bits per pixel */
    unsigned int   biCompression;    /* Type of compression to use */
    unsigned int   biSizeImage;      /* Size of image data */
    int            biXPelsPerMeter;  /* X pixels per meter */
    int            biYPelsPerMeter;  /* Y pixels per meter */
    unsigned int   biClrUsed;        /* Number of colors used */
    unsigned int   biClrImportant;   /* Number of important colors */
} BITMAPINFOHEADER;

/*
 * Constants for the biCompression field...
 */

#  define BI_RGB       0             /* No compression - straight BGR data */
#  define BI_RLE8      1             /* 8-bit run-length compression */
#  define BI_RLE4      2             /* 4-bit run-length compression */
#  define BI_BITFIELDS 3             /* RGB bitmap with RGB masks */

typedef struct                       /**** Colormap entry structure ****/
{
    unsigned char  rgbBlue;          /* Blue value */
    unsigned char  rgbGreen;         /* Green value */
    unsigned char  rgbRed;           /* Red value */
    unsigned char  rgbReserved;      /* Reserved */
} RGBQUAD;

class Bitmap {
public:
    Bitmap(const char* filename);
    ~Bitmap();
    RGBQUAD* pixels;
    BITMAPFILEHEADER fh;
    BITMAPINFOHEADER ih;

    private:

};

#endif

the cpp

//  Bitmap.cpp
//

#include <iostream>
#include <stdio.h>

#include "Bitmap.h"

Bitmap::Bitmap(const char* filename) {
    FILE* file;
    file = fopen(filename, "rb");

    std::cout << sizeof(BITMAPFILEHEADER) << std::endl;

    if(file != NULL) { // file opened
        BITMAPFILEHEADER h;
        size_t x = fread(&h, sizeof(BITMAPFILEHEADER), 1, file); //reading the FILEHEADER

        std::cout << x;
        fread(&this->ih, sizeof(BITMAPINFOHEADER), 1, file);

        fclose(file);
    }
}
Loveliesbleeding answered 12/1, 2012 at 13:40 Comment(0)
B
15

The header needs to be 2 byte aligned.

#pragma pack(2) // Add this

typedef struct
{
    unsigned short bfType;
    unsigned int   bfSize;
    unsigned short bfReserved1;
    unsigned short bfReserved2;
    unsigned int   bfOffBits;
} BITMAPFILEHEADER;

#pragma pack() // and this
Barge answered 12/1, 2012 at 13:43 Comment(4)
worked well thanks :) maybe you can explain why this is necessary?Loveliesbleeding
Without the pragma, the short fields are being padded to 4 bytes. The size of BITMAPFILEHEADER (w/o pragma) is 20, but in the file it is written sequentially as 14 bytes. So two things happen: (1) the struct you read is messed up (2) you read too much, so reading BITMAPINFOHEADER starts 6 bytes too lateBarge
do I have to change the pack for BITMAPINFOHEADER also? There is also a short in the definitionLoveliesbleeding
You don't, because the two shorts are consecutive and the memory is alignedBarge
F
4

How about letting your Windows OS load it for you with LoadImage.

HBITMAP hbm = LoadImage( NULL, path, 0, 0, LR_LOADFROMFILE|LR_CREATEDIBSECTION);

Use GetObject() to find further info like size, etc. and GetDIBits() if you want to get at the individual bits.

Farah answered 12/1, 2012 at 13:49 Comment(1)
Yep. You didn't specify the OS so I assumed Windows. Ignore if that's not the case.Farah
C
0

BITMAPINFOHEADER :: You need to read first the biSize in order to know how large the info header is, you cannot rely on sizeof().

Check out this wiki article about the file format

Capsicum answered 12/1, 2012 at 13:46 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.