vc 位图操作 BITMAPINFO 赋值
BMP 文件结构分成以下几个部分:
1 BITMAP FILEHEADER (BMP 文件头)
2 BITMAP INFOHEADER (BMP 文件信息头)
3 RGBQUAD (BMP 文件调色板)
4 BITMAP DATA (BMP 文件数据)
Windows 中位图有两种格式:
设备相关位图 Device Depend Bitmap DDB
设备无关位图 Device Independ Bitmap DIB
DDB 位图格式 ------------ BITMAP(结构体) CBitmap(MFC类) HBITMAP(HANDLE)
由 BITMAP 数据类型的结构 + 图像数据构成。
因为DDB没有保存位图的调色板,在不同类设备显示时可能造成完全失真。
DIB 位图格式 ----------- BITMAPINFO
BITMAP INFOHEADER (BMP 文件信息头) + RGBQUAD (BMP 文件调色板) + BITMAP DATA (BMP 文件数据) 三部分构成
它实际就是BMP文件去掉BITMAP FILEHEADER (BMP 文件头),即一个BITMAPINFO结构后面接上调色板再加上图像数据。
BMP文件的显示 ---- DIB
首先将BMP读成DIB格式,当显示时直接DIB显示,只要读入BITMAPINFO结构和图像数据即可。
BMP文件的显示 ---- DDB
首先要先将DIB位图转化为DDB位图,再由MFC的CBitmap类显示。
总结: 统一使用DIB显示,即 BITMAPINFO;//个人意见
不要使用以下:BITMAP(结构体) CBitmap(MFC类) HBITMAP(HANDLE)//个人意见
//**********************************************
重点说说 BITMAPINFO MFC中的定义如下:
typedef struct tagBITMAPINFO {
BITMAPINFOHEADER bmiHeader;
RGBQUAD bmiColors[1];
} BITMAPINFO, FAR *LPBITMAPINFO, *PBITMAPINFO;
这个结构体定义很奇怪,大概的意思是兼容没有调色板的情况,不看它的写法,
依据BITMAPINFO的大小为 sizeof(BITMAPINFOHEADER) + numQuad * sizeof(RGBQUAD) 采用如下赋值方法
CFile file;
BITMAPFILEHEADER FILE_HEADER; //文件头
BITMAPINFOHEADER INFO_HEADER; //信息头
file.Open("d://demo.bmp", CFile::modeRead);
file.Read(&FILE_HEADER, sizeof(BITMAPFILEHEADER));
if(FILE_HEADER.bfType != 0x4d42)
{
file.Close();
AfxMessageBox("原图象不为BMP图象!");
return;
}
file.Read(&INFO_HEADER,sizeof(BITMAPINFOHEADER));
// 调色板数目
int numQuad = 0;
if(INFO_HEADER.biBitCount < 24)
{
numQuad = 1 << INFO_HEADER.biBitCount; //1右移?位 = 2的?次方
}
BITMAPINFO *pBMP_INFO = (BITMAPINFO*)HeapAlloc(GetProcessHeap(),0,
sizeof(BITMAPINFOHEADER) + numQuad * sizeof(RGBQUAD));
memcpy(pBMP_INFO, &INFO_HEADER, sizeof(BITMAPINFOHEADER));
RGBQUAD *quad = (RGBQUAD*)((BYTE*)pBMP_INFO + sizeof(BITMAPINFOHEADER));
if(numQuad != 0)
{
file.Read(quad, sizeof(RGBQUAD) * numQuad);
}
int sizeBuf = FILE_HEADER.bfSize - FILE_HEADER.bfOffBits;
BYTE *bmpBuf = new BYTE[sizeBuf];
file.Read(bmpBuf, sizeBuf);
file.Close();
CDC *pDC = GetDC();
Graphics gdiDC(pDC->GetSafeHdc());
Bitmap *pBmp = Bitmap::FromBITMAPINFO(pBMP_INFO, bmpBuf);//GDI+从BITMAPINFO生成bmp的方法
gdiDC.DrawImage(pBmp, 0, 0);
ReleaseDC(pDC);
//====================BITMAPINFO 说明=====================================
typedef struct tagBITMAPINFO {
BITMAPINFOHEADER bmiHeader;
RGBQUAD bmiColors[1];
} BITMAPINFO, FAR *LPBITMAPINFO, *PBITMAPINFO;
在一个结构体定义
RGBQUAD bmiColors[1];
是很危险也非常巧妙的不得已的办法,它的存在只为照顾bmp文件而存在;
因此使用BITMAPINFO有很多限制:
限制一 RGBQUAD bmiColors[1];此类设置只能存在1个,且必在最后
限制二 RGBQUAD类型必为4字节的整倍数
限制三 虽然sizeof(BITMAPINFO) = 40 + 4 = 44;
但为BITMAPINFO申请内存时必须是40 + 4 * 调色板个数,否则内存越界
也就是在使用BITMAPINFO时申请的字节数可能为40或大于44的某个数,总之一定不是44,如果为44会报错
bmp文件的字节是连续的(当然任何文件都是连续的),在文件中,紧随BITMAPINFOHEADER之后是调色板,如果没有调色板,紧随BITMAPINFOHEADER之后是数据,注意如果没有调色板,在BITMAPINFOHEADER与数据之间没有任何字节存在,为了照顾bmp文件BITMAPINFO被设计成这样,bmiColors[1]是个数组,它存放了数组的第1个元素,也就是bmiColors[0],接下来一定是bmiColors[1](此bmiColors[1]表示RGBQUAD数组的第2个元素,而BITMAPINFO中RGBQUAD bmiColors[1];则表示定义一个类型,是一个数组,因为数组是连续存储的,这样设计才能保证与bmp文件结构吻合),好乱~
申请内存也可这样写:
BITMAPINFO *pBMP_INFO = (BITMAPINFO*)malloc(sizeof(BITMAPINFOHEADER) + numQuad * sizeof(RGBQUAD));
BITMAPINFO *pBMP_INFO = new BITMAPINFO[sizeof(BITMAPINFOHEADER) + numQuad * sizeof(RGBQUAD)];