VC将HBITMAP转换成BMP位图文件的各个部分,可以在1BIT,4BIT,8BIT,16BIT,24BIT,32BIT之间转换<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />
2009.9.23
经过这段时间的努力,终于在VC下做成功了,将HBITMAP转换成BMP位图文件的各个部分,可以在1BIT,4BIT,8BIT,16BIT,24BIT,32BIT之间转换,但不能在彩色和灰度之间转换。
对GetDIBits()理解和试验了很多次。个人认为GetDIBits()需要HCD参数,可能是因为它需要HCD来做一些转换工作,但它又没有申请HCD,所以需要程序给它一个HCD。
改自MSDN2001,程序如下:
///////////////////////////////////////////////////////////////////////////////////////////////////////
BOOL myCreateBitmap( HDC hDC, HBITMAP hbitmap, int pixbit,
PBITMAPFILEHEADER &outheadbuf,long *outheadsize,
PBITMAPINFO &outinfobuf,long *outinfosize,
LPBYTE &outdatabuf,long *outdatasize)
//我:根据HDC和HBITMP,及自定义的"每像素比特数",来建立文件头、信息头、位图数据(改自MSDN)
//pixbit 是自定义的每像素BIT数 (如果为0,则按HBITMAP里的不变)
//输入hDC, hbitmap, pixbit
//输出文件头指针,文件头字节数,信息指针,信息字节数,位图数据指针,位图数据字节数
//函数会GlobalAlloc申请内存,主程序不用申请内存,但要GlobalFree掉内存
//成功时返回TRUE
{
BITMAP bmp;
WORD cClrBits;
DWORD my_biClrUsed=0;
outinfobuf=NULL;
outdatabuf=NULL;
outheadbuf=NULL;
if(pixbit!=0 && pixbit!=32 && pixbit!=24 && pixbit!=16 && pixbit!=8 && pixbit!=4 && pixbit!=1) goto errout;
// Retrieve the bitmap's color format, width, and height. 得到HBITMAP的信息
if (!GetObject(hbitmap, sizeof(BITMAP), (LPSTR)&bmp)) goto errout;
if (pixbit) //强制转换的位数
{bmp.bmPlanes=1; bmp.bmBitsPixel=pixbit; } //强制赋值转换出来的每像素BIT数
// Convert the color format to a count of bits.
cClrBits = (WORD)(bmp.bmPlanes * bmp.bmBitsPixel); //得到每像素多少位
if (cClrBits == 1) cClrBits = 1;
else if (cClrBits <= 4) cClrBits = 4;
else if (cClrBits <= 8) cClrBits = 8;
else if (cClrBits <= 16) cClrBits = 16;
else if (cClrBits <= 24) cClrBits = 24;
else cClrBits = 32;
// Allocate memory for the BITMAPINFO structure. (This structure
// contains a BITMAPINFOHEADER structure and an array of RGBQUAD
// data structures.)
if (cClrBits != 24)
{
*outinfosize= sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * (1<< cClrBits);
outinfobuf = (PBITMAPINFO) GlobalAlloc (GPTR, *outinfosize);
//分配内存大小,信息头+调色板大小
// There is no RGBQUAD array for the 24-bit-per-pixel format.
}
else //24BIT的,没有调色板
{
*outinfosize= sizeof(BITMAPINFOHEADER);
outinfobuf = (PBITMAPINFO) GlobalAlloc (GPTR, *outinfosize);
}
// Initialize the fields in the BITMAPINFO structure.
outinfobuf->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); //信息头大小(不含调色板)
outinfobuf->bmiHeader.biWidth = bmp.bmWidth;
outinfobuf->bmiHeader.biHeight = bmp.bmHeight;
outinfobuf->bmiHeader.biPlanes = bmp.bmPlanes;
outinfobuf->bmiHeader.biBitCount = bmp.bmBitsPixel;
if (cClrBits < 24)
{
my_biClrUsed=(1<<cClrBits);
outinfobuf->bmiHeader.biClrUsed = my_biClrUsed;
} //位图实际使用的彩色表中的颜色索引数
// If the bitmap is not compressed, set the BI_RGB flag.
outinfobuf->bmiHeader.biCompression = BI_RGB;
// Compute the number of bytes in the array of color
// indices and store the result in biSizeImage.
// For Windows NT/2000, the width must be DWORD aligned unless
// the bitmap is RLE compressed. This example shows this.
// For Windows 95/98, the width must be WORD aligned unless the
// bitmap is RLE compressed.
outinfobuf->bmiHeader.biSizeImage = ((outinfobuf->bmiHeader.biWidth * cClrBits +31) & ~31)\
/8 * outinfobuf->bmiHeader.biHeight;
//图像大小
// Set biClrImportant to 0, indicating that all of the
// device colors are important.
outinfobuf->bmiHeader.biClrImportant = 0;
/////////////////////////////////得到位图数据
// GlobalAlloc分配位图数据的内存
// GetDIBits 根据hDC 和HBITMAP得到位图数据、调色板数据
*outdatasize=outinfobuf->bmiHeader.biSizeImage;
outdatabuf = (LPBYTE) GlobalAlloc(GPTR, *outdatasize); //根据位图大小分配内存
if (!outdatabuf) goto errout;
// Retrieve the color table (RGBQUAD array) and the bits
// (array of palette indices) from the DIB.
if (!GetDIBits( //根据DC和BITMAP得到位图数据
hDC,
hbitmap,
0,
(WORD) outinfobuf->bmiHeader.biHeight,
outdatabuf, // outdatabuf中得到位图数据
outinfobuf,
DIB_RGB_COLORS) )
{ goto errout; }
//注意:GetDIBits()会更改outinfobuf->bmiHeader.biClrUsed值为0,使后面
//分配内存时大小不正确,导致生成的BMP文件有问题!!!
//因此,前面引入变量my_biClrUsed来事先保存outinfobuf->bmiHeader.biClrUsed
//后面的分配内存时,使用my_biClrUsed来计算和分配
//如果有调色板,则GetDIBits()会将调色板数据放到outinfobuf指定的信息头的后面。
//对于16bpp,调色板共有65536×4字节。位图数据中,每个像素是2字节,最高位是0
//对于16bpp,GetDIBits不会改变调色板数据,如果outinfobuff+40开始,是非0,则调用完GetDIBits后,仍是非0。
//说明对于16bpp,调色板是没有用处的。经实验,无论是选DIB_RGB_COLORS,还是选DIB_PAL_COLORS,GetDIBits都没有调色板数据输出,也不会更改内存中的调色板数据,并且得到的位图数据和位图文件都是一样的。
//对于16bpp,即使调色板数据非0,ACDSEE打开BMP文件也不会用到调色板数据,只会用到位图数据部分。
//biCompression等于BI_RGB时,位图数据是RGB555 for 16bpp(最高位是0) and RGB888 for 32bpp(最高字节是0)
//对于8bpp,如果参数是DIB_PAL_COLORS,则生成的是每个颜色16bits(2个字节)的调色板,8bpp就是256个颜色,在内存中是
//这些数值:0x00 00 01 00 02 00 03 00 04 00 ....一直到0xFE 00 FF 00。说明这16比特是索引到当前“逻辑调色板”的索引值
//而位图数据则是对应了这些索引值的值!
//对于1bpp,如果参数是DIB_RGB_COLORS,会生成调色板数据,是2个颜色,4×2个字节,即是0x00 00 00 00 ff ff ff 00。
//对于1bpp,如果参数是DIB_PAL_COLORS,会生成调色板数据,是2个颜色,2×2个字节,即是0x00 00 01 00。
/////////////////////////////////得到文件头
*outheadsize= sizeof(BITMAPFILEHEADER);
outheadbuf = (PBITMAPFILEHEADER) GlobalAlloc(GPTR, *outheadsize);
//根据位图大小分配内存
if (!outheadbuf) goto errout;
outheadbuf->bfType = 0x4d42; // 0x42 = "B" 0x4d = "M"
// Compute the size of the entire file.
outheadbuf->bfSize = (DWORD) (sizeof(BITMAPFILEHEADER) + \
outinfobuf->bmiHeader.biSize +\
my_biClrUsed * sizeof(RGBQUAD) +\
outinfobuf->bmiHeader.biSizeImage);
outheadbuf->bfReserved1 = 0;
outheadbuf->bfReserved2 = 0;
// Compute the offset to the array of color indices.
outheadbuf->bfOffBits = (DWORD) sizeof(BITMAPFILEHEADER) +
outinfobuf->bmiHeader.biSize +\
my_biClrUsed * sizeof (RGBQUAD);
return TRUE;
//////////////////////错误处理
errout:
if(outinfobuf) GlobalFree(outinfobuf);
if(outdatabuf) GlobalFree(outdatabuf);
if(outheadbuf) GlobalFree(outheadbuf);
outinfobuf=NULL;
outdatabuf=NULL;
outheadbuf=NULL;
*outheadsize=0;
*outinfosize=0;
*outdatasize=0;
return FALSE;
}
使用方法如下:
/////////////////////////////////////////////////////
void CTestDlg::OnButton8()
{
HBITMAP bitmap;
CString cst;
CFile DownloadFile;
/////读取位图文件SAMPLE.BMP
bitmap=(HBITMAP)LoadImage(AfxGetInstanceHandle(),"sample.BMP",IMAGE_BITMAP,0,0,LR_LOADFROMFILE|LR_CREATEDIBSECTION);
ASSERT(bitmap);
HDC hDC;
PBITMAPFILEHEADER outheadbuf;
PBITMAPINFO outinfobuf;
LPBYTE outdatabuf;
long outheadsize,outinfosize,outdatasize;
hDC = ::GetDC(NULL);
if (!myCreateBitmap( hDC, bitmap, 8,
outheadbuf,&outheadsize,
outinfobuf,&outinfosize,
outdatabuf,&outdatasize) )
{
MessageBox("error"); goto errout;
}
DownloadFile.Open("c:\\out.bmp",CFile::modeCreate | CFile::modeWrite);
DownloadFile.Write(outheadbuf,outheadsize);
DownloadFile.Write(outinfobuf,outinfosize);
DownloadFile.Write(outdatabuf,outdatasize);
DownloadFile.Close();
MessageBox("ok");
if(outinfobuf) GlobalFree(outinfobuf);
if(outdatabuf) GlobalFree(outdatabuf);
if(outheadbuf) GlobalFree(outheadbuf);
errout:
::ReleaseDC(NULL,hDC);
}
文章评论(0条评论)
登录后参与讨论