Working with Bitmaps
typedef struct tagBITMAPFILEHEADER
{ // bmfh
WORD bfType; // Specifies the file type.
// Must be 0x4D42 for .BMP
DWORD bfSize; // Specifies the size in bytes of
// the bitmap file.
WORD bfReserved1; //Reserved; must be zero.
WORD bfReserved2; // Reserved; must be zero.
DWORD bfOffBits; // Specifies the offset, in
// bytes, from the
// BITMAPFILEHEADER structure
// to the bitmap bits.
} BITMAPFILEHEADER;
typedef struct tagBITMAPINFO
{ // bmi
BITMAPINFOHEADER bmiHeader; // the info header
RGBQUAD bmiColors[1]; // palette (if there is one)
} BITMAPINFO;
typedef struct tagBITMAPINFOHEADER{ // bmih
DWORD biSize; // Specifies the number of
// bytes required by the structure.
LONG biWidth; // Specifies the width of the bitmap, in pixels.
LONG biHeight; // Specifies the height of the bitmap, in pixels.通过正负号可得知位图数据是否为“颠倒”的
// If biHeight is positive, the bitmap is a
// bottom-up DIB and its
// origin is the lower left corner
// If biHeight is negative, the bitmap
// is a top-down DIB and its origin is the upper left corner.
WORD biPlanes; // Specifies the number of color planes, must be 1.
WORD biBitCount // Specifies the number of bits per pixel. 可得知每像素的位数
// This value must be 1, 4, 8, 16, 24, or 32.
DWORD biCompression; // specifies type of compression (advanced)
// it will always be
// BI_RGB for uncompressed .BMPs
// which is what we're going to use
DWORD biSizeImage; // size of image in bytes
LONG biXPelsPerMeter; // specifies the number of
// pixels per meter in X-axis
LONG biYPelsPerMeter; // specifies the number of
// pixels per meter in Y-axis
DWORD biClrUsed; // specifies the number of
// colors used by the bitmap
DWORD biClrImportant; // specifies the number of
// colors that are important
} BITMAPINFOHEADER;
Note: 8-bit images will usually have the biClrUsed and biClrImportant fields both set to 256, while 16 and 24-bit images will set them to 0. Hence, always test the biBitCount to find out how many bits per pixel are used and go from there.
the palette entries are RGBQUAD, which are in reverse order of normal PALETTEENTRYs, so you have to convert them like this:
typedef struct tagRGBQUAD { // rgbq BYTE rgbBlue; // blue BYTE rgbGreen; // green BYTE rgbRed; // red BYTE rgbReserved; // unused } RGBQUAD;
HANDLE LoadImage( // A Win32 function HINSTANCE hinst, // handle of the instance that contains // the image: Set it to NULL LPCTSTR lpszName, // name or identifier of image: ANDRE.BMP UINT uType, // type of image: IMAGE_BITMAP int cxDesired, // desired width: 如果不为零,则缩放,推荐0 int cyDesired, // desired height UINT fuLoad ); // load flags:LR_LOADFROMFILE | LR_CREATEDIBSECTION
自己写的函数:
typedef struct BITMAP_FILE_TAG
{
BITMAPFILEHEADER bitmapfileheader; // this contains the
// bitmapfile header
BITMAPINFOHEADER bitmapinfoheader; // this is all the info
// including the palette
PALETTEENTRY palette[256];// we will store the palette here
UCHAR *buffer; // this is a pointer to the data
} BITMAP_FILE, *BITMAP_FILE_PTR;
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 (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
// 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_Fileint Flip_Bitmap(UCHAR *image, int bytes_per_line, int height)
{
// this function is used to flip bottom-up .BMP images
UCHAR *buffer; // used to perform the image processing
int index; // looping index
// allocate the temporary buffer
if (!(buffer = (UCHAR *)malloc(bytes_per_line*height)))
return(0);
// copy image to work area
memcpy(buffer,image,bytes_per_line*height);
// flip vertically
for (index=0; index < height; index++)
memcpy(&image[((height-1) - index)*bytes_per_line],
&buffer[index*bytes_per_line], bytes_per_line);
// release the memory
free(buffer);
// return success
return(1);
} // end Flip_Bitmapint Unload_Bitmap_File(BITMAP_FILE_PTR bitmap)
{
// this function releases all memory associated with "bitmap"
if (bitmap->buffer)
{
// release memory
free(bitmap->buffer);
// reset pointer
bitmap->buffer = NULL;
} // end if
// return success
return(1);
} // end Unload_Bitmap_File
1.Regardless of the image format, the buffer that holds the image UCHAR buffer is just a byte pointer, so you must do any casting or pointer arithmetic if the image is 16- or 24-bit.
2. the function allocates a buffer for the image, so the buffer must be released back to the operating system when you're done mucking with the image bits.
载入8位位图:使用该位图自己的调色板
BITMAP_FILE bitmap; // holds the 8-bit image
// given that the 8-bit image has been loaded
if (FAILED(lpddpal->SetEntries(0,0,MAX_COLORS_PALETTE,
bitmap.palette)))
{ /* error */ }
载入16位位图
very few paint programs can generate 16-bit .BMP files, so if you want to use a 16-bit DirectDraw mode, you may have to load a 24-bit bitmap and then manually convert the bits to 16-bit by using a color-scaling algorithm. In general, you would perform the following operations to convert a 24-bit image to a 16-bit image:
-
Create a buffer that's mxn WORDs, where each WORD is 16-bit. This will hold your 16-bit final image.
-
Access the image buffer after loading the 24-bit image into your BITMAP_FILE structure, and convert each 24-bit pixel to 16-bit by using the following crude color transform:
// each pixel in BITMAP_FILE.buffer[] is encoded as 3-bytes // in BGR order, or BLUE, GREEN, RED // assuming index is pointing to the next pixel... UCHAR blue = (bitmap.buffer[index*3 + 0]) >> 3, green = (bitmap.buffer[index*3 + 1]) >> 2, red = (bitmap.buffer[index*3 + 2]) >> 3; // build up 16 bit color word USHORT color = __RGB16BIT565(red,green,blue);
载入24位位图
Then BITMAP_FILE.buffer[] will hold the data in 3-byte pixels left to right, row by row, but in BGR (blue, green, red) format
// each pixel in BITMAP_FILE.buffer[] is encoded as 3-bytes // in BGR order, or BLUE, GREEN, RED // assuming index is pointing to the next pixel... UCHAR blue = (bitmap.buffer[index*3 + 0]), green = (bitmap.buffer[index*3 + 1]), red = (bitmap.buffer[index*3 + 2]); // this builds a 32 bit color value in A.8.8.8 format (8-bit alpha mode) _RGB32BIT(0,red,green,blue);
// this builds a 32 bit color value in A.8.8.8 format (8-bit alpha mode) #define _RGB32BIT(a,r,g,b) ((B) + ((g) << 8) + ((r) << 16) + ((a) << 24))