Hello, im a noob with C++ at the moment and Im trying to create a BMP image from pixel data stored in a array. Everything seems to work except that when i look at the file generated in a hex editor i get an extra '00 00' in between the BM identifier and the bytes reserved for the file size. It is as though the member short BM within the bmp_header struct is taking 4 bytes where i think i it is suppose to take 2 bytes. Could someone please explain why this is happening. Thanks in advance. (there are probably much more efficient ways of doing this but this is the way i want 2 do it at the moment)


Template is from http://en.wikipedia.org/wiki/BMP_file_format (the 2 by 2 pixel example)

#include <fstream>
#include <iostream>
using namespace std;

#define w_in_pix 2
#define h_in_pix 2
short padding = 0x0000;


struct bmp_header
{
       short BM;
       long size_of_file;
       long reserve;
       long offset_of_pixle_data;
       long size_of_header;
       long width;
       long hight;
       short num_of_colour_plane;
       short num_of_bit_per_pix;
       long compression;
       long size_of_pix_data;
       long h_resolution;
       long v_resolution;
       long num_of_colour_in_palette;
       long important_colours;
       
} 
HEADER;

// pix array ///////////////////////////////////////////////////////////////////////////
// L to R //
char BGR [12] = {
0xFF,0x00,0x00,   0x00,0xFF,0x00,
0x00,0x00,0xFF,   0xFF,0xFF,0xFF};
////////////////////////////////////////////////////////////////////////////////////////

int main()
{
    HEADER.BM = 0x4d42;
    HEADER.size_of_file =  sizeof(HEADER) + sizeof(BGR) + sizeof(padding) * h_in_pix;
    HEADER.reserve = 0000; 
    HEADER.offset_of_pixle_data = 54;
    HEADER.size_of_header = 40;
    HEADER.width = w_in_pix;
    HEADER.hight = h_in_pix;
    HEADER.num_of_colour_plane = 1;
    HEADER.num_of_bit_per_pix = 24;
    HEADER.compression = 0;
    HEADER.size_of_pix_data = sizeof(BGR) + sizeof(padding) * h_in_pix;
    HEADER.h_resolution = 2835;
    HEADER.v_resolution = 2835;
    HEADER.num_of_colour_in_palette = 0;
    HEADER.important_colours = 0;
    
    // write BMP Header ////////////////////////////////////////////////////////////////
    ofstream file;
    file.open ("test.bmp", ios::out | ios::trunc | ios::binary);
    file.write ((char*)(&HEADER), sizeof(HEADER));
    ////////////////////////////////////////////////////////////////////////////////////
    // write BMP data //////////////////////////////////////////////////////////////////
    //file.write ((char*)(&BGR[0]),1);
     
    
    int position = w_in_pix * h_in_pix * 3;
    while (position != 0)
    {
          for (int n = 0; n != w_in_pix * 3; n++)
          {
              file.write ((char*)(&BGR[position - w_in_pix * 3 + n]), 1);
          }
          file.write ((char*)(&padding), 2);
          position = position - w_in_pix * 3;
    } 
    
    
}

The short answer is padding and alignment.

> short BM;
> long size_of_file;
To ensure efficient access to size_of_file, the compiler inserts a pair of padding bytes after BM.

The common way to "fix" this is to use something like #pragma pack(1) , but there is no standard way to tell a compiler how to do this (or indeed how well your request for packing the struct will be met).

Also look up "endian-ess"

Unfortunately, the only good long-term answer (which is pretty horrible) is to read/write bytes one at a time, and assign them to the struct in the correct order.

Thanks 4 your help. Ill experiment with what you told me today

Yet another common and portable approach: use ordinar structures to create BMP info then pack them into the final char buffer (use memcpy(buffer+offset,&member,sizeof member), move offset forward and so on). Of course, it's possible to write data to a file stream directly (no need in current write pos forwarding).
Add some syntax sugar, for example:

struct bmp_header
{
       short BM;
       long size_of_file;
       long reserve;
       long offset_of_pixle_data;
       long size_of_header;
       long width;
       long hight;
       short num_of_colour_plane;
       short num_of_bit_per_pix;
       long compression;
       long size_of_pix_data;
       long h_resolution;
       long v_resolution;
       long num_of_colour_in_palette;
       long important_colours;
    void* pack(void* pbuf) {
        char* p = (char*)pbuf;
        int i = 0;
    # define PACK(member) {memcpy(p+i,&member,sizeof member);i+=sizeof member;}
        PACK(BM)
        PACK(size_of_file)
        ...
        PACK(important_colours)
    # undef PACK
        return pbuf;
    }
       
}
HEADER;
...
   HEADER.pack(buffer)

A nasty thing but it works ;)

Can i suggest you store the value of BM outside of the structure and store it in a char array of size 2 then write each one to the file before calling write() on the structure.

Chris

I did what freaky_chris suggested and created the value of BM outside of the bmp_header struct and it seems to work. Final code is now

#include <fstream>
#include <iostream>
using namespace std;

#define w_in_pix 2
#define h_in_pix 2
short padding = 0x0000;
short BM = 0x4d42;

struct bmp_header
{
       
       long size_of_file;
       long reserve;
       long offset_of_pixle_data;
       long size_of_header;
       long width;
       long hight;
       short num_of_colour_plane;
       short num_of_bit_per_pix;
       long compression;
       long size_of_pix_data;
       long h_resolution;
       long v_resolution;
       long num_of_colour_in_palette;
       long important_colours;
       
} 
HEADER;

// pix array ///////////////////////////////////////////////////////////////////////////
// L to R //
char BGR [12] = {
0xFF,0x00,0x00,   0x00,0xFF,0x00,
0x00,0x00,0xFF,   0xFF,0xFF,0xFF};
////////////////////////////////////////////////////////////////////////////////////////

int main()
{
    HEADER.size_of_file =  sizeof(HEADER) + sizeof(BGR) + sizeof(padding) * h_in_pix + 2;
    HEADER.reserve = 0000; 
    HEADER.offset_of_pixle_data = 54;
    HEADER.size_of_header = 40;
    HEADER.width = w_in_pix;
    HEADER.hight = h_in_pix;
    HEADER.num_of_colour_plane = 1;
    HEADER.num_of_bit_per_pix = 24;
    HEADER.compression = 0;
    HEADER.size_of_pix_data = sizeof(BGR) + sizeof(padding) * h_in_pix;
    HEADER.h_resolution = 2835;
    HEADER.v_resolution = 2835;
    HEADER.num_of_colour_in_palette = 0;
    HEADER.important_colours = 0;
    
    // write BMP Header ////////////////////////////////////////////////////////////////
    ofstream file;
    file.open ("test.bmp", ios::out | ios::trunc | ios::binary);
    file.write ((char*)(&BM), 2);
    file.write ((char*)(&HEADER), sizeof(HEADER));
    ////////////////////////////////////////////////////////////////////////////////////
    // write BMP data //////////////////////////////////////////////////////////////////
    //file.write ((char*)(&BGR[0]),1);
     
    
    int position = w_in_pix * h_in_pix * 3;
    while (position != 0)
    {
          for (int n = 0; n != w_in_pix * 3; n++)
          {
              file.write ((char*)(&BGR[position - w_in_pix * 3 + n]), 1);
          }
          file.write ((char*)(&padding), 2);
          position = position - w_in_pix * 3;
    } 
    
    
}

Thanks 4 all of ur help

Hi,

What I have to Change on the code to create a GrayScale 8bit bmp?

Thank you

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.