bitmap分析

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)];

你可能感兴趣的:(VC++知识)