📄 chap11_4.htm
字号:
<html>
<head>
<title>11.4 与设备无关的位图(DIB)</title>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
<meta name="GENERATOR" content="Microsoft FrontPage 3.0">
<link rel="stylesheet" href="../../../cpcw.css"></head>
<body link="#3973DE" alink="#3973DE" background="../../bg.gif">
<div align="center"><center>
<table width="85%" border="0">
<tr bgcolor="#FFFFFF">
<td>
<div align="center">
<center>
</center>
</div>
<p align="CENTER"><b><font color="red" face="Times New Roman">11.4 </font><font color="red">与设备无关的位图</font><font color="red" face="Times New Roman">(DIB)</font></b></p>
<p align="JUSTIFY"> <font face="Times New Roman" size="4"></font> </p>
<p align="JUSTIFY">DIB(Device-indepentent bitmap)的与设备无关性主要体现在以下两个方面:</p>
<ul>
<li>
<p align="JUSTIFY">DIB的颜色模式与设备无关。例如,一个256色的DIB即可以在真彩色显示模式下使用,也可以在16色模式下使用。</p>
</li>
<li>
<p align="JUSTIFY">256色以下(包括256色)的DIB拥有自己的颜色表,像素的颜色独立于系统调色板。</p>
</li>
</ul>
<p> </p>
<p align="JUSTIFY"> 由于DIB不依赖于具体设备,因此可以用来永久性地保存图象。DIB一般是以*.BMP文件的形式保存在磁盘中的,有时也会保存在*.DIB文件中。运行在不同输出设备下的应用程序可以通过DIB来交换图象。</p>
<p align="JUSTIFY">DIB还可以用一种RLE算法来压缩图像数据,但一般来说DIB是不压缩的。</p>
<p align="JUSTIFY"><b></b><font color="#3973DE" face="Times New Roman" size="3">11.4.1
DIB</font><font size="3" color="#3973DE">的结构</font></p>
<p align="JUSTIFY"> 与Borland C++下的框架类库OWL不同,MFC未提供现成的类来封装DIB。尽管Microsoft列出了一些理由,但没有DIB类确实给MFC用户带来很多不便。用户要想使用DIB,首先应该了解DIB的结构。</p>
<p align="JUSTIFY"> 在内存中,一个完整的DIB由两部分组成:一个BITMAPINFO结构和一个存储像素阵列的数组。BITMAPINFO描述了位图的大小,颜色模式和调色板等各种属性,其定义为</p>
<blockquote>
<p align="JUSTIFY">typedef struct tagBITMAPINFO { </p>
<p align="JUSTIFY">BITMAPINFOHEADER bmiHeader; </p>
<p align="JUSTIFY">RGBQUAD bmiColors[1]; //颜色表</p>
<p align="JUSTIFY">} BITMAPINFO;</p>
</blockquote>
<p align="JUSTIFY">RGBQUAD结构用来描述颜色,其定义为</p>
<blockquote>
<p align="JUSTIFY">typedef struct tagRGBQUAD {</p>
<p align="JUSTIFY">BYTE rgbBlue; //蓝色的强度</p>
<p align="JUSTIFY">BYTE rgbGreen; //绿色的强度</p>
<p align="JUSTIFY">BYTE rgbRed; //红色的强度</p>
<p align="JUSTIFY">BYTE rgbReserved; //保留字节,为0</p>
<p align="JUSTIFY">} RGBQUAD;</p>
</blockquote>
<p align="JUSTIFY">注意,RGBQUAD结构中的颜色顺序是BGR,而不是平常的RGB。</p>
<p align="JUSTIFY">BITMAPINFOHEADER结构包含了DIB的各种信息,其定义为</p>
<blockquote>
<p align="JUSTIFY">typedef struct tagBITMAPINFOHEADER{ </p>
<p align="JUSTIFY">DWORD biSize; //该结构的大小</p>
<p align="JUSTIFY">LONG biWidth; //位图的宽度(以像素为单位)</p>
<p align="JUSTIFY">LONG biHeight; //位图的高度(以像素为单位)</p>
<p align="JUSTIFY">WORD biPlanes; //必须为1</p>
<p align="JUSTIFY">WORD biBitCount //每个像素的位数(1、4、8、16、24或32)</p>
<p align="JUSTIFY">DWORD biCompression; //压缩方式,一般为0或BI_RGB (未压缩)</p>
<p align="JUSTIFY">DWORD biSizeImage; //以字节为单位的图象大小(仅用于压缩位图)</p>
<p align="JUSTIFY">LONG biXPelsPerMeter; //以目标设备每米的像素数来说明位图的水平分辨率</p>
<p align="JUSTIFY">LONG biYPelsPerMeter; //以目标设备每米的像素数来说明位图的垂直分辨率</p>
<p align="JUSTIFY">DWORD biClrUsed; /*颜色表的颜色数,若为0则位图使用由biBitCount指定的最大颜色数*/</p>
<p align="JUSTIFY">DWORD biClrImportant; //重要颜色的数目,若该值为0则所有颜色都重要</p>
<blockquote>
<p align="JUSTIFY">} BITMAPINFOHEADER;</p>
</blockquote>
</blockquote>
<p align="JUSTIFY"> 与DDB不同,DIB的字节数组是从图象的最下面一行开始的逐行向上存储的,也即等于把图象倒过来然后在逐行扫描。另外,字节数组中每个扫描行的字节数必需是4的倍数,如果不足要用0补齐。</p>
<p align="JUSTIFY">DIB可以存储在*.BMP或*.DIB文件中。DIB文件是以BITMAPFILEHEADER结构开头的,该结构的定义为</p>
<blockquote>
<p align="JUSTIFY">typedef struct tagBITMAPFILEHEADER { </p>
<p align="JUSTIFY">WORD bfType; //文件类型,必须为“BM”</p>
<p align="JUSTIFY">DWORD bfSize; //文件的大小</p>
<p align="JUSTIFY">WORD bfReserved1; //为0</p>
<p align="JUSTIFY">WORD bfReserved2; //为0</p>
<p align="JUSTIFY">DWORD bfOffBits; //存储的像素阵列相对于文件头的偏移量</p>
<p align="JUSTIFY">} BITMAPFILEHEADER;</p>
</blockquote>
<p align="JUSTIFY"> 紧随该结构的是一个BITMAPINFOHEADER结构,然后是RGBQUAD结构组成的颜色表(如果有的话),文件最后存储的是DIB的像素阵列。</p>
<p align="JUSTIFY"> DIB的颜色信息储存在自己的颜色表中,程序一般要根据颜色表为DIB创建逻辑调色板。在输出一幅DIB之前,程序应该将其逻辑调色板选入到相关的设备上下文中并实现到系统调色板中,然后再调用相关的GDI函数(如::SetDIBitsToDevice或::StretchDIBits)输出DIB。在输出过程中,GDI函数会把DIB转换成DDB,这项工作主要包括以下两步:</p>
<blockquote>
<blockquote>
<p align="JUSTIFY">将DIB的颜色格式转换成与输出设备相同的颜色格式。例如,在真彩色的显示模式下要显示一个256色的DIB,则应该将其转换成24位的颜色格式。</p>
<p align="JUSTIFY">将DIB像素的逻辑颜色索引转换成系统调色板索引。</p>
</blockquote>
</blockquote>
<p><b> </b></p>
<p align="JUSTIFY"> <font color="#3973DE" face="Times New Roman" size="3">11.4.2
</font><font color="#3973DE" size="3">编写DIB类</font></p>
<p align="JUSTIFY"> 由于MFC未提供DIB类,用户在使用DIB时将面临繁重的Windows API编程任务。幸运的是,Visual
C++提供了一个较高层次的API,简化了DIB的使用。这些API函数实际上是由MFC的DibLook例程提供的,它们位于DibLook目录下的dibapi.cpp、myfile.cpp和dibapi.h文件中,主要包括:</p>
<blockquote>
<blockquote>
<p align="JUSTIFY">ReadDIBFile //把DIB文件读入内存</p>
<p align="JUSTIFY">SaveDIB //把DIB保存到文件中</p>
<p align="JUSTIFY">CreateDIBPalette //从DIB中创建一个逻辑调色板</p>
<p align="JUSTIFY">PaintDIB //显示DIB</p>
<p align="JUSTIFY">DIBWidth //返回DIB的宽度</p>
<p align="JUSTIFY">DIBHeight //返回DIB的高度</p>
</blockquote>
</blockquote>
<p> </p>
<p align="JUSTIFY">如果读者对这些函数的内部细节感兴趣,那么可以研究一下dibapi.cpp和myfile.cpp文件,但要做好吃苦的准备。</p>
<p align="JUSTIFY"> 即使利用上述API,编写使用DIB的程序仍然不是很轻松。为了满足读者的要求,笔者编写了一个名为CDib的较简单的DIB类,该类是基于上述API的,它的主要成员函数包括:</p>
<blockquote>
<blockquote>
<p align="JUSTIFY">BOOL Load(LPCTSTR lpszFileName);<br>
该函数从文件中载入DIB,参数lpszFileName说明了文件名。若成功载入则函数返回TRUE,否则返回FALSE。</p>
<p align="JUSTIFY">BOOL LoadFromResource(UINT nID);<br>
该函数从资源中载入位图,参数nID是资源位图的ID。若成功载入则函数返回TRUE,否则返回FALSE。</p>
<p align="JUSTIFY">CPalette* GetPalette()<br>
返回DIB的逻辑调色板。</p>
<p align="JUSTIFY">BOOL Draw(CDC *pDC, int x, int y, int cx=0, int
cy=0);<br>
该函数在指定的矩形区域内显示DIB,它具有缩放位图的功能。参数pDC指向用于绘图的设备上下文,参数x和y说明了目的矩形的左上角坐标,cx和cy说明了目的矩形的尺寸,cx和cy若有一个为0则该函数按DIB的实际大小绘制位图,cx和cy的缺省值是0。若成功则函数返回TRUE,否则返回FALSE。</p>
<p align="JUSTIFY">int Width(); //以像素为单位返回DIB的宽度</p>
<p align="JUSTIFY">int Height(); //以像素为单位返回DIB的高度</p>
</blockquote>
</blockquote>
<p> CDib类的源代码在清单11.3和11.4列出,CDib类的定义位于CDib.h中,CDib类的成员函数代码位于CDib.cpp中。对于CDib类的代码这里就不作具体解释了,读者只要会用就行。</p>
<p align="JUSTIFY">清单11.3 CDib.h</p>
<b></b>
<p align="JUSTIFY">#if !defined MYDIB</p>
<p align="JUSTIFY">#define MYDIB</p>
<p align="JUSTIFY"> </p>
<p align="JUSTIFY">#include "dibapi.h"</p>
<p align="JUSTIFY"> </p>
<p align="JUSTIFY">class CDib</p>
<p align="JUSTIFY">{</p>
<p align="JUSTIFY">public:</p>
<p align="JUSTIFY">CDib();</p>
<p align="JUSTIFY">~CDib();</p>
<p align="JUSTIFY">protected:</p>
<p align="JUSTIFY">HDIB m_hDIB;</p>
<p align="JUSTIFY">CPalette* m_palDIB;</p>
<p align="JUSTIFY">public:</p>
<p align="JUSTIFY">BOOL Load(LPCTSTR lpszFileName);</p>
<p align="JUSTIFY">BOOL LoadFromResource(UINT nID);</p>
<p align="JUSTIFY">CPalette* GetPalette() const</p>
<p align="JUSTIFY">{ return m_palDIB; }</p>
<p align="JUSTIFY">BOOL Draw(CDC *pDC, int x, int y, int cx=0, int cy=0);</p>
<p align="JUSTIFY">int Width();</p>
<p align="JUSTIFY">int Height();</p>
<p align="JUSTIFY">void DeleteDIB();</p>
<p align="JUSTIFY">};</p>
<p align="JUSTIFY"> </p>
<p align="JUSTIFY">#endif</p>
<p align="JUSTIFY"> </p>
<p align="JUSTIFY"><b> </b></p>
<b>
<p align="JUSTIFY">清单11.4 Cdib.cpp</p>
</b>
<p align="JUSTIFY">#include <stdafx.h></p>
<p align="JUSTIFY">#include "CDib.h"</p>
<p align="JUSTIFY"> </p>
<p align="JUSTIFY">#ifdef _DEBUG</p>
<p align="JUSTIFY">#undef THIS_FILE</p>
<p align="JUSTIFY">static char BASED_CODE THIS_FILE[] = __FILE__;</p>
<p align="JUSTIFY">#endif</p>
<p align="JUSTIFY"> </p>
<p align="JUSTIFY">CDib::CDib()</p>
<p align="JUSTIFY">{</p>
<p align="JUSTIFY">m_palDIB=NULL;</p>
<p align="JUSTIFY">m_hDIB=NULL;</p>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -