xShandow 发表于 2004-12-2 15:41

BMP位图结构很详细的说明和示例。

<P  align=center><B>BMP文件结构的探索<p></p></B></P>
<P  align=center><a href="mailtwhatif@51.net" target="_blank" >WhatIf</A> 2004-9-10<p></p></P>
<P >一、文件格式<p></p></P>
<P >Bmp文件是非常常用的位图文件,无论是游戏还是其他都被广泛使用。针对bmp文件的处理也有一堆现成的api进行调用,然而文件内部究竟怎样,如何自己来解析这样的文件呢?为了消除无聊,我用了几天时间来研究了一下,同时作为学习笔记,进行记录。<p></p></P>
<P >首先,整个bmp文件的内容可以分为3到4块。之所以分为3到4块而不是固定的值,是因为,对于bmp来说可能存在调色板或者一些掩码。具体稍候讨论。<p></p></P>
<P >第一块是bmp的文件头用于描述整个bmp文件的情况。结构如下:<p></p></P><PRE>typedef struct tagBITMAPFILEHEADER { <p></p></PRE><PRE>  WORD    bfType;    <p></p></PRE><PRE>  DWORD   bfSize; <p></p></PRE><PRE>  WORD    bfReserved1; <p></p></PRE><PRE>  WORD    bfReserved2; <p></p></PRE><PRE>  DWORD   bfOffBits; <p></p></PRE>
<P ><FONT face="Times New Roman">} BITMAPFILEHEADER, *PBITMAPFILEHEADER;<p></p></FONT></P>
<P >这些信息相当有用,如果你想直接来解析<FONT face="Times New Roman">bmp</FONT>文件。第一个<FONT face="Times New Roman">bfType</FONT>用于表示文件类型,如果它是<FONT face="Times New Roman">bmp</FONT>文件,那么它这个位置的值一定是<FONT face="Times New Roman">”BM” </FONT>也就是<FONT face="Times New Roman">0x4D42</FONT>。第二个<FONT face="Times New Roman">bfSize</FONT>表示整个文件的字节数。第三第四个<FONT face="Times New Roman"> </FONT>则保留,目前无意义,最后一个相当重要,表示,位图的数据信息离文件头的偏移量,以字节为单位。<p></p></P>
<P >第二块是位图信息头,即<FONT face="Times New Roman">BITMAPINFOHEADER</FONT>,用于描述整个位图文件的情况。以下挑重要的数据进行解释<p></p></P>
<P >typedef struct tagBITMAPINFOHEADER{<p></p></P>
<P >  DWORD  biSize; //表示本结构的大小<p></p></P>
<P >  LONG   biWidth; //位图的宽度<p></p></P>
<P >  LONG   biHeight; //位图的高度<p></p></P>
<P  align=left>WORD   biPlanes; //永远为1 ,由于没有用过所以 没做研究 附msdn解释<p></p></P>
<P  align=left>//<FONT face="Times New Roman">Specifies the number of planes for the target device. This value must be set to 1. <p></p></FONT></P>
<P >  WORD   biBitCount;//位图的位数  分为1 4 8 16 24 32 本文没对1 4 进行研究<p></p></P>
<P >  DWORD  biCompression; //本以为压缩类型,但是却另外有作用,稍候解释<p></p></P>
<P >  DWORD  biSizeImage; //表示位图数据区域的大小以字节为单位<p></p></P>
<P >  LONG   biXPelsPerMeter; <p></p></P>
<P >  LONG   biYPelsPerMeter; <p></p></P>
<P >  DWORD  biClrUsed; <p></p></P>
<P >  DWORD  biClrImportant; <p></p></P>
<P >} BITMAPINFOHEADER, *PBITMAPINFOHEADER;<p></p></P>
<P >     第三块就是调色板信息或者掩码部分,如果是8位位图则存放调色板 ;16 与32位 位图则存放RGB颜色的掩码,这些掩码以DWORD大小来存放。<p></p></P>
<P >     最后一块就是位图的数据实体。<p></p></P>
<P >     以上文件信息可以在任意一篇bmp文件结构的文章中找到描述,所以本文只是稍微带过。<p></p></P>
<P><BR  clear=all> </P>
<P >二、4字节对其问题<p></p></P>
<P >     关于数据读取。Bmp文件有个重要特性,那就是对于数据区域而言,每行的数据它必须凑满4字节,如果没有满,则用冗余的数据来补齐。这个特性直接影响到我们读取位图数据的方法,因为在我们看来(x,y)的数据应该在 y*width+x这样的位置上 但是因为会有冗余信息 那么必须将width用width+该行的冗余量来处理,而由于位图文件有不同的位数,所以这样的计算也不尽相同。<p></p></P>
<P >     下面列出计算偏移量的一般公式。<p></p></P>
<P >     首先将位图信息读入一个UCHAR 的buffer中 :<p></p></P>
<P >     8位:<p></p></P>
<P  align=left>int pitch;<p></p></P>
<P  align=left>        if(width%4==0){<p></p></P>
<P  align=left>           pitch=width;<p></p></P>
<P  align=left>        }else{<p></p></P>
<P  align=left>           pitch=width+4-width%4;<p></p></P>
<P >       }<p></p></P>
<P >        index=buffer; 因为8位位图的数据区域存放的是调色板索引值,所以只需读取这个index<p></p></P>
<P >    16位<p></p></P>
<P >       int pitch=width+width%2;<p></p></P>
<P >        buffer[(y*pitch+x)*2] <p></p></P>
<P >buffer[(i*pitch+j)*2+1]<p></p></P>
<P >两个UCHAR内,存放的是(x,y)处的颜色信息<p></p></P>
<P >   24位<p></p></P>
<P >       int pitch=width%4;<p></p></P>
<P  align=left>        buffer[(y*width+x)*3+y*pitch];<p></p></P>
<P  align=left>        buffer[(y*width+x)*3+y*pitch+1];<p></p></P>
<P  align=left>buffer[(y*width+x)*3+y*pitch+2];<p></p></P>
<P  align=left>   32位<p></p></P>
<P  align=left>       由于一个象素就是4字节 所以无需补齐<p></p></P>
<P  align=left> <p></p></P>
<P  align=left>     虽然计算比较繁琐,但是这些计算是必须的,否则当你的位图每行的象素数不是4的倍数,那么y*width+x带给你的是一个扭曲的图片,当然如果你想做这样的旋转,也不错啊,至少我因为一开始没有考虑(不知道这个特性)让一个每行象素少1字节的16位图片变成了扭曲的菱形。<p></p></P>
<P  align=left> <p></p></P>
<P  align=left>三、有了数据分离RGB分量。<p></p></P>
<P  align=left>     由于我的测试代码用了GDI,所以我必须讲得到的某一个点的值分离成 24位模式下的RGB分离,这不是一件容易的工作。位图麻烦的地方之一就是他的格式太多,所以我们还是要分格式再讨论。<p></p></P>
<P  align=left>     8位<p></p></P>
<P  align=left>     通过第二部分提到的操作我们得到了一个index,这个值的范围是0~255 一共256个 正好是调色板的颜色数量。<p></p></P>
<P  align=left>     在8位bmp图片中 数据信息前256个RGBQUAD的大小开始就是调色板的信息。不过如果要组织成调色板还要一定的转换因为里面是RGBQUAD信息 r b 两个与调色板中的顺序是颠倒的。因为我不需要调色板设置所以我字节读取到RGBQUAD数组中,并且通过下面的表达式获取RGB值:<p></p></P>
<P  align=left>UCHAR r=quad.rgbRed;<p></p></P>
<P  align=left>           UCHAR g=quad.rgbGreen;<p></p></P>
<P  align=left>           UCHAR b=quad.rgbBlue;<p></p></P>
<P  align=left>16位<p></p></P>
<P  align=left>这是最麻烦的一个。因为在处理时有555 565 两种格式的区别,而且还有所谓压缩类型的区别。<p></p></P>
<P  align=left>之前的bitmapinfoheader里面提到一个biCompression<p></p></P>
<P  align=left>现在我们分两种情况讨论:BI_RGB和BI_BITFIELDS<p></p></P>
<P  align=left>当他等于BI_RGB时 只有555 这种格式,所以可以放心大胆的进行如下的数据分离:<p></p></P>
<P  align=left>UCHAR b=buffer[(i*pitch+j)*2]&amp;0x1F;<p></p></P>
<P  align=left>UCHAR g=(((buffer[(i*pitch+j)*2+1]&lt;&lt;6)&amp;0xFF)&gt;&gt;3)+(buffer[(i*pitch+j)*2]&gt;&gt;5);<p></p></P>
<P  align=left>UCHAR r=(buffer[(i*pitch+j)*2+1]&lt;&lt;1)&gt;&gt;3;<p></p></P>
<P  align=left> <p></p></P>
<P  align=left>希望不要被这个表达式折磨的眼花缭乱,我想既然你在看这篇文章,你就有能力阅读这样的代码,否则只能说你还没有到阅读这方面的地步,需要去学习基础的语法了。<p></p></P>
<P  align=left>有一点值得提醒的是由于有较多的位操作 ,所以在处理的时候在前一次操作的上面加上一对括号,我就曾经因为没有加而导致出现误差,另外虽然buffer中一个元素代表的是一个UCHAR 但是右移操作会自动增长为两字节 所以需要在进行一次与操作截取低位的1字节数据。<p></p></P>
<P  align=left>现在讨论BI_BITFIELDS。<p></p></P>
<P  align=left>这个模式下 既可以有555 也可以有565 。<p></p></P>
<P  align=left>555 格式 xrrrrrgggggbbbbb<p></p></P>
<P  align=left>565 格式 rrrrrggggggbbbbb<p></p></P>
<P  align=left>显然不同的格式处理不同,所以我们要首先判断处到底属于那种格式。<p></p></P>
<P  align=left>Bitmapinfoheader的biCompression为BI_BITFIELDS时,在位图数据区域前存在一个RGB掩码的描述是3个DWORD值,我们只需要读取其中的R或者G的掩码,来判断是那种格式。<p></p></P>
<P  align=left>以红色掩码为例 0111110000000000的时候就是555格式 1111100000000000就是565格式。<p></p></P>
<P  align=left>以下是565格式时的数据分离:<p></p></P>
<P  align=left>UCHAR b=buffer[(i*pitch+j)*2]&amp;0x1F;<p></p></P>
<P  align=left>UCHAR g=(((buffer[(i*pitch+j)*2+1]&lt;&lt;5)&amp;0xFF)&gt;&gt;2)+(buffer[(i*pitch+j)*2]&gt;&gt;5);<p></p></P>
<P  align=left>UCHAR r=buffer[(i*pitch+j)*2+1]&gt;&gt;3;<p></p></P>
<P  align=left> <p></p></P>
<P  align=left>现在我们得到了RGB各自的分量,但是还有一个新的问题,那就是由于两字节表示了3个颜色  555下每个颜色最多到0x1F 565格式下最大的绿色分量也就0x3F。所以我们需要一个转换 color=color*255/最大颜色数 即可<p></p></P>
<P  align=left>如565下RGB(r*0xFF/0x1F,g*0xFF/0x3F,b*0xFF/0x1F)<p></p></P>
<P  align=left>24位<p></p></P>
<P  align=left>UCHAR b=buffer[(i*width+j)*3+realPitch];<p></p></P>
<P  align=left>UCHAR g=buffer[(i*width+j)*3+1+realPitch];<p></p></P>
<P  align=left>UCHAR r=buffer[(i*width+j)*3+2+realPitch];<p></p></P>
<P  align=left>    32位<p></p></P>
<P  align=left>UCHAR b=buffer[(i*width+j)*4];<p></p></P>
<P  align=left>    UCHAR g=buffer[(i*width+j)*4+1];<p></p></P>
<P  align=left>    UCHAR r=buffer[(i*width+j)*4+2];<p></p></P>
<P  align=left> <p></p></P>
<P  align=left>四、剩余的问题<p></p></P>
<P  align=left>    当数据取到了,颜色也分离出来了 ,但是可能你绘出的位图是倒转的,这是因为有些位图的确是翻转的。通过bitmapinfoheader的biHeight可以判断是正常还是翻转,当biHeight&gt;0的时候颠倒,它小于0的时候正常,不过测试写到现在看到的文件都是颠倒过来的。<p></p></P>
<P  align=left> <p></p></P>
<P  align=left>五、相关测试代码:<p></p></P>
<P  align=left>    采用MFC 目的只是实现自行解析位图文件<p></p></P>
<P  align=left>void CBmpTestView::OnDraw(CDC* pDC)<p></p></P>
<P  align=left>{<p></p></P>
<P  align=left>    CBmpTestDoc* pDoc = GetDocument();<p></p></P>
<P  align=left>    ASSERT_VALID(pDoc);<p></p></P>
<P  align=left>    <p></p></P>
<P  align=left>    // TOD 在此处为本机数据添加绘制代码<p></p></P>
<P  align=left>    <p></p></P>
<P  align=left>    if(filename==""){<p></p></P>
<P  align=left>        return;<p></p></P>
<P  align=left>    }<p></p></P>
<P  align=left>    FILE *fp=fopen(filename,"r");<p></p></P>
<P  align=left>    if(fp==NULL){<p></p></P>
<P  align=left>        pDC-&gt;TextOut(100,200,"no file found");<p></p></P>
<P  align=left>        return;<p></p></P>
<P  align=left>    }<p></p></P>
<P  align=left>    BITMAPFILEHEADER fileheader;<p></p></P>
<P  align=left>    BITMAPINFO info;<p></p></P>
<P  align=left>    <p></p></P>
<P  align=left>    fread(&amp;fileheader,sizeof(fileheader),1,fp);<p></p></P>
<P  align=left>    if(fileheader.bfType!=0x4D42){<p></p></P>
<P  align=left>        pDC-&gt;TextOut(100,200,"无位图文件请选择位图文件");<p></p></P>
<P  align=left>        fclose(fp);<p></p></P>
<P  align=left>        return ;<p></p></P>
<P  align=left>    }<p></p></P>
<P  align=left>    fread(&amp;info.bmiHeader,sizeof(BITMAPINFOHEADER),1,fp);<p></p></P>
<P  align=left>    long width=info.bmiHeader.biWidth;<p></p></P>
<P  align=left>    long height=info.bmiHeader.biHeight;<p></p></P>
<P  align=left>    UCHAR *buffer=new UCHAR;<p></p></P>
<P  align=left>    fseek(fp,fileheader.bfOffBits,0);<p></p></P>
<P  align=left>    fread(buffer,info.bmiHeader.biSizeImage,1,fp);<p></p></P>
<P  align=left> <p></p></P>
<P  align=left>    if(info.bmiHeader.biBitCount==8){<p></p></P>
<P  align=left>       int pitch;<p></p></P>
<P  align=left>        if(width%4==0){<p></p></P>
<P  align=left>           pitch=width;<p></p></P>
<P  align=left>        }else{<p></p></P>
<P  align=left>           pitch=width+4-width%4;<p></p></P>
<P  align=left>       }<p></p></P>
<P  align=left>        RGBQUAD quad;<p></p></P>
<P  align=left>        fseek(fp,fileheader.bfOffBits-sizeof(RGBQUAD)*256,0);<p></p></P>
<P  align=left>        fread(quad,sizeof(RGBQUAD)*256,1,fp);<p></p></P>
<P  align=left>        if(height&gt;0){<p></p></P>
<P  align=left>           //height&gt;0 表示图片颠倒<p></p></P>
<P  align=left>           for(int i=0;i&lt;height;i++){<p></p></P>
<P  align=left>               for(int j=0;j&lt;width;j++){<p></p></P>
<P  align=left>                  int index=buffer;<p></p></P>
<P  align=left>                  UCHAR r=quad.rgbRed;<p></p></P>
<P  align=left>                  UCHAR g=quad.rgbGreen;<p></p></P>
<P  align=left>                  UCHAR b=quad.rgbBlue;<p></p></P>
<P  align=left>                   pDC-&gt;SetPixel(j,height-i,RGB(r,g,b));<p></p></P>
<P  align=left>               }<p></p></P>
<P  align=left>           }<p></p></P>
<P  align=left>        }else{<p></p></P>
<P  align=left>           for(int i=0;i&lt;0-height;i++){<p></p></P>
<P  align=left>               for(int j=0;j&lt;width;j++){<p></p></P>
<P  align=left>                  int index=buffer;<p></p></P>
<P  align=left>                  UCHAR r=quad.rgbRed;<p></p></P>
<P  align=left>                  UCHAR g=quad.rgbGreen;<p></p></P>
<P  align=left>                  UCHAR b=quad.rgbBlue;<p></p></P>
<P  align=left>                   pDC-&gt;SetPixel(j,i,RGB(r,g,b));<p></p></P>
<P  align=left>               }<p></p></P>
<P  align=left>           }<p></p></P>
<P  align=left>        }<p></p></P>
<P  align=left>    }else if(info.bmiHeader.biBitCount==16){<p></p></P>
<P  align=left>       int pitch=width+width%2;<p></p></P>
<P  align=left>        if(height&gt;0){<p></p></P>
<P  align=left>           //height&gt;0 表示图片颠倒<p></p></P>
<P  align=left>           if(info.bmiHeader.biCompression==BI_RGB){<p></p></P>
<P  align=left>               //该模式只有555<p></p></P>
<P  align=left>               for(int i=0;i&lt;height;i++){<p></p></P>
<P  align=left>                   for(int j=0;j&lt;width;j++){          <p></p></P>
<P  align=left>                      //5 5 5 格式<p></p></P>
<P  align=left>                      UCHAR b=buffer[(i*pitch+j)*2]&amp;0x1F;<p></p></P>
<P  align=left>                      UCHAR g=(((buffer[(i*pitch+j)*2+1]&lt;&lt;6)&amp;0xFF)&gt;&gt;3)+(buffer[(i*pitch+j)*2]&gt;&gt;5);<p></p></P>
<P  align=left>                      UCHAR r=(buffer[(i*pitch+j)*2+1]&lt;&lt;1)&gt;&gt;3;<p></p></P>
<P  align=left>                      pDC-&gt;SetPixel(j,height-i,RGB((r*0xFF)/0x1F,(g*0xFF)/0x1F,(b*0xFF)/0x1F));<p></p></P>
<P  align=left>                  }<p></p></P>
<P  align=left>               }<p></p></P>
<P  align=left>           }else if(info.bmiHeader.biCompression==BI_BITFIELDS){<p></p></P>
<P  align=left>               //该模式在bitmapinfoheader之后存在RGB掩码 每个掩码1 DWORD<p></p></P>
<P  align=left>               fseek(fp,fileheader.bfOffBits-sizeof(DWORD )*3,0);<p></p></P>
<P  align=left>               DWORD  rMask;<p></p></P>
<P  align=left>               fread(&amp;rMask,sizeof(DWORD ),1,fp);<p></p></P>
<P  align=left>               if(rMask==0x7C00){<p></p></P>
<P  align=left>                  // 5 5 5 格式<p></p></P>
<P  align=left>                   MessageBeep(0);<p></p></P>
<P  align=left>                   for(int i=0;i&lt;height;i++){<p></p></P>
<P  align=left>                      for(int j=0;j&lt;width;j++){<p></p></P>
<P  align=left>                          UCHAR b=buffer[(i*pitch+j)*2]&amp;0x1F;<p></p></P>
<P  align=left>                          UCHAR g=(((buffer[(i*pitch+j)*2+1]&lt;&lt;6)&amp;0xFF)&gt;&gt;3)+(buffer[(i*pitch+j)*2]&gt;&gt;5);<p></p></P>
<P  align=left>                          UCHAR r=(buffer[(i*pitch+j)*2+1]&lt;&lt;1)&gt;&gt;3;<p></p></P>
<P  align=left>                          pDC-&gt;SetPixel(j,height-i,RGB((r*0xFF)/0x1F,(g*0xFF)/0x1F,(b*0xFF)/0x1F));<p></p></P>
<P  align=left>                      }<p></p></P>
<P  align=left>                   }<p></p></P>
<P  align=left>               }else if(rMask==0xF800){<p></p></P>
<P  align=left>                  //5 6 5 格式<p></p></P>
<P  align=left>                   for(int i=0;i&lt;height;i++){<p></p></P>
<P  align=left>                      for(int j=0;j&lt;width;j++){<p></p></P>
<P  align=left>                          UCHAR b=buffer[(i*pitch+j)*2]&amp;0x1F;<p></p></P>
<P  align=left>                          UCHAR g=(((buffer[(i*pitch+j)*2+1]&lt;&lt;5)&amp;0xFF)&gt;&gt;2)+(buffer[(i*pitch+j)*2]&gt;&gt;5);<p></p></P>
<P  align=left>                          UCHAR r=buffer[(i*pitch+j)*2+1]&gt;&gt;3;<p></p></P>
<P  align=left>                          pDC-&gt;SetPixel(j,height-i,RGB(r*0xFF/0x1F,g*0xFF/0x3F,b*0xFF/0x1F));<p></p></P>
<P  align=left>                      }<p></p></P>
<P  align=left>                  }<p></p></P>
<P  align=left>               }<p></p></P>
<P  align=left>           }<p></p></P>
<P  align=left>        }else{<p></p></P>
<P  align=left>           if(info.bmiHeader.biCompression==BI_RGB){<p></p></P>
<P  align=left>               //该模式只有555<p></p></P>
<P  align=left>               for(int i=0;i&lt;0-height;i++){<p></p></P>
<P  align=left>                   for(int j=0;j&lt;width;j++){          <p></p></P>
<P  align=left>                      //5 5 5 格式<p></p></P>
<P  align=left>                      UCHAR b=buffer[(i*pitch+j)*2]&amp;0x1F;<p></p></P>
<P  align=left>                      UCHAR g=(((buffer[(i*pitch+j)*2+1]&lt;&lt;6)&amp;0xFF)&gt;&gt;3)+(buffer[(i*pitch+j)*2]&gt;&gt;5);<p></p></P>
<P  align=left>                      UCHAR r=(buffer[(i*pitch+j)*2+1]&lt;&lt;1)&gt;&gt;3;<p></p></P>
<P  align=left>                      pDC-&gt;SetPixel(j,i,RGB((r*0xFF)/0x1F,(g*0xFF)/0x1F,(b*0xFF)/0x1F));<p></p></P>
<P  align=left>                  }<p></p></P>
<P  align=left>               }<p></p></P>
<P  align=left>           }else if(info.bmiHeader.biCompression==BI_BITFIELDS){<p></p></P>
<P  align=left>               //该模式在bitmapinfoheader之后存在RGB掩码 每个掩码1 DWORD<p></p></P>
<P  align=left>               fseek(fp,fileheader.bfOffBits-sizeof(DWORD )*3,0);<p></p></P>
<P  align=left>               DWORD  rMask;<p></p></P>
<P  align=left>               fread(&amp;rMask,sizeof(DWORD ),1,fp);<p></p></P>
<P  align=left>               if(rMask==0x7C00){<p></p></P>
<P  align=left>                  // 5 5 5 格式<p></p></P>
<P  align=left>                   MessageBeep(0);<p></p></P>
<P  align=left>                   for(int i=0;i&lt;0-height;i++){<p></p></P>
<P  align=left>                      for(int j=0;j&lt;width;j++){<p></p></P>
<P  align=left>                          UCHAR b=buffer[(i*pitch+j)*2]&amp;0x1F;<p></p></P>
<P  align=left>                          UCHAR g=(((buffer[(i*pitch+j)*2+1]&lt;&lt;6)&amp;0xFF)&gt;&gt;3)+(buffer[(i*pitch+j)*2]&gt;&gt;5);<p></p></P>
<P  align=left>                          UCHAR r=(buffer[(i*pitch+j)*2+1]&lt;&lt;1)&gt;&gt;3;<p></p></P>
<P  align=left>                          pDC-&gt;SetPixel(j,i,RGB((r*0xFF)/0x1F,(g*0xFF)/0x1F,(b*0xFF)/0x1F));<p></p></P>
<P  align=left>                      }<p></p></P>
<P  align=left>                  }<p></p></P>
<P  align=left>               }else if(rMask==0xF800){<p></p></P>
<P  align=left>                  //5 6 5 格式<p></p></P>
<P  align=left>                   for(int i=0;i&lt;0-height;i++){<p></p></P>
<P  align=left>                      for(int j=0;j&lt;width;j++){<p></p></P>
<P  align=left>                          UCHAR b=buffer[(i*pitch+j)*2]&amp;0x1F;<p></p></P>
<P  align=left>                          UCHAR g=(((buffer[(i*pitch+j)*2+1]&lt;&lt;5)&amp;0xFF)&gt;&gt;2)+(buffer[(i*pitch+j)*2]&gt;&gt;5);<p></p></P>
<P  align=left>                          UCHAR r=buffer[(i*pitch+j)*2+1]&gt;&gt;3;<p></p></P>
<P  align=left>                          pDC-&gt;SetPixel(j,i,RGB(r*0xFF/0x1F,g*0xFF/0x3F,b*0xFF/0x1F));<p></p></P>
<P  align=left>                      }<p></p></P>
<P  align=left>                  }<p></p></P>
<P  align=left>               }<p></p></P>
<P  align=left>           }<p></p></P>
<P  align=left>       }<p></p></P>
<P  align=left>        //pDC-&gt;TextOut(100,200,"16位图");<p></p></P>
<P  align=left>    }else if(info.bmiHeader.biBitCount==24){<p></p></P>
<P  align=left>       int pitch=width%4;<p></p></P>
<P  align=left>       //b g r<p></p></P>
<P  align=left>        if(height&gt;0){<p></p></P>
<P  align=left>           //height&gt;0 表示图片颠倒<p></p></P>
<P  align=left>           for(int i=0;i&lt;height;i++){<p></p></P>
<P  align=left>               int realPitch=i*pitch;<p></p></P>
<P  align=left>               for(int j=0;j&lt;width;j++){                 <p></p></P>
<P  align=left>                  UCHAR b=buffer[(i*width+j)*3+realPitch];<p></p></P>
<P  align=left>                  UCHAR g=buffer[(i*width+j)*3+1+realPitch];<p></p></P>
<P  align=left>                  UCHAR r=buffer[(i*width+j)*3+2+realPitch];<p></p></P>
<P  align=left>                   pDC-&gt;SetPixel(j,height-i,RGB(r,g,b));<p></p></P>
<P  align=left>               }<p></p></P>
<P  align=left>           }<p></p></P>
<P  align=left>        }else{<p></p></P>
<P  align=left>           for(int i=0;i&lt;0-height;i++){<p></p></P>
<P  align=left>               int realPitch=i*pitch;<p></p></P>
<P  align=left>               for(int j=0;j&lt;width;j++){<p></p></P>
<P  align=left>                  UCHAR b=buffer[(i*width+j)*3+realPitch];<p></p></P>
<P  align=left>                  UCHAR g=buffer[(i*width+j)*3+1+realPitch];<p></p></P>
<P  align=left>                  UCHAR r=buffer[(i*width+j)*3+2+realPitch];<p></p></P>
<P  align=left>                   pDC-&gt;SetPixel(j,i,RGB(r,g,b));<p></p></P>
<P  align=left>               }<p></p></P>
<P  align=left>           }<p></p></P>
<P  align=left>       }<p></p></P>
<P  align=left>       <p></p></P>
<P  align=left>        //pDC-&gt;TextOut(100,200,"24位图");<p></p></P>
<P  align=left> <p></p></P>
<P  align=left>    }else if(info.bmiHeader.biBitCount==32){<p></p></P>
<P  align=left>       // b g r a<p></p></P>
<P  align=left>        if(height&gt;0){<p></p></P>
<P  align=left>           //height&gt;0 表示图片颠倒<p></p></P>
<P  align=left>           for(int i=0;i&lt;0-height;i++){<p></p></P>
<P  align=left>               for(int j=0;j&lt;width;j++){<p></p></P>
<P  align=left>                  UCHAR b=buffer[(i*width+j)*4];<p></p></P>
<P  align=left>                  UCHAR g=buffer[(i*width+j)*4+1];<p></p></P>
<P  align=left>                  UCHAR r=buffer[(i*width+j)*4+2];<p></p></P>
<P  align=left>                   pDC-&gt;SetPixel(j,height-i,RGB(r,g,b));<p></p></P>
<P  align=left>               }<p></p></P>
<P  align=left>           }<p></p></P>
<P  align=left>        }else{<p></p></P>
<P  align=left>           for(int i=0;i&lt;height;i++){<p></p></P>
<P  align=left>               for(int j=0;j&lt;width;j++){<p></p></P>
<P  align=left>                  UCHAR b=buffer[(i*width+j)*4];<p></p></P>
<P  align=left>                  UCHAR g=buffer[(i*width+j)*4+1];<p></p></P>
<P  align=left>                  UCHAR r=buffer[(i*width+j)*4+2];<p></p></P>
<P  align=left>                   pDC-&gt;SetPixel(j,i,RGB(r,g,b));<p></p></P>
<P  align=left>               }<p></p></P>
<P  align=left>           }<p></p></P>
<P  align=left>       }<p></p></P>
<P  align=left>        //pDC-&gt;TextOut(100,200,"32位图");<p></p></P>
<P  align=left>    }<p></p></P>
<P  align=left>    delete buffer;<p></p></P>
<P  align=left>    fclose(fp); <p></p></P>
<P  align=left>}<p></p></P>

cdn 发表于 2004-12-6 05:03

好!!!

fup 发表于 2004-12-20 14:46

Thank you.
页: [1]
查看完整版本: BMP位图结构很详细的说明和示例。