Hello,

I am making a program that deals with bitmap files and I want to try to load bitmap data manually. The issue is that I cannot find a good resource for exactly what bitmap files can contain. Wikipedia has a decent article, but it is missing some important information. For example, it only explains how BITMAPINFOHEADERs work, but I would need to know how all of them work. Also the examples on wikipedia show integers stored in a sort of interleaved-endianness... I am wondering if normal c-style stdio file io would accurately read these values. Basically I just need a bit of help filling out this class:

class BitmapImage
{
    struct{
        unsigned short headerField      :16;
        unsigned int fileSize           :32;
        unsigned short reserved1        :16;
        unsigned short reserved2        :16;
        unsigned int startAddress       :32;
    }BitmapFileHeader;
    struct{
        //probably a union of the different possible header structs???
    }DIBHeader;
    struct{

    }ExtraBitMasks;
    struct{

    }ColourTable;
    unsigned int gap1,gap2;
    struct{

    }PixelArray;
    struct{

    }ICCColourProfile;
    public:
    void LoadBMP(FILE*);
    void SaveBMP(FILE*);
    int width();
    int height();
    unsigned int &operator()(int x, int y);//pixel access
    unsigned int alphaMask();
    unsigned int redMask();
    unsigned int greenMask();
    unsigned int blueMask();
    unsigned int bpp();
};

Thanks.

Recommended Answers

All 6 Replies

There really isn't any formal definition of the format, unfortunately, at least not one that Microsoft has seen fit to share with anyone. Their own recommendation is to always use their library functions to manipulate BMPs, and any other approach is likely to be incomplete, as they deliberately keep the full details from other programmers - and a full implementation might be in violation of one or more patents, either Microsoft's own or ones they have licensed. Who knows? MS isn't telling...

My recommendation is to look into the code for libbmp. It's probably the best resource available on the format outside of Microsoft themselves.

I'm guessing you've seen these links already, but in case you haven't, here are some resources to follow up on:

The libbmp repository (probably the closest thing to a complete 3rd party implementation):
https://code.google.com/p/libbmp/

Official MS documentation:
http://msdn.microsoft.com/en-us/library/dd183391.aspx
http://msdn.microsoft.com/en-us/library/dd183386.aspx
http://msdn.microsoft.com/en-us/library/dd183383.aspx

DDJ article on the format:
http://www.drdobbs.com/architecture-and-design/the-bmp-file-format-part-1/184409517
http://www.drdobbs.com/the-bmp-file-format-part-2/184409533?pgno=5

Other links:
http://www.fileformat.info/format/bmp/egff.htm
http://www.faqs.org/faqs/graphics/fileformats-faq/part3/section-18.html

Oops, I forgot to say, while you certainly can use the C-style file functions, I don't think there is any reason why you can't use the C++ iostreams as well. While the C++ I/O may require some additional effort to get it to do what you want, it actually is more flexible than the C functions are. Either way, just remember to open the file as binary rather than the default text mode.

If it helps any, here is what I've come up with so far in implementing your class:

bitmap.h

#ifndef BITMAP_H
#define BITMAP_H 1

#include <exception>
#include <iostream>
#include <iomanip>
#include <fstream>


const unsigned short BMP_MAGIC = 0x4D42;

class bmp_format_exception : public std::exception
{
public:
    virtual const char* what() const throw()
    {
        return "Bitmap format not valid.";
    }
};


class file_write_exception : public std::exception
{
public:
    virtual const char* what() const throw()
    {
        return "Unable to write to file.";
    }
};


class BitmapImage
{
    struct
    {
        unsigned short headerField;
        unsigned int fileSize;
        unsigned short reserved1;
        unsigned short reserved2;
        unsigned int startAddress;
    } BitmapFileHeader;
    struct
    {
        //probably a union of the different possible header structs???
    } DIBHeader;
    struct
    {

    } ExtraBitMasks;
    struct
    {

    } ColourTable;
    unsigned int gap1,gap2;
    struct
    {

    } PixelArray;
    struct
    {

    } ICCColourProfile;
public:

    friend std::istream& operator>>(std::istream& is, BitmapImage& bmp)  throw(bmp_format_exception);
    friend std::ostream& operator<<(std::ostream& os, BitmapImage& bmp)  throw(file_write_exception);
    void printHeaders();    // used mainly for debugging purposes
    int width();
    int height();
    unsigned int &operator()(int x, int y);//pixel access
    unsigned int alphaMask();
    unsigned int redMask();
    unsigned int greenMask();
    unsigned int blueMask();
    unsigned int bpp();
};

std::istream& operator>>(std::istream& is, BitmapImage& bmp)  throw(bmp_format_exception);
std::ostream& operator<<(std::ostream& os, BitmapImage& bmp)  throw(file_write_exception);
#endif

