Skip to main content
GameDev.net gamedev.net
🔒 Locked

pitch in a windows 24bit bmp

Started by serratemplar Jul 18, 2004 at 2:11 AM 14 replies 2.8k views
Original Post
serratemplar
serratemplar
Does anyone know how a 24bit windows BMP file gets padded at the end of every line? There is no member of BITMAPFILEHEADER or BITMAPFILEINFO that gives you the lPitch, and I can't find it any documented anywhere on msdn.com.
chadmv
chadmv
I don't think BMP's themselves are padded. lpitch is a member of the surface struct, DDSURFACEDESC2. So when you copy the bitmap to the service you can manually add 8 bits of padding to the color WORD since many graphics cards don't support 24-bit graphics.
serratemplar
serratemplar
I'm doing that by using LONGs instead of WORDS...maybe I should just use words and write in a word, write in a zero byte....?
serratemplar
serratemplar
So how do I do that? My guess is each time I write the last pixel on a line (just after my nexted "X" loop finishes with x=biWidth), I check the width*sizeofWORD...and add to it in bytes whatever the remainder is of it %4?
Colin Jeanne
Colin Jeanne
Quote:
Original post by serratemplar
So how do I do that? My guess is each time I write the last pixel on a line (just after my nexted "X" loop finishes with x=biWidth), I check the width*sizeofWORD...and add to it in bytes whatever the remainder is of it %4?

I had a thead with a similar question.
Kippesoep
Kippesoep
pitch = (width * BytesPerPixel + 3) & ~3;
Kippesoep
serratemplar
serratemplar
Again, thanks for all of your help.

I tried the solution posed in that thread, Invader X and now (this is REALLY strange)...the bitmap is properly proportioned...but now there are THREE copies of it (!!!) one next to the other, and they are all minature, and all sitting in the top 1/3 of the space the bitmap should actually take up on screen. I have no guess as to what that could be. And now I am no closer to solving this =(
serratemplar
serratemplar
Kippesoep, I tried to use your pitch formula (which I presume you meant to use to read from the bitmap??) and I had no luck with that. No matter how I implement it, it just crashes the program.

My closest so far is the three little copies, which gives me a headache.
serratemplar
serratemplar
Not sure if anyone can figure this out, but here is my code, with all of the code people've pitched to me remarked out as well...

Thanks again everyone for your help.

#define _RGB32BIT(a,r,g,b) ((b) + ((g) << 8) + ((r) << 16) + ((a) << 24))typedef struct _DIBPIXEL{	BYTE blue, green, red;} DIBPIXEL, *LPDIBPIXEL;	LONG *video_buffer = reinterpret_cast<LONG*>(ddsd.lpSurface);	DIBPIXEL dibPixel; // stored in the bmp file, <b,g,r>		int width = m_Width*3;								//this solution gives me three mini-copies.	unsigned long padding = (4 - (width&3)) & ~4;		//ULONG pitch = bminfo.biSizeImage/m_Height;		// old solution, obsolete	//unsigned long pitch = (m_Width * bminfo.biBitCount + 3) & (~3); // Kippesoep's pitch		for (int y = 0; y < m_Height; y++)		for (int x = 0; x < m_Width; x++)		{			// three mini copies			dibPixel = *((DIBPIXEL*)(DataBuffer) + (x*3 + y * (width + padding)));			// one 1/3 tall copy			//dibPixel = *((DIBPIXEL*)((unsigned char*)DataBuffer) + (x + (m_Width + padding) * y) * 3);			// Kippesoep's proposed solution...			//dibPixel = *((DIBPIXEL*)((unsigned char*)DataBuffer) + (x + (pitch * y)));			// put it in the ddraw surface			(video_buffer[x+y*(ddsd.lPitch>>2)]) = _RGB32BIT(0, dibPixel.red, dibPixel.green, dibPixel.blue);		}
evillive2
evillive2
Not sure if this helps, but I have a bitmap class I use from time to time and here is the saving routine for it.

// here are the member variables of the class//////////////////////////////////////////////////BITMAPFILEHEADER m_bmfh; // file headerBITMAPINFOHEADER m_bmih; // info headerBYTE	*m_pbits; // array of bitsint	m_width; // width of bitmap in pixelsint	m_height; // height of bitmap 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;    }    // here is where I figure out how many bytes    // to pad onto the end of a scan line.    // basicly each scanline has to end on a DWORD    // or 4 byte block. By using the mod operator    // on the width of the bitmap * bytesperpixel    // I am left with the remaining bytes needed to    // end on a DWORD value.    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 scanline at a time    for ( y = m_height -1; y >=0; y-- )    {	fwrite( &m_pbits[y*m_width*3], sizeof(BYTE)*3, m_width, fp );        // add the scanline padding	fwrite( pad, sizeof(BYTE), pad_bytes, fp );    }    fclose(fp);}


I am sure there are better ways to do this but this is probably the most straight forward.

Hope it helps out.

Evillive2
serratemplar
serratemplar
Dude, you ROCK. I can't wait to try this out...I'll let you all know how it works.
serratemplar
serratemplar
Okay, so instead of trying to avoid the padbytes in my buffer, I've decided instead to try and initially load the bitmap while entirely avoiding the padbytes at the end of every scanline.

My guess was that, regardless of how many padbytes there were, so long as I start at the beginning of each scanline and read ONLY the pixel-data, I could just *not* read in the padbytes. I thought that might entirely avoid this problem.

Naturally, it's not working yet...but I'll be poking at it all day. If anyone has any thoughts on it, I wouldn't mind the advice.

Here's my new code to load the pixel data portion of the bmp file:

	m_FileToReadFrom.seekg(bmheader.bfOffBits, std::ifstream::beg);	LPDIBPIXEL DataBuffer = NULL;	DataBuffer = new DIBPIXEL[bminfo.biSizeImage];	//m_FileToReadFrom.read(reinterpret_cast<char*>(DataBuffer), bminfo.biSizeImage); // this loads entire file at once	for (int scanlines = 0; scanlines < m_Height; scanlines++)		m_FileToReadFrom.read(reinterpret_cast<char*>(DataBuffer) + (m_Width*3*scanlines), m_Width*3); // skip pad bytes!
serratemplar
serratemplar
in the BITMAPINFOHEADER, does the biSizeImage field take the padding into account?!? Because that would account for a great part of this weirdness if it does not. =)
evillive2
evillive2
I leave the BiSizeImage at 0. As a matter of fact, here is what my BITMAPINFOHEADER looks like:

	m_bmih.biWidth			= width;	m_bmih.biHeight			= height;	m_bmih.biPlanes			= 1;	m_bmih.biBitCount		= 24;	// only supports 24 bpp	m_bmih.biSizeImage		= 0;	m_bmih.biSize			= sizeof(m_bmih);	m_bmih.biXPelsPerMeter	= 0;	m_bmih.biYPelsPerMeter	= 0;	m_bmih.biClrUsed			= 0;	m_bmih.biClrImportant	= 0;


