help! odd bitmap loading

Started by
11 comments, last by timaer 18 years, 1 month ago
I've tried to load a 24bit bitmap to the primary surface,but whenever I set the bitmap_width odd number,the bitmap would be disordered.To the contrary ,after I set the bitmap_width even,It can be display correctly. I've tested that the bitmap_height seems no relation with this problem.Anyone could give me some advice? thanks! some crucial code is below: lpddsprimary->Lock(NULL,&ddsd, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT,NULL); // get video pointer to primary surfce DWORD *primary_buffer = (DWORD *)ddsd.lpSurface; // process each line and copy it into the primary buffer for (int index_y = 0; index_y < bitmap_height; index_y++) { for (int index_x = 0; index_x < bitmap_width; index_x++) { // get BGR values UCHAR blue = (bitmap.buffer[index_y*bitmap_width*3 + index_x*3 + 0]), green = (bitmap.buffer[index_y*bitmap_width*3 + index_x*3 + 1]), red = (bitmap.buffer[index_y*bitmap_width*3 + index_x*3 + 2]); // this builds a 32 bit color value in A.8.8.8 format (8-bit alpha mode) DWORD pixel = _RGB32BIT(0,red,green,blue); // write the pixel primary_buffer[index_x + (index_y*ddsd.lPitch >> 2)] = pixel; } // end for index_x } // end for index_y // now unlock the primary surface if (FAILED(lpddsprimary->Unlock(NULL))) return(0);
Advertisement
Did you take the line padding in account?

The bitmap data in Windows bitmaps is padded to full 32 bits per line. If the line with (in bytes) is not divisible by 4 the data is padded. This data can be discarded on loading.

Also, when you're using D3DFMT_A8R8G8B8 consider setting alpha to 255 instead of 0.

Your copy code looks ok so far.

Fruny: Ftagn! Ia! Ia! std::time_put_byname! Mglui naflftagn std::codecvt eY'ha-nthlei!,char,mbstate_t>

Thank you so much,Endurion.I know your meaning,and I guess that's the key to resolve this problem.but I don't how to do it.

As you mentioned,windows need one line's total bytes be divisible by 4,so I can set the 24bit bitmap_width such as 20,40,60 pixel,since one line 20*3byte ,40*3byte,60*3byte all can be divisible by 4.

so,what if I need setting the bitmap_width such as 10,30,50,in that case,10*3byte ,30*3byte and 50*3byte can't be divisible by 4,what should I do to avoid losing data?
You do the changes in the loading routine. If your 24bit bitmap has a width of 10 pixels, the bitmap data in one line equals 3 byte * 10 pixel = 30 bytes.

