设备相关位图(DDB)
在Windows中有两种类型的位图:DDB位图(与设备相关位图)及DIB位图(与设备无关位图).与设备相关位图(
device-dependent bitmap)是一种内部位图格式,它由MFC库6.0版本CBitmap类定义,有一个与之关联的Windows数据结构.
DDB中不包括颜色信息,显示时是以系统的
调色板为基础进行各位的颜色映射.它显示的图像依计算机显示系统的设置不同而不同,因此一般不存储文件.
MFC6.0定义了Cbitmap类对DDB结构BITMAP和DDB位图操作进行了封装.结构BITMAP定义了DDB位图的类型宽度高度颜色格式和像素位置,其在Windows中定义如下:
typedef struct tagBITMAP
{
int bmType; //位图类型,必须设置为0
int bmWidth; //位图宽度
int bmHeight; //位图高度
int bmWidthBytes; //位图中每一扫描行中的字节数
BYTE bmPlanes; //颜色层数
BYTE bmbitsPixel; //每一像素所占的位数
void FAR* bmbits; //存放像素值内存块的地址
}BITMAP;
在
数字图像处理中,使用较多的DIB位图,即与设备无关位图,DDB位图使用较少
编辑本段DIB的结构
与
Borland C++下的框架类库OWL不同,MFC未提供现成的类来封装DIB。尽管Microsoft列出了一些理由,但没有DIB类确实给MFC用户带来很多不便。用户要想使用DIB,首先应该了解DIB的结构。
typedef struct tagBITMAPINFO {
BITMAPINFOHEADER bmiHeader;
RGBQUAD bmiColors[1]; //颜色表
} BITMAPINFO;
RGBQUAD结构用来描述颜色,其定义为
typedef struct tagRGBQUAD {
BYTE rgbBlue; //蓝色的强度
BYTE rgbGreen; //绿色的强度
BYTE rgbRed; //红色的强度
BYTE rgbReserved; //保留字节,为0
} RGBQUAD;
注意,RGBQUAD结构中的颜色顺序是BGR,而不是平常的RGB。
BITMAPINFOHEADER结构包含了DIB的各种信息,其定义为
typedef struct tagBITMAPINFOHEADER{
DWORD biSize; //该结构的大小
LONG biWidth; //
位图的宽度(以像素为单位)
LONG biHeight; //
位图的高度(以像素为单位)
WORD biPlanes; //必须为1
WORD biBitCount //每个像素的位数(1、4、8、16、24或32)
DWORD biCompression; //压缩方式,一般为0或BI_RGB (未压缩)
LONG biXPelsPerMeter; //以目标设备每米的像素数来说明
位图的水平分辨率
LONG biYPelsPerMeter; //以目标设备每米的像素数来说明位图的垂直分辨率
DWORD biClrUsed; /*颜色表的颜色数,若为0则
位图使用由biBitCount指定的最大颜色数*/
DWORD biClrImportant; //重要颜色的数目,若该值为0则所有颜色都重要
} BITMAPINFOHEADER;
编辑本段结构的定义
DIB可以存储在*.BMP或*.DIB文件中。DIB文件是以BITMAPFILEHEADER结构开头的 typedef struct tagBITMAPFILEHEADER {
WORD bfType; //文件类型,必须为"BM"
DWORD bfSize; //文件的大小
WORD bfReserved1; //为0
WORD bfReserved2; //为0
} BITMAPFILEHEADER;
紧随该结构的是一个BITMAPINFOHEADER结构,然后是RGBQUAD结构组成的颜色表(如果有的话),文件最后存储的是DIB的像素阵列。
DIB的颜色信息储存在自己的颜色表中,程序一般要根据颜色表为DIB创建逻辑调色板。在输出一幅DIB之前,程序应该将其逻辑调色板选入到相关的
设备上下文中并实现到系统调色板中,然后再调用相关的GDI函数(如::
SetDIBitsToDevice或::StretchDIBits)输出DIB。在输出过程中,GDI函数会把DIB转换成DDB,这项工作主要包括以下两步:
将DIB的颜色格式转换成与输出设备相同的颜色格式。例如,在
真彩色的显示模式下要显示一个256色的DIB,则应该将其转换成24位的颜色格式。
将DIB像素的逻辑颜色索引转换成系统调色板索引。
编辑本段编写DIB类
由于MFC未提供DIB类,用户在使用DIB时将面临繁重的Windows API编程任务。幸运的是,
Visual C++提供了一个较高层次的API,简化了DIB的使用。这些API函数实际上是由MFC的DibLook例程提供的,它们位于DibLook目录下的dibapi.cpp、myfile.cpp和dibapi.h文件中,主要包括:
ReadDIBFile //把DIB文件读入内存
SaveDIB //把DIB保存到文件中
CreateDIBPalette //从DIB中创建一个逻辑调色板
PaintDIB //显示DIB
DIBWidth //返回DIB的宽度
DIBHeight //返回DIB的高度
DIB区块
DIB区块
DIB能拥有几种色彩组织中的一种,DDB必须是单色的或是与真实
输出设备相同的格式。DIB是一个档案或
记忆体块;DDB是GDI
点阵图物件并由点阵图代号表示。DIB能被显示或转换为DDB并转换回DIB,但是这里包含了装置无关位元和设备相关位元之间的转换程序。
现在您将遇到一个函式,它打破了这些规则。该函式在32位元Windows版本中发表,称为CreateDIBSection,语法为:
hBitmap = CreateDIBSection (
hdc, // device context handle
pInfo, // pointer to DIB information
fClrUse, // color use flag
ppBits, // pointer to pointer variable
hSection, // file-mapping object handle
dwOffset) ; // offset to bits in file-mapping object
CreateDIBSection是Windows API中最重要的函式之一(至少在使用
点阵图时),然而您会发现它很深奥并难以理解。
编辑本段DIB section是什么
让我们从它的名称开始,我们知道DIB是什么,但「DIB section」到底是什么呢?当您第一次检查CreateDIBSection时,可能会寻找该函式与DIB区块工作的方式。这是正确的,CreateDIBSection所做的就是建立了DIB的一部分(
点阵
图图素位元的
记忆体块)。
现在我们看一下传回值,它是GDI
点阵图物件的代号,这个传回值可能是该函式呼叫最会拐人的部分。传回值似乎暗示著CreateDIBSection在功能上与
CreateDIBitmap相同。事实上,它只是相似但完全不同。实际上,从CreateDIBSection传回的
点阵图代号与我们在本章和上一章遇到的所有点阵图建立函式传回的点阵图代号在本质上不同。
一旦理解了CreateDIBSection的真实特性,您可能觉得奇怪为什么不把传回值定义得有所区别。您也可能得出结论:CreateDIBSection应该称之为
CreateDIBitmap,并且如同我前面所指出的CreateDIBitmap应该称之为CreateDDBitmap。
编辑本段使用
首先让我们检查一下如何简化CreateDIBSection,并正确地使用它。首先,把最後两个参数hSection和dwOffset,分别设定为NULL和0。第二,仅在fColorUse参数设定为DIB_ PAL_COLORS时,才使用hdc参数,如果fColorUse为DIB_RGB_COLORS(或0),hdc将被忽略(这与
CreateDIBitmap不同,hdc参数用於取得与DDB相容的设备的色彩格式)。
因此,CreateDIBSection最简单的形式仅需要第二和第四个参数。第二个参数是指向BITMAPINFO结构的指针,我们以前曾使用过。我希望指向第四个参数的指标定义的指标不会使您困惑,它实际上很简单。
假设要建立每图素24位元的384×256位元DIB,24位元格式不需要色彩对照表,因此它是最简单的,所以我们可以为BITMAPINFO参数使用BITMAPINFOHEADER结构。
您需要定义三个变数:BITMAPINFOHEADER结构、BYTE指标和
点阵图代号:
BITMAPINFOHEADER bmih ;
BYTE * pBits ;
HBITMAP hBitmap ;
现在初始化BITMAPINFOHEADER结构的栏位
bmih->biSize = sizeof (BITMAPINFOHEADER) ;
bmih->biWidth = 384 ;
bmih->biHeight = 256 ;
bmih->biPlanes = 1 ;
bmih->biBitCount = 24 ;
bmih->biCompression = BI_RGB ;
bmih->biSizeImage = 0 ;
bmih->biXPelsPerMeter = 0 ;
bmih->biYPelsPerMeter = 0 ;
bmih->biClrUsed = 0 ;
bmih->biClrImportant = 0 ;
在基本准备後,我们呼叫该函式:
hBitmap = CreateDIBSection (NULL, (BITMAPINFO *) &bmih, 0, &pBits, NULL, 0) ;
编辑本段注意
我们为第二个参数赋予BITMAPINFOHEADER结构的位址。这是常见的,但一个BYIE指标pBits的位址,就不常见了。这样,第四个参数是函式需要的指向指标的指标。
这是函式呼叫所做的:CreateDIBSection检查BITMAPINFOHEADER结构并配置足够的
记忆体块来载入
DIB图素位元。(在这个例子里,
记忆体块的大小为384×256×3位元组。)它在您提供的pBits参数中储存了指向此
记忆体块的指标。函式传回
点阵图代号,正如我说的,它与
CreateDIBitmap和其他点阵图建立函式传回的代号不一样。
然而,我们还没有做完,点阵图图素是未初始化的。如果正在读取DIB档案,可以简单地把pBits
参数传递给ReadFile函式并读取它们。或者可以使用一些程式码「人工」设定。