第15章 设备相关位图_15.1 DIB文件格式

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)即,
 2^bcBitCount。

新增了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位为颜色遮罩,分别为红色、绿色、蓝色遮罩。
注意:
1、 “从上到下”,即biHeight<0的图像不能被压缩。
2、BI_RGB时,表示没压缩的,跟正常的存储是一样的,具体请参考1、4、8、16、24、32位的DIB像素存储格式


DWORD biSizeImage


图像字节数(即bfOffsetBits后面数据区大小)
1、如果biCompression为BI_RLE4或BI_RLE8,则该字段存储DIB像素数据的大小(单位:字节)。

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
时间: 2024-10-30 18:19:22

第15章 设备相关位图_15.1 DIB文件格式的相关文章

第15章 设备相关位图_15.3 DIB和DDB的结合

15.3.1 从DIB创建DDB (1)hBitmap =CreateDIBitmap(…)——注意这名称会误导,实际上创建的是DDB 参数 说明 hdc 设备环境句柄,可以为NULL. pInfoHdr 指向DIB信息头的指针,即BITMAPINFOHEADER fInit 0或CBM_INIT.CBM_INIT指定用后面3个参数来初始化DDB中的像素位 pBits DIB像素位的指针 pInfo DIB信息指针,即BITMAPINFO(包含BITMAPINFOHEADER和颜色表) fClr

第15章 设备相关位图_15.2 显示和打印DIB

15.2.1 探究DIB (1)DIB文件的结构 整个文件 紧凑DIB(整个文件除文件头) 文件头(File Header) 信息头(Information Header) 信息头(Information Header) 颜色表(Color Table) 颜色表(Color Table) 像素位(Pixel Bits) 像素位(Pixel Bits) 注意:①紧凑DIB在内存中是连续的,即整个DIB存在单个内存块中 ②DIB载入内存时,像素位与信息头可以分别存在两个内存块,即内存不连续. (2)

【大话存储II】学习笔记(15章),文件级集群系统

[大话存储II]学习笔记(15章),块级集群存储系统里面分析的主要是块集群系统,同样文件级存储也可以集群化. 因为NAS系统的前端网络是以太网,速度比较低,导致NAS主要用于一些非关键业务中,比如文件共享.但是一些特殊应用也需要多主机同时访问某个大文件,比如3D渲染集群等.如果我们使用块集群存储系统,则会存在一个问题,需要在应用程序上引入文件锁,而NAS的文件系统一般都自带有文件锁机制,所以还不如把NAS存储系统进行集群化. 在谈怎么样把NAS系统进行集群化之前,我们说说集群文件系统的架构.集群

《白帽子讲WEB安全》学习笔记之第15章 web server配置安全

第15章 web server配置安全 15.1 apache安全 在linux部署安装web Server时候一定主要要使用"最小权限原则".尽量不要使用root部署. 15.2 nginx安全 Nginx 安全配置指南技术手册 PDF 下载 免费下载地址在http://linux.linuxidc.com/ 用户名与密码都是www.linuxidc.com 具体下载目录在 /pub/服务器相关教程/Nginx/Nginx 安全配置指南技术手册/ 参考资料:http://my.osc

第15章 就不能换DB吗?—抽象工厂模式

由于抽象工厂在我们编程当中经常使用和常见,所有本篇文章对<大话设计模式>中的15章做了很详细的比较.通过一个Dao层可以更换访问任意数据库的例子来学习抽象工厂模式.例如:Dao层可以访问Sqlserver数据库,也可以访问Access数据库,当程序新增访问Oracle数据库时,无需修改现有代码,只需要添加访问Oracle相关的类就可以,实现了开闭原则.本篇文章的例子中每种数据库上都有User和Department表,我们Dao层对这两个表进行查询和插入操作. 最基本数据库访问 一下是访问Sql

第12 13 14 15章总结与感悟

第12章 用户体验 12.1用户体验的要素 1.1用户的第一印象 1.2从用户的角度考虑问题,这需要“同理心”(理解别人的处境,心理,动机和能力) 用户需要帮助,但是用户没那么笨 光吃狗食也不够 1.3软件服务始终记住用户的选择 1.4短期刺激和长期影响 1.5不让用户犯简单的错误 1.6用户体验和质量 1.7情感设计 12.2用户体验设计的步骤和目标 12.3评价标准 1.尽快提供可感触的反馈 2.系统界面符合用户的现实管理 3.用户有控制权 4.一致性和标准化 5.适合各种类型的用户 6.帮

3.30日第八次作业,第14章,采购管理,15章,信息文档和配置管理

3.30日第八次作业,第14章,采购管理,15章,信息文档和配置管理   第14章.采购管理1.采购管理包括哪些过程?(记)P382-383 答:1).编制采购计划.2).编制询价计划.3).询价.招投标.4).供方选择.5).合同管理.6).合同收尾. 2.编制采购计划过程的成果是什么?P386-387 答:1).采购管理计划.2).采购工作说明书. 3.判断:每个采购工作说明书都来自于项目范围基准.P387 答:是的. 4.结合P388页表14-1,工作说明书应该清楚地描述哪些内容?P388

java第15章示例代码

import java.util.Scanner; /** * * @author asus第15章示例代码1 全桂群2017.4.9 * */public class Registter { /** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub Scanner input = new Scanner(System.in); String uname, pw

【Android】15.0 第15章 广播和通知&mdash;本章示例主界面

分类:C#.Android.VS2015: 创建日期:2016-02-28 一.简介 广播(Broadcast):其功能类似于收音机的广播,你只要调到那个台(只要在接收的类中注册了要接收的广播),就能收到这个台播放的信息. 通知(Notifications):安卓的服务组件(Android Service,后面章节再细讲)本来是在后台运行的,可是,用户可能希望关注某个后台任务当前正在执行的状态或者结果,此时就可以利用"通知"在前台告诉用户. 二.本章示例主界面 1.运行截图 这个截图也