So you read 30 bytes into your bitmap buffer. Following in the file are 2 padding bytes (to make 32 bytes). Simply skip them in the loading routine (read 2 bytes but don't do anything with them). Continue with the next line.

This boils down that you may have to change the reading from one big block of memory into the single lines.

Fruny: Ftagn! Ia! Ia! std::time_put_byname! Mglui naflftagn std::codecvt eY'ha-nthlei!,char,mbstate_t>

thanks ,Endurion.I tried to skip reading the padding 2 byte,but the bitmap was still displayed disorderly.

my revised sample code is below:(Assume that I need to draw a 10*10 pixel bitmap)

for (int index_y = 0; index_y < 10; index_y++)
{
for (int index_x = 0; index_x < 10; index_x++)
{

UCHAR blue = (bitmap.buffer[index_y*(10*3+2) + index_x*3 + 0]),
green = (bitmap.buffer[index_y*(10*3+2) + index_x*3 + 1]),
red = (bitmap.buffer[index_y*(10*3+2) + index_x*3 + 2]);


DWORD pixel = _RGB32BIT(0,red,green,blue);


primary_buffer[index_x + (index_y*ddsd.lPitch >> 2)] = pixel;

}

}

Is there anything wrong with my code?:(
It looks ok. I would separate the drawing from the loading even more though (right now your drawing code needs to be specialized for the bitmap size).

How do you fill your bitmap.buffer? A full block read?

If you did skip the bytes on reading into bitmap.buffer already you do not need to skip them again in the drawing code.

Fruny: Ftagn! Ia! Ia! std::time_put_byname! Mglui naflftagn std::codecvt eY'ha-nthlei!,char,mbstate_t>

Your message is so helpful.Now I think the problem probably caused by the loading procedure.

I'm reading a book written by Andre Lamoth,and I've been using the Load_Bitmap_File function in the book's CD.Since I'm not aware that how windows loading bitmap file.

the function is below ,could you tell me how to revised it?

int Load_Bitmap_File(BITMAP_FILE_PTR bitmap, char *filename)
{
// this function opens a bitmap file and loads the data into bitmap

int file_handle, // the file handle
index; // looping index

UCHAR *temp_buffer = NULL; // used to convert 24 bit images to 16 bit
OFSTRUCT file_data; // the file data information

// open the file if it exists
if ((file_handle = OpenFile(filename,&file_data,OF_READ))==-1)
return(0);

// now load the bitmap file header
_lread(file_handle, &bitmap->bitmapfileheader,sizeof(BITMAPFILEHEADER));

// test if this is a bitmap file
if (bitmap->bitmapfileheader.bfType!=BITMAP_ID)
{
// close the file
_lclose(file_handle);

// return error
return(0);
} // end if

// now we know this is a bitmap, so read in all the sections

// first the bitmap infoheader

// now load the bitmap file header
_lread(file_handle, &bitmap->bitmapinfoheader,sizeof(BITMAPINFOHEADER));

// now load the color palette if there is one
if (bitmap->bitmapinfoheader.biBitCount == 8)
{
_lread(file_handle, &bitmap->palette,MAX_COLORS_PALETTE*sizeof(PALETTEENTRY));

// now set all the flags in the palette correctly and fix the reversed
// BGR RGBQUAD data format
for (index=0; index < MAX_COLORS_PALETTE; index++)
{
// reverse the red and green fields
int temp_color = bitmap->palette[index].peRed;
bitmap->palette[index].peRed = bitmap->palette[index].peBlue;
bitmap->palette[index].peBlue = temp_color;

// always set the flags word to this
bitmap->palette[index].peFlags = PC_NOCOLLAPSE;
} // end for index

} // end if

// finally the image data itself
_lseek(file_handle,-(int)(bitmap->bitmapinfoheader.biSizeImage),SEEK_END);

// now read in the image, if the image is 8 or 16 bit then simply read it
// but if its 24 bit then read it into a temporary area and then convert
// it to a 16 bit image

if (bitmap->bitmapinfoheader.biBitCount==8 || bitmap->bitmapinfoheader.biBitCount==16 ||
bitmap->bitmapinfoheader.biBitCount==24)
{
// delete the last image if there was one
if (bitmap->buffer)
free(bitmap->buffer);

// allocate the memory for the image
if (!(bitmap->buffer = (UCHAR *)malloc(bitmap->bitmapinfoheader.biSizeImage)))
{
// close the file
_lclose(file_handle);

// return error
return(0);
} // end if

// now read it in
_lread(file_handle,bitmap->buffer,bitmap->bitmapinfoheader.biSizeImage);

} // end if
else
{
// serious problem
return(0);

} // end else

#if 0
// write the file info out
printf("\nfilename:%s \nsize=%d \nwidth=%d \nheight=%d \nbitsperpixel=%d \ncolors=%d \nimpcolors=%d",
filename,
bitmap->bitmapinfoheader.biSizeImage,
bitmap->bitmapinfoheader.biWidth,
bitmap->bitmapinfoheader.biHeight,
bitmap->bitmapinfoheader.biBitCount,
bitmap->bitmapinfoheader.biClrUsed,
bitmap->bitmapinfoheader.biClrImportant);
#endif

// close the file
_lclose(file_handle);

// flip the bitmap
Flip_Bitmap(bitmap->buffer,
bitmap->bitmapinfoheader.biWidth*(bitmap->bitmapinfoheader.biBitCount/8),
bitmap->bitmapinfoheader.biHeight);

// return success
return(1);

} // end Load_Bitmap_File

plus:By the way,you metioned "A full block read",I guess that means in the loading procedure we can read data by block.Anyway,I can't figure out a method in drawing code to make it possible writing bitmap's data into direct surface by block(since before writting,data have to be encoded 32 bit format?)If you have any idea to make the drawing procedure faster ,I'll be glad to hear that.Thanks so much.
I'm having a problem loading my bitmaps too. I'm not using the same language as timaer. I'm using c++ and windows API. I have the resource done correctly and the pictures are bmp format. Everything in the code seems fine, but I think I may have to have the the size of the bitmap a certain width/height. Any idea what I did wrong? If you need to see the code I'll post it.
Whoever it was who decided that bitmaps must be both stored upside-down and with a line-pad.....
My idea would be along those lines.

A few comments: biSizeImage can be set to 0, it is a valid value. You could simply calculate the needed size yourself. Also note that biHeight might be negative to indicate flipped top-down (Therefore the abs).

// allocate the memory for the imagesize_t iNeededMemoryPerLine = bitmap->bitmapinfoheader.biWidth * bitmap->bitmapinfoheader.biBitCount / 8;size_t iNeededMemory = iNeededMemoryPerLine * abs( bitmap->bitmapinfoheader.biHeight );// Calculate padding bytes (this is not optimized but shows the way to think)size_t iTemp = iNeededMemoryPerLine;size_t iPaddingBytes = 0;while ( iTemp % 4 ){  ++iPaddingBytes;  ++iTemp;}if ( !( bitmap->buffer = (UCHAR*)malloc( iNeededMemory ) ) ){  // close the file  _lclose(file_handle);  // return error  return 0;}// now read it infor ( int i = 0; i < abs( bitmap->bitmapinfoheader.biHeight ); ++i ){  // read one line  _lread( file_handle, bitmap->buffer + i * iNeededMemoryPerLine, iNeededMemoryPerLine );  // skip padding if needed  _lseek( file_handle, iPaddingBytes, SEEK_CUR );}


Now that the padding is taken care of you can make the drawing code generic again:

lpddsprimary->Lock(NULL,&ddsd, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT,NULL);// get video pointer to primary surfceDWORD *primary_buffer = (DWORD *)ddsd.lpSurface; // process each line and copy it into the primary bufferfor (int index_y = 0; index_y < bitmap_height; index_y++){  for (int index_x = 0; index_x < bitmap_width; index_x++)  {    // get BGR values    UCHAR blue = (bitmap.buffer[index_y*bitmap_width*3 + index_x*3 + 0]),          green = (bitmap.buffer[index_y*bitmap_width*3 + index_x*3 + 1]),          red = (bitmap.buffer[index_y*bitmap_width*3 + index_x*3 + 2]);    // this builds a 32 bit color value in A.8.8.8 format (8-bit alpha mode)    DWORD pixel = _RGB32BIT(0,red,green,blue);    // write the pixel    primary_buffer[index_x + (index_y*ddsd.lPitch >> 2)] = pixel;  } // end for index_x} // end for index_y


If you want to optimize for direct screen copying you have to change the image data on loading to 32 bit already. Then you could do memcpy for the single lines which will speed the drawing up tremendously.

This is typed off my head, there may be errors inside (although i hope not).

Fruny: Ftagn! Ia! Ia! std::time_put_byname! Mglui naflftagn std::codecvt eY'ha-nthlei!,char,mbstate_t>

This topic is closed to new replies.

Advertisement