zoukankan      html  css  js  c++  java
  • 第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
    
    "), szFileName);
        SetCursor(LoadCursor(NULL, IDC_WAIT));
        ShowCursor(TRUE);
    
        //读取文件
        pbmfh = DibLoadImage(szFileName);
        if (pbmfh == NULL)
        {
            Printf(hwnd, TEXT("Could not read file.
    
    "));
            return;
        }
        ShowCursor(FALSE);
        SetCursor(LoadCursor(NULL, IDC_ARROW));
    
        //显示文件尺寸
        Printf(hwnd, TEXT("File size =%u bytes
    
    "), pbmfh->bfSize);
        //显示BITMAPFILEHEADER结构体
        Printf(hwnd, TEXT("BitmapFileHeader结构体
    "));
        Printf(hwnd, TEXT("	.bfType =0x%X
    "), pbmfh->bfType);
        Printf(hwnd, TEXT("	.bfSize =%u bytes
    "), pbmfh->bfSize);
        Printf(hwnd, TEXT("	.bfReserved1 =%u
    "), pbmfh->bfReserved1);
        Printf(hwnd, TEXT("	.bfReserved2 =%u
    "), pbmfh->bfReserved2);
        Printf(hwnd, TEXT("	.bfOffBits =%u
    
    "), 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.
    
    "), pbmih->bV5Size);
            free(pbmfh);
            return;
        }
        //显示信息头名称
        Printf(hwnd, TEXT(" %s
    "), szInfoName[i]);
        //显示BITMAPCOREHEADER 各字段信息
        if (pbmih->bV5Size == sizeof(BITMAPCOREHEADER))
        {
            pbmch = (BITMAPCOREHEADER*)pbmih;
            Printf(hwnd, TEXT("	.bcSize =%u bytes
    "), pbmch->bcSize);
            Printf(hwnd, TEXT("	.bcWidth =%u
    "), pbmch->bcWidth);
            Printf(hwnd, TEXT("	.bcHeight =%u
    "), pbmch->bcHeight);
            Printf(hwnd, TEXT("	.bcPlanes =%u
    "), pbmch->bcPlanes);
            Printf(hwnd, TEXT("	.bcBitCount =%u
    
    "), pbmch->bcBitCount);
            free(pbmfh);
            return;
        }
        //显示BITMAPINFOHEADER 各字段信息
        Printf(hwnd, TEXT("	.b%sSize =%u bytes
    "), szV, pbmih->bV5Size);
        Printf(hwnd, TEXT("	.b%sWidth =%u
    "), szV, pbmih->bV5Width);
        Printf(hwnd, TEXT("	.b%sHeight =%u
    "), szV, pbmih->bV5Height);
        Printf(hwnd, TEXT("	.b%sPlanes =%u
    "), szV, pbmih->bV5Planes);
        Printf(hwnd, TEXT("	.b%sBitCount =%u
    "), szV, pbmih->bV5BitCount);
        Printf(hwnd, TEXT("	.b%sCompression =%s
    "), szV, szCompression[min(4, pbmih->bV5Compression)]);
        Printf(hwnd, TEXT("	.b%sSizeImage =%u
    "), szV, pbmih->bV5SizeImage);
        Printf(hwnd, TEXT("	.b%sXPelsPerMeter =%i
    "), szV, pbmih->bV5XPelsPerMeter);
        Printf(hwnd, TEXT("	.b%sYPelsPerMeter =%i
    "), szV, pbmih->bV5YPelsPerMeter);
        Printf(hwnd, TEXT("	.b%sClrUsed =%i
    "), szV, pbmih->bV5ClrUsed);
        Printf(hwnd, TEXT("	.b%sClrImportant =%i
    
    "), szV, pbmih->bV5ClrImportant);
        if (pbmih->bV5Size == sizeof(BITMAPINFOHEADER))
        {
            if (pbmih->bV5Compression == BI_BITFIELDS)
            {
                Printf(hwnd, TEXT("Red Mask = %08X
    "), pbmih->bV5RedMask);
                Printf(hwnd, TEXT("Green Mask = %08X
    "), pbmih->bV5GreenMask);
                Printf(hwnd, TEXT("Blue Mask = %08X
    
    "), pbmih->bV5BlueMask);
            }
            free(pbmfh);
            return;
        }
        //显示BITMAPV4HEADER额外的字段
        Printf(hwnd, TEXT("	.b%sRedMask     = %08X
    "), szV, pbmih->bV5RedMask);
        Printf(hwnd, TEXT("	.b%sGreenMask   = %08X
    "), szV, pbmih->bV5GreenMask);
        Printf(hwnd, TEXT("	.b%sBlueMask    = %08X
    "), szV, pbmih->bV5BlueMask);
        Printf(hwnd, TEXT("	.b%sAlphaMask   = %08X
    "), szV, pbmih->bV5AlphaMask);
        Printf(hwnd, TEXT("	.b%sCSType      = %u
    "), szV, pbmih->bV5CSType);
        Printf(hwnd, TEXT("	.b%sEndpoints.ciexyzRed.ciexyzX   = %08X
    "), szV, pbmih->bV5Endpoints.ciexyzRed.ciexyzX);
        Printf(hwnd, TEXT("	.b%sEndpoints.ciexyzRed.ciexyzY   = %08X
    "), szV, pbmih->bV5Endpoints.ciexyzRed.ciexyzY);
        Printf(hwnd, TEXT("	.b%sEndpoints.ciexyzRed.ciexyzZ   = %08X
    "), szV, pbmih->bV5Endpoints.ciexyzRed.ciexyzZ);
        Printf(hwnd, TEXT("	.b%sEndpoints.ciexyzGreen.ciexyzX   = %08X
    "), szV, pbmih->bV5Endpoints.ciexyzGreen.ciexyzX);
        Printf(hwnd, TEXT("	.b%sEndpoints.ciexyzGreen.ciexyzY   = %08X
    "), szV, pbmih->bV5Endpoints.ciexyzGreen.ciexyzY);
        Printf(hwnd, TEXT("	.b%sEndpoints.ciexyzGreen.ciexyzZ   = %08X
    "), szV, pbmih->bV5Endpoints.ciexyzGreen.ciexyzZ);
        Printf(hwnd, TEXT("	.b%sEndpoints.ciexyzBlue.ciexyzX   = %08X
    "), szV, pbmih->bV5Endpoints.ciexyzBlue.ciexyzX);
        Printf(hwnd, TEXT("	.b%sEndpoints.ciexyzBlue.ciexyzY   = %08X
    "), szV, pbmih->bV5Endpoints.ciexyzBlue.ciexyzY);
        Printf(hwnd, TEXT("	.b%sEndpoints.ciexyzBlue.ciexyzZ   = %08X
    "), szV, pbmih->bV5Endpoints.ciexyzBlue.ciexyzZ);
        Printf(hwnd, TEXT("	.b%sGammaRed   = %08X
    "), szV, pbmih->bV5GammaRed);
        Printf(hwnd, TEXT("	.b%sGammaGreen   = %08X
    "), szV, pbmih->bV5GammaGreen);
        Printf(hwnd, TEXT("	.b%sGammaBlue   = %08X
    
    "), szV, pbmih->bV5GammaBlue);
    
        if (pbmih->bV5Size == sizeof(BITMAPV4HEADER))
        {
            free(pbmfh);
            return;
        }
        //显示BITMAPV5HEADER额外的字段
        Printf(hwnd, TEXT("	.b%sIntent   = %u
    "), szV, pbmih->bV5Intent);
        Printf(hwnd, TEXT("	.b%sProfileData   = %u
    "), szV, pbmih->bV5ProfileData);
        Printf(hwnd, TEXT("	.b%sProfileSize   = %u
    "), szV, pbmih->bV5ProfileSize);
        Printf(hwnd, TEXT("	.b%sReserved      = %u
    
    "), 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)*.bmp")
            TEXT("All Files(*.*)*.*");
        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"
    END
    2 TEXTINCLUDE
    BEGIN
    "#include ""winres.h""
    "
    ""
    END
    3 TEXTINCLUDE
    BEGIN
    "
    "
    ""
    END
    #endif    // APSTUDIO_INVOKED
    /////////////////////////////////////////////////////////////////////////////
    //
    // Menu
    //
    DIBHEADS MENU
    BEGIN
    POPUP "&File"
    BEGIN
    MENUITEM "&Open...	Ctrl+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
  • 相关阅读:
    centos下安装Anaconda
    centos下安装python2.7.9和pip以及数据科学常用的包
    mysql基础(5)-关联(mysql+pandas)
    mysql基础(4)-数据导入
    mysql基础(3)-高级查询
    mysql基础(2)-数据处理(mysql+pandas)
    mysql基础(1)-基本操作
    创建线程的三种方法
    Jar 包 及运行Jar包
    导出成可运行jar包时所遇问题的解决办法
  • 原文地址:https://www.cnblogs.com/5iedu/p/4698982.html
Copyright © 2011-2022 走看看