Archived

This topic is now archived and is closed to further replies.

Toolmaker

Saving a 24bit bitmap?

Recommended Posts

Ok, this might be a stupid question which, but I can't seem to get it right. I have been trying to save a 24bit BMP file friday, but it didn't work. So, I created the structs for the header, infoheader, even the RGBQUAD, although I don't use it(No palette). First I start out with filling the 2 headers up and write them to the file. However, there is a little problem that arises here. If I want to save a 50 * 50 pixel BMP, to what do I set the width? 50? or 3 * 50(because 1 pixel needs 3 bytes, right?). To check things, this is my code, any help is appreciated, since it didn't work friday.
struct BMPFILEHEADER
{
    WORD  bfType;
    DWORD bfSize;
    WORD  bfReserved1;
    WORD  bfReserved2;
    DWORD bfOffbits;
};

struct BMPINFOHEADER
{
  DWORD  biSize; 
  LONG   biWidth; 
  LONG   biHeight; 
  WORD   biPlanes; 
  WORD   biBitCount; 
  DWORD  biCompression; 
  DWORD  biSizeImage; 
  LONG   biXPelsPerMeter; 
  LONG   biYPelsPerMeter; 
  DWORD  biClrUsed; 
  DWORD  biClrImportant; 
};

//struct RGBQUAD

//{

//    BYTE Blue;

//    BYTE Green;

//    BYTE Red;

//    BYTE Reserved;

//};


BOOL WriteBitmap24(const char *szFile, BYTE *Surface, DWORD dwWidth, DWORD dwHeight)
{
    BMPFILEHEADER FileHeader;
    BMPINFOHEADER InfoHeader;
    BYTE V = 0;

    FileHeader.bfType      = 0x4D42; // It's a bitmap!

    FileHeader.bfSize      = sizeof(BMPFILEHEADER) + sizeof(BMPINFOHEADER) + (3 * dwWidth) * dwHeight;
    FileHeader.bfReserved1 = 0;
    FileHeader.bfReserved2 = 0;
    FileHeader.bfOffbits   = sizeof(BMPFILEHEADER) + sizeof(BMPINFOHEADER);

    InfoHeader.biSize          = sizeof(BMPINFOHEADER);
    InfoHeader.biWidth         = (long)dwWidth;
    InfoHeader.biHeight        = (long)dwHeight;
    InfoHeader.biPlanes        = 1;
    InfoHeader.biBitCount      = 24;
    InfoHeader.biCompression   = 0;
    InfoHeader.biSizeImage     = 3 * dwWidth * dwHeight;
    InfoHeader.biXPelsPerMeter = 0;
    InfoHeader.biYPelsPerMeter = 0;
    InfoHeader.biClrUsed       = 0;
    InfoHeader.biClrImportant  = 0;

    long dwPadWidth = dwWidth * 3;
    while ((dwWidth % 4) != 0)
        ++dwWidth;

    ofstream File(szFile, ios::binary);
    if (!File.is_open())
        return (FALSE);

    File.write((char *)&FileHeader, sizeof(BMPFILEHEADER));
    File.write((char *)&InfoHeader, sizeof(BMPINFOHEADER));
    for (int Vert = 0; Vert < dwHeight; ++Vert)
    {
        for (int Horz = 0; Horz < dwPadWidth; ++Horz)
        {
            if (Horz < dwPadWidth - dwWidth)
                File.write((char *)&Surface[Vert * dwHeight + Horz], sizeof(BYTE));
            else
                File.write((char *)&V, sizeof(BYTE));
        }
    }
    File.close();

    return (TRUE);
}

-Earth is 98% full. Please delete anybody you can. [edited by - toolmaker on April 5, 2004 9:16:39 AM]

Share this post


Link to post
Share on other sites
Shouldn''t this:

File.write((char *)Surface[Vert * dwHeight + Horz], sizeof(BYTE));

be this:

File.write((char *)&Surface[Vert * dwHeight + Horz], sizeof(BYTE));



"C lets you shoot yourself in the foot rather easily. C++ allows you to reuse the bullet!"

Share this post


Link to post
Share on other sites
Dont forget to write file in binary mode, as in windows you''ll get 2 chars when outputing ''/n'' otherwise.

______________________________
Madman

Share this post


Link to post
Share on other sites
quote:
Original post by CPPMaster Poppet
Shouldn''t this:

File.write((char *)Surface[Vert * dwHeight + Horz], sizeof(BYTE));

be this:

File.write((char *)&Surface[Vert * dwHeight + Horz], sizeof(BYTE));



I don''t think so, Surface is already a BYTE ptr. A pointer to pointer would get me weird output(I assume).

quote:

Dont forget to write file in binary mode, as in windows you''ll get 2 chars when outputing ''/n'' otherwise.



I won''t be writing \n characters to a bitmap file. But as you mentioned it, I saw I forgot it. So it was assuming I was writing in text mode(I think it''s text mode by default).