Now, to load a bitmap I have created, I use this:

void CDIBBMP::LoadFromFile( char *strFile ){    int y, pad_bytes;    BYTE pad[4] = {0,0,0,0};    FILE *fp = NULL;    if ( (fp = fopen( strFile, "rb" )) == NULL )    {	// error msg	return;    }    // read in the headers    fread( &m_bmfh, sizeof(m_bmfh), 1, fp );    fread( &m_bmih, sizeof(m_bmih), 1, fp );    m_width	= m_bmih.biWidth;    m_height	= m_bmih.biHeight;    // only supports 24 bpp    if ( m_bmih.biBitCount != 24 )    {	// error msg	return;    }    // create the array    // the byte array has no padding in it    m_pbits = new BYTE[m_width*m_height*3];    // the padding is still in there to throw us off    // so we need to figure out what kind of padding there is    if ( (pad_bytes = sizeof(BYTE)*m_width*3 % 4) )	pad_bytes = 4 - pad_bytes;    // Jump to the place the BITMAPFILEHEADER says the bitmap bits are    // don't want to assume anything here.    fseek( fp, m_bmfh.bfOffBits, SEEK_SET );    // bitmaps are saved upside down for some reason so we    // place the scanlines accordingly    for ( y = m_height -1; y >=0; y-- )    {	fread( &m_pbits[y*m_width*3], sizeof(BYTE)*3, m_width, fp );	// read the pad bytes to increment the file pointer 	// but we never use them anyway	// could just jump over the bytes with fseek	// but this tends to be more clear as to whats going on	fread( pad, sizeof(BYTE), pad_bytes, fp );    }    fclose(fp);}


I hope that helps.
Evillive2

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.