15.1 DIB文件格式(一种文件格式,扩展名为BMP)
15.1.1 OS/2风格的DIB
文件格式 |
字段 |
说明 |
文件头 (BITMAPFILEHEADER)
1、共14个字节 2、缩写建议用bmfh |
WORD bfType |
文件签名,表示位图文件,以0x4D42,即字母“BM”打头 |
DWORD bfSize |
整个文件的大小(含文件头的大小)。单位:字节 |
|
WORD bfReserved1 |
以下这两个字段必须为0。鼠标指针文件,格式类似于DIB但这两个字段表示了“热点”的位置。 |
|
WORD bfReserved2 |
||
DWORD bfOffsetBits |
从文件起始位置到像素位的偏移,即像素位的位置 |
|
信息头 (BITMAPCOREHEADER)
1、缩写建议bmch 2、“CORE”说明是其他位图格式的基础。 |
DWORD bcSize |
该结构体的大小,sizeof(BITMAPCOREHEADER),12字节 |
WORD bcWidth |
图像宽度(像素),WORD类型最大65535 |
|
WORD bcHeight |
图像高度(像素),也是图像的总像素行数! |
|
WORD bcPlanes |
总是等于1 |
|
WORD bcBitCount |
每像素位(1,4,8,or 24)即2^bcBitCount。但没有16和32位的。 1、4、8位时:后面跟一个颜色表 24位时: 没有颜色表 |
|
颜色表(可选) 注意是个数组,每个元素为RGBTRIPLE类型。 |
BYTE rgbtBlue |
1、推荐最重要的颜色排最前面 2、注意顺序是Blue、Green、Red。 3、结构长为3字节。但为了内存对齐,DIB文件总是有偶数个RGBTRIPLE结构。 |
BYTE rgbtGreen |
||
BYTE rgbtRed |
||
像素位 |
|
颜色表之后的数据,或24位DIB信息头之后的数据 |
(1)紧凑格式的DIB:指没有文件头,只有信息头、颜色表(可选)和像素位的DIB。
(2)组合信息头和颜色表的结构体——BITMAPCOREINFO
typedef struct tagBITMAPCOREINFO //建议缩写形式bmci
{
BITMAPCOREHEADER bmciHeader; //基本信息头
RGBTRIPLE bmciColor[1]; //颜色表数组,注意这里为元素个数为
//1,实质上是个柔性数组,可扩充。
}
举例说明:为8位DIB的BITMAPCOREINFO分配内存:(共256种颜色)
//分配内存,注意BITMAPCOREHEADER内有一个RGBTRIPLE,再分配255个
pbmci =malloc(sizeof(BITMAPCOREINFO)+255*sizeof(RGBTRIPLE));
//访问某个颜色的方法
pbmci->bmciColor[i];
15.1.2 自下而上的存储
(1)DIB是从图像最下面一行开始,然后逐渐向上存储整个图像
(2)概念区别:
图像 |
顶行 |
视觉上图像的顶部,如头发 |
底行 |
视觉上图像的底部,如脚 |
|
DIB像素行 |
第一行 |
紧跟颜色表之后的像素行,即图像的底行 |
最后一行 |
文件中最后的像素行,即图像的顶行 |
15.1.3 DIB像素位
(1)每行像素的字节数(4的倍数,不够时补0。单位是字节)
RowLength = 4* ((bmch.bcWidth * bmch.bcBitCount + 32 ) / 32 );
或 = ((bmch.bcWidth* bmch.bcBitCount + 31 ) & ~31 ) >> 3;(高效!)
(2)所有像素占用的字节数:RowLength * bmch.bcHeight; //每行像素*总行数
(3)像素位编码
①每像素1位DIB——单色DIB
A、像素位的内存值为0表示该像素的颜色由颜色表的第一个RGBTRIPLE字段指定
B、像素位的内存值为1表示该像素的颜色由颜色表的第二个RGBTRIPLE字段指定
C、内存中的每1位表示1个像素的值。
②每像素4位DIB——16色DIB
A、每4位表示一个像素的值,这个值代表颜色表中的数组的索引
B、每个像素的值在0~15之间。
C、每个字节表示2个像素
③每像素8位DIB——256色DIB
A、每8位表示一个像素的值,这个值代表颜色表中的数组的索引
B、每个像素的值在0~15之间。
C、每个字节表示2个像素
④每像素24位DIB——全彩DIB
A、每个像素需要3个字节,每行的结尾添加一些0,保证每行的字节数是4年倍数。
B、每像素24位的DIB没有颜色表
⑤每像素16位DIB——OS/2风格没这种,只有Windows扩展DIB才有
A、该种DIB有5-5-5和5-6-6之分。5-5-5时最高位为0,5-6-5时,绿色为6位。
B、如果没有被压缩过,像素位的值经过移位处理后,可以代表实际的颜色值。但是压缩后即(biCompression为BI_BITFIELDS时)还要结合颜色遮罩算出颜色值。
⑥每像素32位DIB——OS/2风格没这种,只有Windows扩展DIB才有
A、如果没有被压缩,像素位的值经过移位处理后,可以代表实际的颜色值。但是压缩后即(biCompression为BI_BITFIELDS时)还要结合颜色遮罩算出颜色值。
B、注意:这里的32位RGB与COLOREF不一样,COLOREF中,红色在最位低字节中!15.1.4 Windows扩展DIB
文件格式 |
字段 |
说明 |
文件头 (BITMAPFILEHEADER)
1、共14个字节 2、缩写建议用bmfh |
WORD bfType |
文件签名,表示位图文件,以0x4D42,即字母“BM”打头 |
DWORD bfSize |
整个文件的大小(含文件头的大小)。单位:字节 |
|
WORD bfReserved1 |
以下这两个字段必须为0。鼠标指针文件,格式类似于DIB但这两个字段表示了“热点”的位置。 |
|
WORD bfReserved2 |
||
DWORD bfOffsetBits |
从文件起始位置到像素位的偏移,即像素位的位置 |
|
信息头 (BITMAPINFOHEADER)
1、缩写建议bmih 2、比“CORE”新增6个字段。 |
DWORD biSize |
该结构体的大小,sizeof(BITMAPINFOHEADER),40字节 |
LONG biWidth |
图像宽度(像素),WORD类型最大65535 |
|
LONG biHeight |
图像高度(像素),也是图像的总像素行数! 负数:DIB从上到下,原点在左上角。 |
|
WORD biPlanes |
总是等于1 |
|
WORD biBitCount |
每像素位(1,4,8,16,24 or 32)即, 新增了16和32位。 1、4、8位时:后面跟一个颜色表 24位时:可以有颜色表,大小由biClrUsed指定,但该颜色表要求程序自己负责管理。 |
|
DWORD biCompression |
压缩编码 1、对于1位DIB,该字段总是BI_RGB 2、对于4位DIB,该字段为BI_RGB或BI_RLE4 3、对于8位DIB,为BI_RGB或BI_RLE8 4、对于24位DIB,总是BI_RGB 5、16、32位的DIB,为BI_RGB或BI_BITFIELDS。如果为BI_BITFIELDS,则表示紧跟BITMAPINFOHEADER后面的3个32位为颜色遮罩,分别为红色、绿色、蓝色遮罩。 |
|
DWORD biSizeImage |
图像字节数(即bfOffsetBits后面数据区大小) 2、如果biCompression为BI_RGB,该字段为0或 biHeight*每一行字节数。 |
|
LONG biXPelsPerMeter |
水平\垂直分辨率(像素/米),指示图像在真实世界中的大小。现在一般为0,表示没有一个推荐的真实世界的大小。 |
|
LONG biYPelsPerMeter |
||
DWORD biClrUsed |
重要字段,指用到的颜色数(可用来减少DIB大小) 0:颜色表中元素个数由biBitCount指定,即2^bitBitCount个。其余值说明了颜色表的元素的实际个数。 1位DIB:该字段为0或2。颜色表总有2个元素 4位DIB:为0或16,颜色表有16个元素。如果设置该字段为2~15,则指明了颜色表的元素个数,每个像素的最大值为该值减1。 8位DIB:为0或256,颜色表有256个元素,其余同上。 16、24、32位:一般为0.如果不是,则指明了颜色表的元数个数。应用程序可以用这个颜色表为该DIB在256色的显示器上设置调色板 |
|
DWORD biClrImportant |
重要颜色的数目,通常为0。表示所有颜色都很重要。或可设置为biClrUsed的值。 |
|
颜色表(可选)
1、颜色表是个数组,每个元素为RGBQUARD类型。 2、为保证每个地址边界32位处理器有效寻址,每个结构地址从32位地址边界开始。 |
BYTE rgbtBlue |
1、推荐最重要的颜色排最前面 2、注意顺序是Blue、Green、Red。 3、结构长为3字节。但为了内存对齐,DIB文件总是有偶数个RGBTRIPLE结构。 |
BYTE rgbtGreen |
||
BYTE rgbtRed |
||
BYTE rgbReserved |
=0 |
|
像素位 |
|
颜色表之后的数据,或24位DIB信息头之后的数据 1、对于1、4、8、24的DIB来说,扩展版的与OS/2兼容的DIB一样。 2、对于16和32位的DIB:像素位见后面讨论。 |
注意:组合信息头和颜色表的结构体——BITMAPINFO
typedef struct tagBITMAPINFO //建议缩写形式bmi
{
BITMAPINFOHEADER bmiHeader; //基本信息头
RGBQUAD bmiColor[1]; //颜色表数组,注意这里为元素个数为
//1,实质上是个柔性数组,可扩充。
}
15.1.5 现实情况——以每像素8位的DIB为例
(1)8位灰度DIB(8位可表示256种颜色,但这种位图64种,即biClrUsed=64)
①颜色表中有64个元素,即64个RGBQUARD结构的数组(索引i=0~63)
②灰色图则Red=Green=Blue,即rgb[i].rgbRed = rgb[i].rgbGreen = rgb[i].rgbBlue=i*256/64;(i为索引)
③RGB值为并不代表实际颜色,而是灰度等级。如0x00表示黑色,如0x20(十进制32表示50%灰色(32/63),0x3F(十进制的63)表示100%,即白色。
④部分灰度DIB的颜色表可能不是64种颜色,由biClrUsed指定,范围在2~256。但没有必要指定为2时,因为这说明每个像素实际使用2种颜色,可以将这个8位DIB重新编码为1位的DIB。同理,biClrUsed小于16时,说明每个像素实际4种以下的颜色,同样可以重新编码为4位的DIB。
⑤每个像素的数值不大于颜色表元数的个数减一(因为像素数值是个索引,是颜色表数组的下标)。如biClrUsed为64的8位DIB(实际上只使用6位),像素数值为0x00~0x3F。
(3)调色板化的8位彩色DIB,biClrUsed一般为0或256,表示有256种颜色。
15.1.6 DIB压缩——RLE编码(Run-Length Encoding)
(1)biCompression设置(BI_RGB时,表示未压缩格式,像素位与OS/2的DIB一样存储。否则用RLE编码)
①对1位DIB:biCompression总是BI_RGB,说明像素位值没被压缩,仍是索引。
②对4位DIB:biCompression可以是BI_RGB或BI_RLE4
③对8位DIB:biCompression可以是BI_RGB或BI_RLE8
④对24位DIB:biCompression总是BI_RGB,说明像素位值是RGB值,没被压缩。
⑤对于16位和32位DIB,biCompression是BI_RGB或表示颜色遮罩的BI_BITFIELDS(见后面的颜色遮罩)
(2)行程长度编码(RLE)规则
字节1 |
字节2 |
字节3 |
字节4 |
含义 |
00 |
00 |
|
|
一行的结尾 |
00 |
01 |
|
|
图像的结尾 |
00 |
02 |
dx |
dy |
移动到(x+dx,y+dy) |
00 |
n=03~FF |
|
|
使用接下来的n个像素 |
n=01~FF |
像素位 |
|
|
重复像素n次 |
(3)分析RLE_8编码(8位DIB)
①表格最后一行:如果第1个字节不为0,那n表示像素应重复n次。如:0x05 0x27 解码后的像素值为:0x27 0x270x27 0x27 0x27
②表格倒数第二行:如果第1字节为0,第2字节在大于03的,则表明其后紧跟的n个字节就表示像素位,没被压缩,可直接使用。
A、如 0x00 0x060x45 0x32 0x77 0x34 0x59 0x90 解码后:0x45 0x32 0x77 0x34 0x590x90。
B、但是这种序列总是与两个字节的边界对齐,如果第2个字节是奇数,那么这个序列的结尾会被补上一个不用的多余字节。
如 0x00 0x05 0x45 0x32 0x77 0x34 0x59 0x00 解码后:0x45 0x32 0x77 0x34 0x59
③表格的前三行,指出一个矩形DIB图像中的有些部分是可以没有定义的。可以通过偏移跳过这些位置,而正确找到己定义的、要被解码的像素位。
解码过程中,用一个矩形的Buffer来接收解码后的数据,先维护一对从(0,0)开始的数值(x,y),x、y对应分别于Buffer列和行。每次解出一个像素后,将解码后的值存入Buffer[x][y],然后x++,每结束一行时y++,然后x置0。遇到一个0x00后紧跟0x02字节时,后读取第3、4个字节,并把它们分别作为无符号整数dx、dy,然后进行x +=dx,y +=dy。直到遇到0x00后跟0x01表示整个图像解码结束。最后跟创建一个可供显示的DIB,将像素数据指向Buffer即可。
(4)分析RLE_4编码(4位DIB)
编码(Compression) |
解码 |
说明 |
0x07 0x35 0x05 0x24 |
0x35 0x35 0x35 0x32 0x42 0x42 |
第1字节不为0,则重复n次 |
0x00 0x05 0x23 0x57 0x10 0x00 |
0x23 0x57 0x1? |
//编码序列必须补0到偶数字节 //“?”表示该处数据会与后面的解码出来的数,拼成一个字节。 |
(5)biCompression字段为BI_RLE4或BI_RLE8时,biSizeImage表示DIB实际像素数据大小,字节为单位。biCompression为BI_RGB时,biSizeImage通常为0或biHeight乘以每行字节数。
(6)只有从下向到上的DIB才能被压缩,即biHeight>0。负值表示从上到下。
15.1.7 颜色遮罩
(1)未压缩时(BI_RGB)像素位值的读取。
说明:
①未压缩时,读取每个通道颜色时,用某个常量(如上图中的0x7C00、0x00FF0000)和像素变量进行与操作,相当于起到遮罩作用。压缩情况下遮罩由紧跟BITMAPINFOHEADER后的3个32位颜色遮罩指定,分别为红色、绿色、蓝色遮罩。
②16位中像素和一个遮罩按位与操作,再右移一个位数,这时产生的颜色值在0x00~0x1F之间。最后再左移3位,可以使每个通道的颜色值在0x00~0xF8之间。
③记住,如果16位DIB像素宽度是奇数,则每一行最后两个字节是用0填充的,用来使每行的字节数是4的位数,所以这两个字节的颜色值是没有意义的。
④一个32位的像素值与GDI函数中32位的COLORREF并不一样,在COLORREF中,红色在最低字节。每个通道颜色的最大值是0xFF。
(2)压缩时(BI_BITFIELDS)像素值的读取。
①先从3个颜色遮罩中,读取遮罩的值,如分别为dwMask[0],dwMask[1],dwMask[2];
②再从颜色遮罩中判断像素变量需要右移和位移的位数。
遮罩位的特点:每个通道颜色遮罩1的位数必须连续,3个遮罩中为1的位不能互相重叠。
int MaskToRshift(DWORD dwMask) { //设dwMask =0x0000F800 int iShift; if (dwMask == 0) return 0; //dwMask&1:取出dwMask最后一位,如果是0,则继续右移,直到遇到1停止。 for (iShift = 0; !(dwMask & 1); iShift++) dwMask >> 1; return iShift; } //判断左移位数 int MaskToLshift(DWORD dwMask) { //设dwMask =0x0000F800 int iShift; if (dwMask == 0) return 0; //先去掉dwMask右侧的0 while (!(dwMask & 1)) dwMask >> 1; //dwMask&1:取出dwMask最后一位,如果是1,则统计1的个数,直到遇到0为止。 for (iShift = 0; (dwMask & 1); iShift++) dwMask >> 1; return 8- iShift; //因为每个通道的颜色用1个字节(8位)表示。 }
③取读像素变量中各通道的颜色值。
Red =((dwMask[0] & wPixel) >> iRShift[0]) << iLShift[0];
Green= ((dwMask[1] & wPixel) >> iRShift[1]) << iLShift[1];
Blue = ((dwMask[2] & wPixel) >> iRShift[2]) << iLShift[2];
(3)遮罩是DWORD型的,但Windows中对颜色遮罩有严格的规定
|
16位DIB |
16位DIB |
32位DIB |
说明 |
红色遮罩 |
0x00007C00 |
0x0000F800 |
0x00FF0000 |
简写形式为每个像素红、绿、蓝所用的位数。 |
绿色遮罩 |
0x000003E0 |
0x000007E0 |
0x0000FF00 |
|
蓝色遮罩 |
0x0000001F |
0x0000001F |
0x000000FF |
|
简写 |
5-5-5 |
5-6-5 |
8-8-8 |
15.1.8 版本4的文件信息头——BITMAPV4HEADER结构体
字段 |
含义 |
备注 |
bv4Size |
结构的大小=120 |
这11个字段与BITMAPINFOHEADER结构是一样的。 |
bv4Width |
图像宽度(像素) |
|
bv4Height |
图像高度(像素) |
|
bv4Planes |
=1 |
|
bv4BitCount |
每像素位数(1、4、8、16、24、32) |
|
bv4Compression |
压缩编码 |
|
bv4SizeImage |
图像字节数 |
|
bv4XPelsPerMeter |
水平分辨率 |
|
bv4YPelsPerMeter |
垂直分辩率 |
|
bv4ClrUsed |
用到的颜色数 |
|
bv4ClrImportant |
重要的颜色数 |
|
bv4RedMask |
红色遮罩 |
1、只适当于bv4Compression为BI_BITFIELDS的16位或32位DIB。 2、bv4AlphaMask很少用到。 |
bv4GreenMask |
绿色遮罩 |
|
bv4BlueMask |
蓝色遮罩 |
|
bv4AlphaMask |
阿尔法遮罩 |
|
bv4CSType |
色彩空间类型 |
颜色匹配技术,用于弥补RGB表示颜色的缺陷,把颜色与设备无关的标准联系起来。 |
bv4Endpoints |
XYZ值 |
|
bv4GammaRed |
红色伽玛值 |
|
bv4GammaGreen |
绿色伽玛值 |
|
bv4GammaBlue |
蓝色伽玛值 |
15.19 版本5的文件信息头——BITMAPV5HEADER结构体
字段 |
含义 |
备注 |
bv5Size |
结构的大小=120 |
这11个字段与BITMAPINFOHEADER结构是一样的。 |
bv5Width |
图像宽度(像素) |
|
bv5Height |
图像高度(像素) |
|
bv5Planes |
=1 |
|
bv5BitCount |
每像素位数(1、4、8、16、24、32) |
|
bv5Compression |
压缩编码 |
|
bv5SizeImage |
图像字节数 |
|
bv5XPelsPerMeter |
水平分辨率 |
|
bv5YPelsPerMeter |
垂直分辩率 |
|
bv5ClrUsed |
用到的颜色数 |
|
bv5ClrImportant |
重要的颜色数 |
|
bv5RedMask |
红色遮罩 |
1、只适当于bv4Compression为BI_BITFIELDS的16位或32位DIB。 2、bv4AlphaMask很少用到。 |
bv5GreenMask |
绿色遮罩 |
|
bv5BlueMask |
蓝色遮罩 |
|
bv5AlphaMask |
阿尔法遮罩 |
|
bv5CSType |
色彩空间类型 |
颜色匹配技术,用于弥补RGB表示颜色的缺陷,把颜色与设备无关的标准联系起来。 |
bv5Endpoints |
XYZ值 |
|
bv5GammaRed |
红色伽玛值 |
|
bv5GammaGreen |
绿色伽玛值 |
|
bv5GammaBlue |
蓝色伽玛值 |
|
bv5Intent |
渲染意图 |
将设备相关的颜色值与设备无关的颜色规范联系起来。颜色配置文件的扩展名为.ICM。可以内嵌在DIB文件。 |
bv5ProfileData |
颜色配置数据或文件名 |
|
bv5ProfileSize |
内嵌数据或文件名的大小 |
|
bv5Reserved |
保留 |
15.1.10 显示DIB信息
效果图
/*------------------------------------------------------------ DIBHEADS.C -- Displays DIB Header Information (c) Charles Petzold, 1998 ------------------------------------------------------------*/ #include <windows.h> #include "resource.h" #include "DibFile.h" LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow) { static TCHAR szAppName[] = TEXT("DibHeads"); HWND hwnd; MSG msg; WNDCLASSEX wndclass; HACCEL hAccel; wndclass.style = CS_HREDRAW | CS_VREDRAW; wndclass.cbSize = sizeof(WNDCLASSEX); wndclass.lpfnWndProc = WndProc; wndclass.cbClsExtra = 0; wndclass.cbWndExtra = 0; wndclass.hInstance = hInstance; wndclass.hIcon = LoadIcon(hInstance, szAppName); wndclass.hIconSm = LoadIcon(hInstance, szAppName); wndclass.hCursor = LoadCursor(NULL, IDC_ARROW); wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); wndclass.lpszMenuName = szAppName; wndclass.lpszClassName = szAppName; if (!RegisterClassEx(&wndclass)) { MessageBox(NULL, TEXT("This program requires Windows NT!"), szAppName, MB_ICONERROR); return 0; } hwnd = CreateWindow(szAppName, // window class name TEXT("DIB Headers"), // window caption WS_OVERLAPPEDWINDOW, // window style CW_USEDEFAULT, // initial x position CW_USEDEFAULT, // initial y position CW_USEDEFAULT, // initial x size CW_USEDEFAULT, // initial y size NULL, // parent window handle NULL, // window menu handle hInstance, // program instance handle NULL); // creation parameters ShowWindow(hwnd, iCmdShow); UpdateWindow(hwnd); hAccel = LoadAccelerators(hInstance, szAppName); while (GetMessage(&msg, NULL, 0, 0)) { if (!TranslateAccelerator(hwnd, hAccel, &msg)) { TranslateMessage(&msg); DispatchMessage(&msg); } } return msg.wParam; } void Printf(HWND hwnd, TCHAR* szFormat, ...) { TCHAR szBuffer[1024]; va_list pArgList; va_start(pArgList, szFormat); wvsprintf(szBuffer, szFormat, pArgList); va_end(pArgList); // (0, -1)表示全选, (-1,任意)表示全不选 SendMessage(hwnd, EM_SETSEL, (WPARAM)-1, (LPARAM)-1); //取消选择 //未选择文本时,替换文本被插入到Caret所在位置 SendMessage(hwnd, EM_REPLACESEL, FALSE, (LPARAM)szBuffer); //FALSE表示不能被撤消 SendMessage(hwnd, EM_SCROLLCARET, 0, 0); } void DisplayDibHeaders(HWND hwnd, TCHAR* szFileName) { static TCHAR* szInfoName[] = { TEXT("BITMAPCOREHEADER"), TEXT("BITMAPINFOHEADER"), TEXT("BITMAPV4HEADER"), TEXT("BITMAPV5HEADER") }; static TCHAR* szCompression[] = { TEXT("BI_RGB"), TEXT("BI_RLE8"), TEXT("BI_RLE4"), TEXT("BI_BITFIELDS"), TEXT("unkown") }; BITMAPFILEHEADER* pbmfh; BITMAPV5HEADER* pbmih; BITMAPCOREHEADER* pbmch; TCHAR* szV = NULL; int i; //显示文件名: Printf(hwnd, TEXT("File:%s\r\n\r\n"), szFileName); SetCursor(LoadCursor(NULL, IDC_WAIT)); ShowCursor(TRUE); //读取文件 pbmfh = DibLoadImage(szFileName); if (pbmfh == NULL) { Printf(hwnd, TEXT("Could not read file.\r\n\r\n")); return; } ShowCursor(FALSE); SetCursor(LoadCursor(NULL, IDC_ARROW)); //显示文件尺寸 Printf(hwnd, TEXT("File size =%u bytes\r\n\r\n"), pbmfh->bfSize); //显示BITMAPFILEHEADER结构体 Printf(hwnd, TEXT("BitmapFileHeader结构体\r\n")); Printf(hwnd, TEXT("\t.bfType =0x%X\r\n"), pbmfh->bfType); Printf(hwnd, TEXT("\t.bfSize =%u bytes\r\n"), pbmfh->bfSize); Printf(hwnd, TEXT("\t.bfReserved1 =%u\r\n"), pbmfh->bfReserved1); Printf(hwnd, TEXT("\t.bfReserved2 =%u\r\n"), pbmfh->bfReserved2); Printf(hwnd, TEXT("\t.bfOffBits =%u\r\n\r\n"), pbmfh->bfOffBits); //判断信息头的类型 pbmih = (BITMAPV5HEADER*)((BYTE*)pbmfh + sizeof(BITMAPFILEHEADER)); //指向信息头 switch (pbmih->bV5Size) { case sizeof(BITMAPCOREHEADER) : i = 0; break; case sizeof(BITMAPINFOHEADER) : i = 1; szV = TEXT("i"); break; case sizeof(BITMAPV4HEADER) : i = 2; szV = TEXT("V4"); break; case sizeof(BITMAPV5HEADER) : i = 3; szV = TEXT("V5"); break; default: Printf(hwnd, TEXT("Unknown header size of %u.\r\n\r\n"), pbmih->bV5Size); free(pbmfh); return; } //显示信息头名称 Printf(hwnd, TEXT(" %s\r\n"), szInfoName[i]); //显示BITMAPCOREHEADER 各字段信息 if (pbmih->bV5Size == sizeof(BITMAPCOREHEADER)) { pbmch = (BITMAPCOREHEADER*)pbmih; Printf(hwnd, TEXT("\t.bcSize =%u bytes\r\n"), pbmch->bcSize); Printf(hwnd, TEXT("\t.bcWidth =%u\r\n"), pbmch->bcWidth); Printf(hwnd, TEXT("\t.bcHeight =%u\r\n"), pbmch->bcHeight); Printf(hwnd, TEXT("\t.bcPlanes =%u\r\n"), pbmch->bcPlanes); Printf(hwnd, TEXT("\t.bcBitCount =%u\r\n\r\n"), pbmch->bcBitCount); free(pbmfh); return; } //显示BITMAPINFOHEADER 各字段信息 Printf(hwnd, TEXT("\t.b%sSize =%u bytes\r\n"), szV, pbmih->bV5Size); Printf(hwnd, TEXT("\t.b%sWidth =%u\r\n"), szV, pbmih->bV5Width); Printf(hwnd, TEXT("\t.b%sHeight =%u\r\n"), szV, pbmih->bV5Height); Printf(hwnd, TEXT("\t.b%sPlanes =%u\r\n"), szV, pbmih->bV5Planes); Printf(hwnd, TEXT("\t.b%sBitCount =%u\r\n"), szV, pbmih->bV5BitCount); Printf(hwnd, TEXT("\t.b%sCompression =%s\r\n"), szV, szCompression[min(4, pbmih->bV5Compression)]); Printf(hwnd, TEXT("\t.b%sSizeImage =%u\r\n"), szV, pbmih->bV5SizeImage); Printf(hwnd, TEXT("\t.b%sXPelsPerMeter =%i\r\n"), szV, pbmih->bV5XPelsPerMeter); Printf(hwnd, TEXT("\t.b%sYPelsPerMeter =%i\r\n"), szV, pbmih->bV5YPelsPerMeter); Printf(hwnd, TEXT("\t.b%sClrUsed =%i\r\n"), szV, pbmih->bV5ClrUsed); Printf(hwnd, TEXT("\t.b%sClrImportant =%i\r\n\r\n"), szV, pbmih->bV5ClrImportant); if (pbmih->bV5Size == sizeof(BITMAPINFOHEADER)) { if (pbmih->bV5Compression == BI_BITFIELDS) { Printf(hwnd, TEXT("Red Mask = %08X\r\n"), pbmih->bV5RedMask); Printf(hwnd, TEXT("Green Mask = %08X\r\n"), pbmih->bV5GreenMask); Printf(hwnd, TEXT("Blue Mask = %08X\r\n\r\n"), pbmih->bV5BlueMask); } free(pbmfh); return; } //显示BITMAPV4HEADER额外的字段 Printf(hwnd, TEXT("\t.b%sRedMask = %08X\r\n"), szV, pbmih->bV5RedMask); Printf(hwnd, TEXT("\t.b%sGreenMask = %08X\r\n"), szV, pbmih->bV5GreenMask); Printf(hwnd, TEXT("\t.b%sBlueMask = %08X\r\n"), szV, pbmih->bV5BlueMask); Printf(hwnd, TEXT("\t.b%sAlphaMask = %08X\r\n"), szV, pbmih->bV5AlphaMask); Printf(hwnd, TEXT("\t.b%sCSType = %u\r\n"), szV, pbmih->bV5CSType); Printf(hwnd, TEXT("\t.b%sEndpoints.ciexyzRed.ciexyzX = %08X\r\n"), szV, pbmih->bV5Endpoints.ciexyzRed.ciexyzX); Printf(hwnd, TEXT("\t.b%sEndpoints.ciexyzRed.ciexyzY = %08X\r\n"), szV, pbmih->bV5Endpoints.ciexyzRed.ciexyzY); Printf(hwnd, TEXT("\t.b%sEndpoints.ciexyzRed.ciexyzZ = %08X\r\n"), szV, pbmih->bV5Endpoints.ciexyzRed.ciexyzZ); Printf(hwnd, TEXT("\t.b%sEndpoints.ciexyzGreen.ciexyzX = %08X\r\n"), szV, pbmih->bV5Endpoints.ciexyzGreen.ciexyzX); Printf(hwnd, TEXT("\t.b%sEndpoints.ciexyzGreen.ciexyzY = %08X\r\n"), szV, pbmih->bV5Endpoints.ciexyzGreen.ciexyzY); Printf(hwnd, TEXT("\t.b%sEndpoints.ciexyzGreen.ciexyzZ = %08X\r\n"), szV, pbmih->bV5Endpoints.ciexyzGreen.ciexyzZ); Printf(hwnd, TEXT("\t.b%sEndpoints.ciexyzBlue.ciexyzX = %08X\r\n"), szV, pbmih->bV5Endpoints.ciexyzBlue.ciexyzX); Printf(hwnd, TEXT("\t.b%sEndpoints.ciexyzBlue.ciexyzY = %08X\r\n"), szV, pbmih->bV5Endpoints.ciexyzBlue.ciexyzY); Printf(hwnd, TEXT("\t.b%sEndpoints.ciexyzBlue.ciexyzZ = %08X\r\n"), szV, pbmih->bV5Endpoints.ciexyzBlue.ciexyzZ); Printf(hwnd, TEXT("\t.b%sGammaRed = %08X\r\n"), szV, pbmih->bV5GammaRed); Printf(hwnd, TEXT("\t.b%sGammaGreen = %08X\r\n"), szV, pbmih->bV5GammaGreen); Printf(hwnd, TEXT("\t.b%sGammaBlue = %08X\r\n\r\n"), szV, pbmih->bV5GammaBlue); if (pbmih->bV5Size == sizeof(BITMAPV4HEADER)) { free(pbmfh); return; } //显示BITMAPV5HEADER额外的字段 Printf(hwnd, TEXT("\t.b%sIntent = %u\r\n"), szV, pbmih->bV5Intent); Printf(hwnd, TEXT("\t.b%sProfileData = %u\r\n"), szV, pbmih->bV5ProfileData); Printf(hwnd, TEXT("\t.b%sProfileSize = %u\r\n"), szV, pbmih->bV5ProfileSize); Printf(hwnd, TEXT("\t.b%sReserved = %u\r\n\r\n"), szV, pbmih->bV5Reserved); free(pbmfh); return; } LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { static HWND hwndEdit; static TCHAR szFileName[MAX_PATH], szTitleName[MAX_PATH]; switch (message) { case WM_CREATE: hwndEdit = CreateWindow(TEXT("edit"), NULL, WS_CHILD | WS_VISIBLE | WS_BORDER | WS_VSCROLL | WS_HSCROLL | ES_MULTILINE | ES_AUTOVSCROLL | ES_READONLY, 0, 0, 0, 0, hwnd, (HMENU)1, ((LPCREATESTRUCT)lParam)->hInstance, NULL); DibFileInitialize(hwnd); return 0; case WM_SIZE: MoveWindow(hwndEdit, 0, 0, LOWORD(lParam), HIWORD(lParam), TRUE); return 0; case WM_COMMAND: switch (LOWORD(wParam)) { case IDM_FILE_OPEN: if (DibFileOpenDlg(hwnd, szFileName, szTitleName)) { DisplayDibHeaders(hwndEdit, szFileName); } return 0; } break; case WM_DESTROY: PostQuitMessage(0); return 0; } return DefWindowProc(hwnd, message, wParam, lParam); }
//DibFile.h
/*----------------------------------------------------- DIBFILE.H ---- Header File for DIBFILE.C ------------------------------------------------------*/ #pragma once #include <windows.h> void DibFileInitialize(HWND hwnd); BOOL DibFileOpenDlg(HWND hwnd, PTSTR pstrFileName, PTSTR pstrTitleName); BOOL DibFileSaveDlg(HWND hwnd, PTSTR pstrFileName, PTSTR pstrTitleName); BITMAPFILEHEADER* DibLoadImage(PTSTR pstrFileName); BOOL DibSaveImage(PTSTR pstrFileName, BITMAPFILEHEADER*);
//DibFile.c
#include "DibFile.h" static OPENFILENAME ofn; void DibFileInitialize(HWND hwnd) { static TCHAR szFilter[] = TEXT("Bitmap Files (*.BMP)\0*.bmp\0")\ TEXT("All Files(*.*)\0*.*\0\0"); ofn.lStructSize = sizeof(OPENFILENAME); ofn.hwndOwner = hwnd; ofn.hInstance = NULL; ofn.lpstrFilter = szFilter; ofn.lpstrCustomFilter = NULL; ofn.nMaxCustFilter = 0; ofn.nFilterIndex = 0; ofn.lpstrFile = NULL; //在打开和关闭中设置 ofn.nMaxFile = MAX_PATH; ofn.lpstrFileTitle = NULL; //在打开和关闭函数中设置 ofn.nMaxFileTitle = MAX_PATH; ofn.lpstrInitialDir = NULL; ofn.lpstrTitle = NULL; ofn.Flags = 0; //在打开和关闭函数中设置 ofn.nFileOffset = 0; ofn.nFileExtension = 0; ofn.lpstrDefExt = TEXT("bmp"); //默认扩展名 ofn.lCustData = 0; ofn.lpfnHook = NULL; ofn.lpTemplateName = NULL; } BOOL DibFileOpenDlg(HWND hwnd, PTSTR pstrFileName, PTSTR pstrTitleName) { ofn.hwndOwner = hwnd; ofn.lpstrFile = pstrFileName; ofn.lpstrFileTitle = pstrTitleName; ofn.Flags = 0; return GetOpenFileName(&ofn); } BOOL DibFileSaveDlg(HWND hwnd, PTSTR pstrFileName, PTSTR pstrTitleName) { ofn.hwndOwner = hwnd; ofn.lpstrFile = pstrFileName; ofn.lpstrFileTitle = pstrTitleName; ofn.Flags = OFN_OVERWRITEPROMPT; return GetSaveFileName(&ofn); } BITMAPFILEHEADER* DibLoadImage(PTSTR pstrFileName) { BOOL bSuccess; DWORD dwFileSize, dwHighSize, dwBytesRead; HANDLE hFile; BITMAPFILEHEADER* pbmfh; hFile = CreateFile(pstrFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL); if (hFile == INVALID_HANDLE_VALUE) return NULL; //返回文件大小的低位字,保存在dwFileSize中,高位字保存在dwHighSize中 dwFileSize = GetFileSize(hFile, &dwHighSize); if (dwHighSize) //文件太大,超过4G则dwHighSize不为0,退出 { CloseHandle(hFile); return NULL; } //为位图文件分配内存,内存指针由文件头指针保管 pbmfh = malloc(dwFileSize); if (!pbmfh) { CloseHandle(hFile); return NULL; } //读位图文件到内存 bSuccess = ReadFile(hFile, pbmfh, dwFileSize, &dwBytesRead, NULL); CloseHandle(hFile); if ((!bSuccess) || (dwBytesRead != dwFileSize) || (pbmfh->bfType != *(WORD*)"BM") || //位图标志“BM” (pbmfh->bfSize != dwFileSize)) { free(pbmfh); return NULL; } return pbmfh; } BOOL DibSaveImage(PTSTR pstrFileName, BITMAPFILEHEADER* pbmfh) { BOOL bSuccess; DWORD dwBytesWritten; HANDLE hFile; hFile = CreateFile(pstrFileName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (hFile == INVALID_HANDLE_VALUE) return FALSE; bSuccess = WriteFile(hFile, pbmfh, pbmfh->bfSize, &dwBytesWritten, NULL); CloseHandle(hFile); if ((!bSuccess) || (dwBytesWritten != pbmfh->bfSize)) { DeleteFile(pstrFileName); return FALSE; } return TRUE; }
//resource.h
//resource.h //{{NO_DEPENDENCIES}} // Microsoft Visual C++ 生成的包含文件。 // 供 DIBHeads.rc 使用 // #define IDM_FILE_OPEN 101 // Next default values for new objects // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS #define _APS_NEXT_RESOURCE_VALUE 103 #define _APS_NEXT_COMMAND_VALUE 40004 #define _APS_NEXT_CONTROL_VALUE 1001 #define _APS_NEXT_SYMED_VALUE 101 #endif #endif
//DibHeads.c
// Microsoft Visual C++ generated resource script. // #include "resource.h" #define APSTUDIO_READONLY_SYMBOLS ///////////////////////////////////////////////////////////////////////////// // // Generated from the TEXTINCLUDE 2 resource. // #include "winres.h" ///////////////////////////////////////////////////////////////////////////// #undef APSTUDIO_READONLY_SYMBOLS ///////////////////////////////////////////////////////////////////////////// // 中文(简体,中国) resources #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_CHS) LANGUAGE LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED #ifdef APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // TEXTINCLUDE // 1 TEXTINCLUDE BEGIN "resource.h\0" END 2 TEXTINCLUDE BEGIN "#include ""winres.h""\r\n" "\0" END 3 TEXTINCLUDE BEGIN "\r\n" "\0" END #endif // APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // Menu // DIBHEADS MENU BEGIN POPUP "&File" BEGIN MENUITEM "&Open...\tCtrl+O", IDM_FILE_OPEN END END ///////////////////////////////////////////////////////////////////////////// // // Accelerator // DIBHEADS ACCELERATORS BEGIN "^O", IDM_FILE_OPEN, ASCII, NOINVERT END #endif // 中文(简体,中国) resources ///////////////////////////////////////////////////////////////////////////// #ifndef APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // Generated from the TEXTINCLUDE 3 resource. // ///////////////////////////////////////////////////////////////////////////// #endif // not APSTUDIO_INVOKED