Other then that, are there logic errors in my code?

Toolmaker



-Earth is 98% full. Please delete anybody you can.

Share this post


Link to post
Share on other sites
quote:
Original post by Toolmaker I don''t think so, Surface is already a BYTE ptr.


yes, but you dereference it with []

Share this post


Link to post
Share on other sites
Good thinking

[EDIT]
I updated the above code. For some reason, I can''t write my BMP image to file. Can anyone find out why I doesn''t show up as a working bitmap? The above code is my entire header+source.

Toolmaker



-Earth is 98% full. Please delete anybody you can.

Share this post


Link to post
Share on other sites
I wrote a program based on a tutorial before for creating a 24 bit bitmap, throwing in some random pixels and writing it to a file and then counting how many unique 24 bit color values there were. The counting part I am sure was done really bad but you're welcome to the source code. Just email me if you are interested and you can have a look. I think that I used bits from This tutorial but leaving out the directdraw stuff.

[edit]
After looking at that tutorial, I don't think I used that one but for some reason it is in my bookmarks under bitmap stuff. Maybe I just used Big Sassy's tutorial on loading them but reversed the concepts. That seems to fit better since I prefer to use fopen instead of streams.

Evillive2
E-Mail

[edited by - evillive2 on April 5, 2004 7:33:43 PM]

Share this post


Link to post
Share on other sites
I noticed the file is 2 bytes bigger then when I save it from paint using the same size. How do I prevent MSVC from aligning on DWORDs?

Toolmaker



-Earth is 98% full. Please delete anybody you can.

Share this post


Link to post
Share on other sites
quote:
Original post by Toolmaker
I noticed the file is 2 bytes bigger then when I save it from paint using the same size. How do I prevent MSVC from aligning on DWORDs?



Here''s my code for the BMP header. Note the pragmas..


#pragma pack( push, BMP_Header )
#pragma pack(1)
struct BMP_Header
{
char B;
char M;
int SizeOfFile;
int Reserved;
int ImageOffset;

int SizeOfImageHeader;
int ImageWidth;
int ImageHeight;
short NumberOfPlanes;
short BitsPerPixel;
int CompressionType;
int CompressedImageSize;
int HorizontalResolution;
int VerticalResolution;
int NumberOfColoursInPalette;
int NumberOfMostImportantColours;
};
#pragma pack( pop, BMP_Header )


Share this post


Link to post
Share on other sites
I tested my code on a 16x16 BMP image and the output is weird indeed. I mem filled the data with RGB(0,0,255)(Blue) and then wrote it to file.

Except, the output was a mini bar graph, that had all 3 of the colors in it. I dunno why. What is wrong with my above code(Except that I now aligned the headers.

Toolmaker



-Earth is 98% full. Please delete anybody you can.

Share this post


Link to post
Share on other sites
Are you sure your surface is 24 bits? It''s just a byte pointer in your function, so there''s no hints to its actual structure, but what you''re describing could result from reading a 32 bit surface as a 24 bit surface.

Share this post


Link to post
Share on other sites
Here is the part of my DIB bitmap class that actually saves the DIB to a file. There are probably cleaner more flexible ways to do this but I know it saves a 24 bit bitmap that I can view in ms paint, the picture and fax viewer, paint shop pro and photoshop. I know it uses fopen/fwrite instead of streams but the concept is the same (I think).


// m_bmfh - bmp file header

// m_bmih - bmp info header

// m_width - bmp width in pixels

// m_height - bmp height in pixels


void CDIBBMP::SaveToFile( char *strFile )
{
FILE *fp = NULL;
int y, pad_bytes;
BYTE pad[4] = {0,0,0,0};

if ( (fp = fopen( strFile, "wb" )) == NULL )
{
// error msg

return;
}

if ( (pad_bytes = sizeof(BYTE)*m_width*3 % 4) )
pad_bytes = 4 - pad_bytes;

m_bmfh.bfSize = sizeof( m_bmfh ) + sizeof( m_bmih ) +
(sizeof(BYTE)*m_width*m_height*3) + (pad_bytes*m_height);
m_bmfh.bfOffBits = sizeof( m_bmfh ) + sizeof( m_bmih );
m_bmfh.bfType = ''MB'';
m_bmfh.bfReserved1 = 0;
m_bmfh.bfReserved2 = 0;

fwrite( &m_bmfh, sizeof(m_bmfh), 1, fp );
fwrite( &m_bmih, sizeof(m_bmih), 1, fp );

// bitmaps are saved upside down for some reason so we flip it

// and save one row at a time

for ( y = m_height -1; y >=0; y-- )
{
fwrite( &m_pbits[y*m_width*3], sizeof(BYTE)*3, m_width, fp );
fwrite( pad, sizeof(BYTE), pad_bytes, fp );
}

fclose(fp);
}


I hope that makes sense. If not, just ask and I think I can explain better.


Evillive2
E-Mail

Share this post


Link to post
Share on other sites