将HBITMAP转换成BMP位图文件的各个部分,可以在1BIT,4BIT,8BIT,16BIT,24BIT,32BIT之间转换

本文介绍在VC环境下将HBITMAP转换为BMP位图文件的方法,支持1BIT、4BIT、8BIT、16BIT、24BIT、32BIT之间的转换。通过使用GetDIBits()函数,实现自定义每像素比特数的转换过程,并详细解释了转换细节和注意事项。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 

 

VC将HBITMAP转换成BMP位图文件的各个部分,可以在1BIT,4BIT,8BIT,16BIT,24BIT,32BIT之间转换

http://blog.ednchina.com/wxleasyland/278112/message.aspx

 

 

经过这段时间的努力,终于在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);

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值