以下内容转载自http://www.ltesting.net/html/70/n-113570.html
在 Windows 3.0 以前,Windows系统用的是DDB(设备有关位图)。DDB没有调色板,显示的颜色依赖硬件,处理色彩很不方便。所以 Microsoft 在 Windows 3.0中 重新定义了BMP文件格式(BMP 3.0),使其支持设备无关位图——也就是DIB。 时至今日,BMP的版本号已升至5.0(Windows NT 4.0、Windows95 定义了 BMP 4.0,Windows 98、Windows 2000 定义了 BMP 5.0),但基本结构没有变——仍是 BMP文件头 和 DIB 组成:
BMP文件 | BITMAPFILEHEADER | BMP文件头 | |
DIB | BITMAPINFOHEADER | 位图信息头 | BITMAPINFO |
RGBQUAD[] | 调色板 | ||
位图数据 |
原型定义: | |
typedef struct tagBITMAPFILEHEADER { // bmfh WORD bfType; DWORD bfSize; WORD bfReserved1; WORD bfReserved2; DWORD bfOffBits;} BITMAPFILEHEADER; | |
VB声明: | |
Type BITMAPFILEHEADER bfType(0 to 1) As Byte bfSize As Long bfReserved1 As Integer bfReserved2 As Integer bfOffBits As LongEnd Type | |
说明: | |
bfType | 指示文件的类型,必须是“BM” |
bfSize# | 指示文件的大小,包括BITMAPFILEHEADER |
bfReserved1 | 保留,=0 |
bfReserved2 | 保留,=0 |
bfOffBits# | 从文件头到位图数据的偏移字节数 |
原型定义: | |
typedef struct tagBITMAPINFOHEADER{ // bmih DWORD biSize; LONG biWidth; LONG biHeight; WORD biPlanes; WORD biBitCount; DWORD biCompression; DWORD biSizeImage; LONG biXPelsPerMeter; LONG biYPelsPerMeter; DWORD biClrUsed; DWORD biClrImportant;} BITMAPINFOHEADER; | |
VB声明: | |
Type BITMAPINFOHEADER biSize As Long biWidth As Long biHeight As Long biPlanes As Integer biBitCount As Integer biCompression As Long biSizeImage As Long biXPelsPerMeter As Long biYPelsPerMeter As Long biClrUsed As Long biClrImportant As LongEnd Type | |
说明: | |
biSize | BITMAPINFOHEADER结构的大小。BMP有多个版本,就靠biSize来区别: BMP3.0:BITMAPINFOHEADER(=40) BMP4.0:BITMAPV4HEADER(=108) BMP5.0:BITMAPV5HEADER(=124) |
biWidth | 位图的高度,单位是像素 |
biHeight | 位图的宽度,单位是像素 |
biPlanes | 设备的位平面数。现在都是1 |
biBitCount | 图像的颜色位数 0:当biCompression=BI_JPEG时必须为0(BMP 5.0) 1:单色位图 4:16色位图 8:256色位图 16:增强色位图,默认为555格式 24:真彩色位图 32:32位位图,默认情况下Windows不会处理最高8位,可以将它作为自己的Alpha通道 |
biCompression | 压缩方式 BI_RGB:无压缩 BI_RLE8:行程编码压缩,biBitCount必须等于8 BI_RLE4:行程编码压缩,biBitCount必须等于4 BI_BITFIELDS:指定RGB掩码,biBitCount必须等于16、32 BI_JPEG:JPEG压缩(BMP 5.0) BI_PNG:PNG压缩(BMP 5.0) |
biSizeImage# | 实际的位图数据所占字节(biCompression=BI_RGB时可以省略) |
biXPelsPerMeter# | 目标设备的水平分辨率,单位是每米的像素个数 |
biYPelsPerMeter# | 目标设备的垂直分辨率,单位是每米的像素个数 |
biClrUsed# | 使用的颜色数(当biBitCount等于1、4、8时才有效)。如果该项为0,表示颜色数为2^biBitCount |
biClrImportant# | 重要的颜色数。如果该项为0,表示所有颜色都是重要的 |
原型定义: | |
typedef struct tagRGBQUAD { // rgbq BYTE rgbBlue; BYTE rgbGreen; BYTE rgbRed; BYTE rgbReserved;} RGBQUAD; | |
VB声明: | |
Private Type RGBQUAD rgbBlue As Byte rgbGreen As Byte rgbRed As Byte rgbReserved As ByteEnd Type | |
说明: | |
rgbBlue | 蓝色分量 |
rgbGreen | 绿色分量 |
rgbRed | 红色分量 |
rgbReserved# | 保留,=0 |
◆扫描行: 一行的图像数据叫做一个扫描行。一个扫描行的长度必须是4的倍数(字节),如果不是,则需要补齐。计算公式:LineBytes=((biWidth*biBitCount+31)And &HFFFFFFE0)\8 由于BMP设定者认为数学坐标系更总要,所以DIB的扫描行是逆序存储的(相对于屏幕坐标系而言),即屏幕上的第一行是DIB位图数据的最后一行。 |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
◆1位色: 用1位表示一个像素,所以一个字节可以表示8个像素。坐标是从最左边(最高位)开始的,而不是一般情况下的最低位。在内存的摆放形式如下:
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
◆4位色: 用4位表示一个像素,所以一个字节可以表示2个像素。坐标是从最左边(最高位)开始的,而不是一般情况下的最低位。在内存的摆放形式如下:
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
◆8位色: 用8位表示一个像素,所以一个字节刚好只能表示一个像素。在内存的摆放形式如下:
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
◆16位色: 用16位表示一个像素,所以两个字节可以表示1个像素。默认情况下16位DIB是555格式,最高位无效(这对VB是个福音,因为VB没有16位无符号型)。在内存的摆放形式如下(PC机是低字节在前):
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
◆24位色: 用24位表示一个像素,所以三个字节可以表示1个像素。注意它的顺序是BGR,而不是传统的RGB。在内存的摆放形式如下:
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
◆32位色: 用32位表示一个像素,所以四个字节可以表示1个像素。注意绝大多数的GDI函数不会处理Alpha通道(只有AlphaBlend支持)。在内存的摆放形式如下:
|
原型定义: | |||||
int SetDIBitsToDevice( HDC hDC, // handle to device context int XDest, // x-coordinate of upper-left corner of dest. rect. int YDest, // y-coordinate of upper-left corner of dest. rect. DWORD dwWidth, // source rectangle width DWORD dwHeight, // source rectangle height int XSrc, // x-coordinate of lower-left corner of source rect. int YSrc, // y-coordinate of lower-left corner of source rect. UINT uStartScan, // first scan line in array UINT cScanLines, // number of scan lines CONST VOID *lpvBits, // address of array with DIB bits CONST BITMAPINFO *lpbmi, // address of structure with bitmap info. UINT fuColorUse // RGB or palette indexes); | |||||
VB声明: | |||||
Declare Function SetDIBitsToDevice Lib "gdi32.dll" (ByVal hDC As Long, ByVal XDest As Long, ByVal YDest As Long, ByVal dwWidth As Long, ByVal dwHeight As Long, ByVal XSrc As Long, ByVal YSrc As Long, ByVal uStartScan As Long, ByVal cScanLines As Long, lpvBits As Any, lpbmi As Any, ByVal fuColorUse As Long) As Long | |||||
说明: | |||||
将一幅与设备无关位图的全部或部分数据直接复制到一个设备。这个函数在设备中定义了一个目标矩形,以便接收位图数据。它也在DIB中定义了一个源矩形,以便从中提取数据 | |||||
返回值: | |||||
如函数执行成功,返回欲复制的扫描线的数量;如返回常数GDI_ERROR,表示出错 | |||||
参数: | |||||
hDC | 一个设备场景的句柄。该场景用于接收位图数据 | ||||
XDest | 指定绘制区域的左上角X坐标 | ||||
YDest | 指定绘制区域的左上角Y坐标 | ||||
dwWidth | 指定绘制区域的高度 | ||||
dwHeight | 指定绘制区域的宽度 | ||||
XSrc | 矩形在DIB中的起点X坐标 | ||||
YSrc | 矩形在DIB中的起点Y坐标 | ||||
uStartScan | lpvBits中第一条扫描线的编号。如lpbmi之BITMAPINFOHEADER部分的biHeight字段是正数,那么这条扫描线就会从位图的底部开始计算;如果是负数,就从顶部开始计算 | ||||
cScanLines | 欲复制的扫描线数量 | ||||
lpvBits | 指向一个缓冲区的指针。这个缓冲区包含了以DIB格式描述的位图数据;这种格式是由lpbmi指定的 | ||||
lpbmi | 指向BITMAPINFO(为兼容BMP4/5而声明成Any),对DIB的格式和颜色进行描述的一个结构 | ||||
fuColorUse |
|
原型定义: | |||||
int StretchDIBits( HDC hDC, // handle to device context int XDest, // x-coordinate of upper-left corner of dest. rectangle int YDest, // y-coordinate of upper-left corner of dest. rectangle int nDestWidth, // width of destination rectangle int nDestHeight, // height of destination rectangle int XSrc, // x-coordinate of upper-left corner of source rectangle int YSrc, // y-coordinate of upper-left corner of source rectangle int nSrcWidth, // width of source rectangle int nSrcHeight, // height of source rectangle CONST VOID *lpBits, // address of bitmap bits CONST BITMAPINFO *lpBitsInfo, // address of bitmap data UINT iUsage, // usage flags DWORD dwRop // raster operation code); | |||||
VB声明: | |||||
Declare Function StretchDIBits Lib "gdi32" (ByVal hDC As Long, ByVal XDest As Long, ByVal YDest As Long, ByVal nDestWidth As Long, ByVal nDestHeight As Long, ByVal XSrc As Long, ByVal YSrc As Long, ByVal nSrcWidth As Long, ByVal nSrcHeight As Long, lpBits As Any, lpBitsInfo As Any, ByVal wUsage As Long, ByVal dwRop As Long) As Long | |||||
说明: | |||||
根据一幅与设备无关的位图创建一幅与设备有关的位图 | |||||
返回值: | |||||
执行成功返回位图句柄,零表示失败 | |||||
参数: | |||||
hDC | 一个设备场景的句柄,该设备场景定义了要创建的与设备有关位图的配置信息 | ||||
XDest | 指定绘制区域的左上角X坐标 | ||||
YDest | 指定绘制区域的左上角Y坐标 | ||||
nDestWidth | 指定绘制区域的高度 | ||||
nDestHeight | 指定绘制区域的宽度 | ||||
XSrc | 矩形在DIB中的起点X坐标 | ||||
YSrc | 矩形在DIB中的起点Y坐标 | ||||
nSrcWidth | 指定原位图绘制区域的左上角X坐标 | ||||
nSrcHeight | 指定原位图绘制区域的左上角Y坐标 | ||||
lpBits | 指向一个缓冲区的指针。这个缓冲区包含了以DIB格式描述的位图数据;这种格式是由lpBitsInfo指定的 | ||||
lpBitsInfo | 指向BITMAPINFO(为兼容BMP4/5而声明成Any),对DIB的格式和颜色进行描述的一个结构 | ||||
iUsage |
|
||||
dwRop | 欲进行的光栅运算 |
原型定义: | |||||
HBITMAP CreateDIBitmap( HDC hDC, // handle to device context CONST BITMAPINFOHEADER *lpbmih, // pointer to bitmap size and format data DWORD fdwInit, // initialization flag CONST VOID *lpbInit, // pointer to initialization data CONST BITMAPINFO *lpbmi, // pointer to bitmap color-format data UINT fuUsage // color-data usage); | |||||
VB声明: | |||||
Declare Function CreateDIBitmap Lib "gdi32" (ByVal hDC As Long, lpbmih As Any, ByVal fdwInit As Long, lpbInit As Any, lpbmi As Any, ByVal fuUsage As Long) As Long | |||||
说明: | |||||
将一幅与设备无关位图的全部或部分数据直接复制到一个设备。这个函数在设备中定义了一个目标矩形,以便接收位图数据。它也在DIB中定义了一个源矩形,以便从中提取数据 | |||||
返回值: | |||||
执行成功则返回扫描线的数量,零表示失败。会设置GetLastError | |||||
参数: | |||||
hDC | 一个设备场景的句柄。该场景用于接收位图数据 | ||||
lpbmih | BITMAPINFOHEADER(为兼容BMP4/5而声明成Any),对DIB的格式进行描述的一个结构 | ||||
fdwInit | 如不应对位图数据进行初始化,那么设为零。如设为CBM_INIT,表示根据lpbInit和 lpbmi参数对位图进行初始化 | ||||
lpbInit | 指向一个缓冲区的指针。这个缓冲区包含了以DIB格式描述的位图数据;这种格式是由lpbmi指定的 | ||||
lpbmi | 指向BITMAPINFO(为兼容BMP4/5而声明成Any),对DIB的格式和颜色进行描述的一个结构 | ||||
fuUsage |
|
原型定义: | |||||
HBITMAP CreateDIBSection( HDC hDC, // handle to device context CONST BITMAPINFO *lpbmi, // pointer to structure containing bitmap size, format, and color data UINT iUsage, // color data type indicator: RGB values or palette indexes VOID *ppvBits, // pointer to variable to receive a pointer to the bitmap´s bit values HANDLE hSection, // optional handle to a file mapping object DWORD dwOffset // offset to the bitmap bit values within the file mapping object); | |||||
VB声明: | |||||
Declare Function CreateDIBSection Lib "gdi32" (ByVal hDC As Long, lpbmi As Any, ByVal iUsage As Long, ByRef ppvBits As Long, ByVal hSection As Long, ByVal dwOffset As Long) As Long | |||||
说明: | |||||
CreateDIBSection能创建一种特殊的DIB,称为DIB项(DIBSection),然后返回一个GDI位图的句柄。它提供了DIB和GDI位图的最好的特性。这样我们可以直接访问DIB的内存,可以利用位图句柄和内存设备环境,我们甚至还可以在DIB中调用GDI函数来绘图 | |||||
返回值: | |||||
执行成功返回DIBSection位图的句柄,零表示失败。会设置GetLastError | |||||
参数: | |||||
hDC | 一个设备场景的句柄。如dw设为DIB_PAL_COLORS,那么DIB颜色表就会用来自逻辑调色板的颜色进行初始化 | ||||
lpbmi | 指向BITMAPINFO(为兼容BMP4/5而声明成Any),这个结构初始化成欲创建的那幅位图的配置数据 | ||||
iUsage |
|
||||
ppvBits | 用于得到DIBSection数据区的内存地址 | ||||
hSection | 指向一个文件映射对象的可选句柄,位图将在其中创建。如设为零,Windows会自动分配内存 | ||||
dwOffset | 如指定了句柄,就用这个参数指定位图数据在文件映射对象中的偏移量 |
原型定义: | |||||
int GetDIBits( HDC hDC, // handle to device context HBITMAP hbmp, // handle to bitmap UINT uStartScan, // first scan line to set in destination bitmap UINT cScanLines, // number of scan lines to copy LPVOID lpvBits, // address of array for bitmap bits LPBITMAPINFO lpbmi,// address of structure with bitmap data UINT uUsage // RGB or palette index); | |||||
VB声明: | |||||
Declare Function GetDIBits Lib "gdi32" (ByVal hDC As Long, ByVal hbmp As Long, ByVal uStartScan As Long, ByVal cScanLines As Long, lpvBits As Any, lpbmi As Any, ByVal uUsage As Long) As Long | |||||
说明: | |||||
该函数利用申请到的内存,由GDI位图得到DIB位图数据。通过该函数,可以对DIB的格式进行控制,可以制定颜色的位数,而且可以指定是否进行压缩。如果采用了压缩方式,则必须调用该函数两次,一次为了得到所需内存,另外一次为了得到位图数据 | |||||
返回值: | |||||
执行成功则返回扫描线的数量,零表示失败。会设置GetLastError | |||||
参数: | |||||
hDC | 定义了与设备有关位图hBitmap的配置信息的一个设备场景的句柄 | ||||
hbmp | 源位图的句柄 | ||||
uStartScan | 欲复制到DIB中的第一条扫描线的编号 | ||||
cScanLines | 欲复制的扫描线数量 | ||||
lpvBits | 指向一个缓冲区的指针。这个缓冲区包含了以DIB格式描述的位图数据;这种格式是由lpbmi指定的 | ||||
lpbmi | 指向BITMAPINFO(为兼容BMP4/5而声明成Any).对DIB的格式及颜色进行说明的一个结构。在BITMAPINFOHEADER结构中,从biSize到biCompression之间的所有字段都必须初始化 | ||||
uUsage |
|
原型定义: | |||||
int SetDIBits( HDC hDC, // handle to device context HBITMAP hbmp, // handle to bitmap UINT uStartScan, // starting scan line UINT cScanLines, // number of scan lines CONST VOID *lpvBits, // array of bitmap bits CONST BITMAPINFO *lpbmi, // address of structure with bitmap data UINT uUsage // type of color indexes to use); | |||||
VB声明: | |||||
Declare Function SetDIBits Lib "gdi32" (ByVal hDC As Long, ByVal hbmp As Long, ByVal uStartScan As Long, ByVal cScanLines As Long, lpvBits As Any, lpbmi As Any, ByVal uUsage As Long) As Long | |||||
说明: | |||||
将来自与设备无关位图的二进制位复制到一幅与设备有关的位图里 | |||||
返回值: | |||||
执行成功则返回扫描线的数量,零表示失败。会设置GetLastError | |||||
参数: | |||||
hDC | 定义了与设备有关位图hBitmap的配置信息的一个设备场景的句柄 | ||||
hbmp | 源位图的句柄 | ||||
uStartScan | 欲复制到DIB中的第一条扫描线的编号 | ||||
cScanLines | 欲复制的扫描线数量 | ||||
lpvBits | 指向一个缓冲区的指针。这个缓冲区包含了以DIB格式描述的位图数据;这种格式是由lpbmi指定的 | ||||
lpbmi | 指向BITMAPINFO(为兼容BMP4/5而声明成Any).对DIB的格式及颜色进行说明的一个结构。在BITMAPINFOHEADER结构中,从biSize到biCompression之间的所有字段都必须初始化 | ||||
uUsage |
|
原型定义: | |
UINT GetDIBColorTable( HDC hDC, // handle to device context whose DIB is of interest UINT uStartIndex, // color table index of first entry to retrieve UINT cEntries, // number of color table entries to retrieve RGBQUAD *pColors // pointer to buffer that receives color table entries); | |
VB声明: | |
Declare Function GetDIBColorTable Lib "gdi32" (ByVal hDC As Long, ByVal uStartIndex As Long, ByVal cEntries As Long, pColors As RGBQUAD) As Long | |
说明: | |
从选入设备场景的DIBSection中取得颜色表信息 | |
返回值: | |
取回的颜色条目数量,零表示失败。会设置GetLastError | |
参数: | |
hDC | 已选入了一个DIBSection对象的设备场景 |
uStartIndex | 颜色表中欲取回的第一个条目的索引 |
cEntries | 欲取回的条目数量 |
pColors | 这个结构数组用于装载颜色表信息的第一个条目 |
原型定义: | |
UINT SetDIBColorTable( HDC hDC, // handle to device context whose DIB is of interest UINT uStartIndex, // color table index of first entry to set UINT cEntries, // number of color table entries to set CONST RGBQUAD *pColors // pointer to array of color table entries); | |
VB声明: | |
Declare Function SetDIBColorTable Lib "gdi32" (ByVal hDC As Long, ByVal uStartIndex As Long, ByVal cEntries As Long, pColors As RGBQUAD) As Long | |
说明: | |
从选入设备场景的DIBSection中取得颜色表信息 | |
返回值: | |
取回的颜色条目数量,零表示失败。会设置GetLastError | |
参数: | |
hDC | 已选入了一个DIBSection对象的设备场景 |
uStartIndex | 颜色表中欲取回的第一个条目的索引 |
cEntries | 欲取回的条目数量 |
pColors | 这个结构数组用于装载颜色表信息的第一个条目 |
*****************************************************************************************************************************************************************************************
根据以上参考资料,把位图信息加载到内存后再显示的方法:(只讨论显示的基本方法,实际开发要考虑更多)
// GDI
//读取文件
CFile file("D:\\1.bmp",CFile::modeRead);
char* bmpbuf = new char[file.GetLength()+1];
file.Read(bmpbuf,file.GetLength());
//分析文件
BITMAPFILEHEADER* bmpfileheader = (BITMAPFILEHEADER*)bmpbuf;//文件头
BITMAPINFOHEADER* bmpinfoheader = (BITMAPINFOHEADER*)((char*)bmpbuf + sizeof(BITMAPFILEHEADER));//位图头
BITMAPINFO* bmpinfo = (BITMAPINFO*)bmpinfoheader;//位图信息
CClientDC dc(this);
// //第一种方法
// StretchDIBits(dc.GetSafeHdc(),0,0,1024,768,0,0,bmpinfoheader->biWidth,bmpinfoheader->biHeight,
// bmpbuf+bmpfileheader->bfOffBits,bmpinfo,DIB_RGB_COLORS,SRCCOPY);
// //第二种方法
// void* p = new char[bmpinfoheader->biSizeImage];
// HBITMAP hbmp = CreateDIBSection(dc.GetSafeHdc(),bmpinfo,DIB_RGB_COLORS,&p,NULL,0);//CreateDIBSection
// memcpy(p,bmpbuf+bmpfileheader->bfOffBits,bmpinfoheader->biSizeImage);
// CBitmap bitmap;
// bitmap.Attach(hbmp);
// CDC cmpDC;
// cmpDC.CreateCompatibleDC(&dc);
// CBitmap* oldbmp = cmpDC.SelectObject(&bitmap);
// dc.StretchBlt(0,0,1024,768,&cmpDC,0,0,bmpinfoheader->biWidth,bmpinfoheader->biHeight,SRCCOPY);
// cmpDC.SelectObject(oldbmp);
// //第三种方法
// HBITMAP hbitmap = CreateDIBitmap(dc.GetSafeHdc(),bmpinfoheader,CBM_INIT,bmpbuf+bmpfileheader->bfOffBits,bmpinfo,DIB_RGB_COLORS);
// CDC cmpDC;
// cmpDC.CreateCompatibleDC(&dc);
// HBITMAP oldbmp = (HBITMAP)::SelectObject(cmpDC.GetSafeHdc(),hbitmap);
// dc.BitBlt(0,0,1024,768,&cmpDC,0,0,SRCCOPY);
// cmpDC.SelectObject(oldbmp);
delete []bmpbuf;