DaniWeb IT Discussion Community

DaniWeb IT Discussion Community (http://www.daniweb.com/forums/index.php)
-   C++ (http://www.daniweb.com/forums/forum8.html)
-   -   Help with manually creating a BMP image (http://www.daniweb.com/forums/thread165645.html)

BMPaul Jan 2nd, 2009 7:40 am
Help with manually creating a BMP image
 
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;
    }
   
   
}

Salem Jan 2nd, 2009 8:23 am
Re: Help with manually creating a BMP image
 
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.

BMPaul Jan 2nd, 2009 7:33 pm
Re: Help with manually creating a BMP image
 
Thanks 4 your help. Ill experiment with what you told me today

ArkM Jan 2nd, 2009 9:02 pm
Re: Help with manually creating a BMP image
 
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 ;)

Freaky_Chris Jan 3rd, 2009 5:58 am
Re: Help with manually creating a BMP image
 
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

BMPaul Jan 3rd, 2009 7:36 am
Re: Help with manually creating a BMP image
 
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;
    }
   
   
}

BMPaul Jan 3rd, 2009 7:37 am
Re: Help with manually creating a BMP image
 
Thanks 4 all of ur help


All times are GMT -4. The time now is 4:28 pm.

Forum system based on vBulletin Copyright ©2000 - 2009, Jelsoft Enterprises Ltd.
©2003 - 2009 DaniWeb® LLC