bitmap.cpp

#include <iostream>
#include <iomanip>
#include "bitmap.h"

unsigned short char2short(unsigned char upper, unsigned  char lower);
unsigned int char2word(unsigned char upper, unsigned char middle, unsigned char lower, unsigned char lowest);

inline unsigned short char2short(unsigned char upper, unsigned char lower)
{
    return (static_cast<unsigned short>(lower) << 8) | static_cast<unsigned short>(upper);
}


inline unsigned int char2word(unsigned char upper, unsigned char middle, unsigned char lower, unsigned char lowest)
{
    return (static_cast<unsigned int>(char2short(lower, lowest)) << 16 | static_cast<unsigned int>(char2short(upper, middle)));
}


void BitmapImage::printHeaders()
{
    std::cout << "File type: 0x"
              << std::setw(4) << std::setfill('0') << std::hex
              << BitmapFileHeader.headerField << std::endl;
    std::cout << "File Size: " << std::dec
              << BitmapFileHeader.fileSize << std::endl;
    std::cout << "Start Address: 0x"
              << std::setw(8) << std::setfill('0') << std::hex
              << BitmapFileHeader.startAddress << std::endl;
}

std::istream& operator>>(std::istream& is, BitmapImage& bmp) throw(bmp_format_exception)
{
    char main_header[14];

    is.read(main_header, 14);
    bmp.BitmapFileHeader.headerField = char2short(main_header[0], main_header[1]);

    if (!is.good() || bmp.BitmapFileHeader.headerField != BMP_MAGIC)
    {
        std::cout << std::hex << bmp.BitmapFileHeader.headerField << std::endl;
        throw bmp_format_exception(); // not a legitimate bitmap file, exit
    }

    bmp.BitmapFileHeader.fileSize      = char2word(main_header[2], main_header[3], main_header[4], main_header[5]);
    bmp.BitmapFileHeader.reserved1     = char2short(main_header[6], main_header[7]);
    bmp.BitmapFileHeader.reserved2     = char2short(main_header[8], main_header[9]);
    bmp.BitmapFileHeader.startAddress  = char2word(main_header[10], main_header[11], main_header[12], main_header[13]);

    // so far, only the first header is implemented
    return is;
}

I've also come up with a short test program to check the correctness of this:

bmptest.cpp

#include <iostream>
#include <fstream>
#include <iomanip>
#include <string>
#include <cstdlib>
#include "bitmap.h"

using namespace std;

int main()
{
    BitmapImage bmp;
    string filename;

    cout << "Enter the name of the file to review: ";
    cin >> filename;

    ifstream in(filename, ios_base::in | ios_base::binary);

    if (!in.good() || in.eof())
    {
        cout << "Could not open file.";
        exit(-1);
    }

    in >> bmp;

    bmp.printHeaders();

    in.seekg(0);

    cout << "Dump of the header: ";

    for (int i = 0; i < 14; i++)
    {
        unsigned char b;
        in >> b;
        cout << setw(2) << setfill('0') << hex << static_cast<unsigned int>(b) << ' ';
    }
    cout << endl;

    return 0;
}

HTH.

Ok. Thank you for your code, but it seems as though you are correct in that it is very hard to be able to read ANY bitmap file. Instead of going through all of this hassle I think it might be better to just use a library that can load more image types. I just have no idea which image library to use for easy, fast access to the individual pixels in an image. Any suggestions?

Hmmn. Can you go into more detail about what you are trying to do? It is very unusual to need (or even want) pixel per pixel access to the a bitmap, and the particualr goal is important. Are you trying to alter the image as it is loaded into video memory, or the file, and if the former, do you need to save it back to the file again later? Put another way, is this a matter of editing the file, or of modifying the image as it is shown, or both?

I'll assume that this is under Windows; I know you don't use Macs, and under Linux you would use libbmp, as previously mentioned.

If you need pixel access to an image being displayed, then it doesn't matter what sort of file it came from; you would use GetDIBits() and SetDIBits() if you are working with the GDI library directly, or else you could use the Bitmap class of the GDI+ class library, which has the methods GetPixel() and SetPixel() for this purpose. (I am assuming you want to avoid C++/CLI.)

Even with Windows, libbmp is an option, if you are using MinGW and GCC. That may be the easier solution, as the library is platform-independent and avoids a lot of the details of Windows image handling that you would otherwise be facing. Note that it only works with uncompressed files, AFAIK. The bmp_get_pixel() and bmp_set_pixel() functions should make for rather simple operations.

I intend to make a program that will hide a message in the parity of each pixel's colour of an image. As such I need access to the actual pixels and ability to write the image back to the file when I am done. The libbmp looks promising! Although it would be nice if I could get per-pixel access to other file types too (even though for some per-pixel access makes very little sense). Thanks. :)

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.