这样,bcBitCount字段等于:
∙1代表2色DIB
∙4代表16色DIB
∙8代表256色DIB
∙24代表full-ColorDIB
当我提到「8位DIB」时,就是说每图素占8位的DIB。
对于前三种情况(也就是位数为1、4和8时),BITMAPCOREHEADER后紧跟色彩对照表,24位DIB没有色彩对照表。
色彩对照表是一个3字节RGBTRIPLE结构的数组,数组中的每个元素代表图像中的每种颜色:
typedefstructtagRGBTRIPLE//rgbt
{
BYTErgbtBlue;//bluelevel
BYTErgbtGreen;//greenlevel
BYTErgbtRed;//redlevel
}
RGBTRIPLE;
这样排列色彩对照表以便DIB中最重要的颜色首先显示,我们将在下一章说明原因。
WINGDI.H表头文件也定义了下面的结构:
typedefstructtagBITMAPCOREINFO//bmci
{
BITMAPCOREHEADERbmciHeader;//core-headerstructure
RGBTRIPLEbmciColors[1];//colortablearray
}
BITMAPCOREINFO,*PBITMAPCOREINFO;
这个结构把信息表头与色彩对照表结合起来。
虽然在这个结构中RGBTRIPLE结构的数量等于1,但在DIB文件内您绝对不会发现只有一个RGBTRIPLE。
根据每个图素的位数,色彩对照表的大小始终是2、16或256个RGBTRIPLE结构。
如果需要为8位DIB配置PBITMAPCOREINFO结构,您可以这样做:
pbmci=malloc(sizeof(BITMAPCOREINFO)+255*sizeof(RGBTRIPLE));
然后可以这样存取RGBTRIPLE结构:
pbmci->bmciColors[i]
因为RGBTRIPLE结构的长度是3字节,许多RGBTRIPLE结构可能在DIB中以奇数地址开始。
然而,因为在DIB文件内始终有偶数个的RGBTRIPLE结构,所以紧跟在色彩对照表数组后的数据块总是以WORD地址边界开始。
紧跟在色彩对照表(24位DIB中是信息表头)后的数据是图素位本身。
由下而上
像大多数位图格式一样,DIB中的图素位是以水平行组织的,用视讯显示器硬件的术语称作「扫描线」。
行数等于BITMAPCOREHEADER结构的bcHeight字段。
然而,与大多数位图格式不同的是,DIB从图像的底行开始,往上表示图像。
在此应定义一些术语,当我们说「顶行」和「底行」时,指的是当其正确显示在显示器或打印机的页面上时出现在虚拟图像的顶部和底部。
就好像肖像的顶行是头发,底行是下巴,在DIB文件中的「第一行」指的是DIB文件的色彩对照表后的图素行,「最后行」指的是文件最末端的图素行。
因此,在DIB中,图像的底行是文件的第一行,图像的顶行是文件的最后一行。
这称之为由下而上的组织。
因为这种组织和直觉相反,您可能会问:
为什么要这么做?
好,现在我们回到OS/2的PresentationManager。
IBM的人认为PM内的坐标系统-包括窗口、图形和位图-应该是一致的。
这引起了争论:
大多数人,包括在全画面文字方式下编程和窗口环境下工作的程序写作者认为应使用垂直坐标在屏幕上向下增加的坐标。
然而,计算机图形程序写作者认为应使用解析几何的数学方法进行视讯显示,这是一个垂直坐标在空间中向上增加的直角(或笛卡尔)坐标系。
简而言之,数学方法赢了。
PM内的所有事物都以左下角为原点(包括窗口坐标),因此DIB也就有了那种方式。
DIB图素位
DIB文件的最后部分(在大多数情况下是DIB文件的主体)由实际的DIB的图素字节成。
图素位是由从图像的底行开始并沿着图像向上增长的水平行组织的。
DIB中的行数等于BITMAPCOREHEADER结构的bcHeight字段。
每一行的图素数等于该结构的bcWidth字段。
每一行从最左边的图素开始,直到图像的右边。
每个图素的位数可以从bcBitCount字段取得,为1、4、8或24。
以字节为单位的每行长度始终是4的倍数。
行的长度可以计算为:
RowLength=4*((bmch.bcWidth*bmch.bcBitCount+31)/32);
或者在C内用更有效的方法:
RowLength=((bmch.bcWidth*bmch.bcBitCount+31)&~31)>>3;
如果需要,可通过在右边补充行(通常是用零)来完成长度。
图素数据的总字节数等于RowLength和bmch.bcHeight的乘积。
要了解图素编码的方式,让我们分别考虑四种情况。
在下面的图表中,每个字节的位显示在框内并且编了号,7表示最高位,0表示最低位。
图素也从行的最左端从0开始编号。
对于每图素1位的DIB,每字节对应为8图素。
最左边的图素是第一个字节的最高位:
每个图素可以是0或1。
0表示该图素的颜色由色彩对照表中第一个RGBTRIPLE项目给出。
1表示图素的颜色由色彩对照表的第二个项目给出。
对于每图素4位的DIB,每个字节对应两个图素。
最左边的图素是第一个字节的高4位,以此类推:
每图素4位的值的范围从0到15。
此值是指向色彩对照表中16个项目的索引。
对于每图素8位的DIB,每个字节为1个图素:
字节的值从0到255。
同样,这也是指向色彩对照表中256个项目的索引。
对于每图素24位的DIB,每个图素需要3个字节来代表红、绿和蓝的颜色值。
图素位的每一行,基本上就是RGBTRIPLE结构的数组,可能需要在每行的末端补0以便该行为4字节的倍数:
每图素24位的DIB没有色彩对照表。
扩展的WindowsDIB
现在我们掌握了Windows3.0中介绍的与OS/2兼容的DIB,同时也看一看Windows中DIB的扩展版本。
这种DIB形式跟前面的格式一样,以BITMAPFILEHEADER结构开始,但是接着是BITMAPINFOHEADER结构,而不是BITMAPCOREHEADER结构:
typedefstructtagBITMAPINFOHEADER//bmih
{
DWORDbiSize;//sizeofthestructure=40
LONGbiWidth;//widthoftheimageinpixels
LONGbiHeight;//heightoftheimageinpixels
WORDbiPlanes;//=1
WORDbiBitCount;//bitsperpixel(1,4,8,16,24,or32)
DWORDbiCompression;//compressioncode
DWORDbiSizeImage;//numberofbytesinimage
LONGbiXPelsPerMeter;//horizontalresolution
LONGbiYPelsPerMeter;//verticalresolution
DWORDbiClrUsed;//numberofcolorsused
DWORDbiClrImportant;//numberofimportantcolors
}
BITMAPINFOHEADER,*PBITMAPINFOHEADER;
您可以通过检查结构的第一字段区分与OS/2兼容的DIB和WindowsDIB,前者为12,后者为40。
您将注意到,在这个结构内有六个附加的字段,但是BITMAPINFOHEADER不是简单地由BITMAPCOREHEADER加上一些新字段而成。
仔细看一下:
在BITMAPCOREHEADER结构中,bcWidth和bcHeight字段是16位WORD值;而在BITMAPINFOHEADER结构中它们是32位LONG值。
这是一个令人讨厌的小变化,当心它会给您带来麻烦。
另一个变化是:
对于使用BITMAPINFOHEADER结构的1位、4位和8位DIB,色彩对照表不是RGBTRIPLE结构的数组。
相反,BITMAPINFOHEADER结构紧跟着一个RGBQUAD结构的数组:
typedefstructtagRGBQUAD//rgb
{
BYTErgbBlue;//bluelevel
BYTErgbGreen;//greenlevel
BYTErgbRed;//redlevel
BYTErgbReserved;//=0
}
RGBQUAD;
除了包括总是设定为0的第四个字段外,与RGBTRIPLE结构相同。
WINGDI.H表头文件也定义了以下结构:
typedefstructtagBITMAPINFO//bmi
{
BITMAPINFOHEADERbmiHeader;//info-headerstructure
RGBQUADbmiColors[1];//colortablearray
}
BITMAPINFO,*PBITMAPINFO;
注意,如果BITMAPINFO结构以32位的地址边界开始,因为BITMAPINFOHEADER结构的长度是40字节,所以RGBQUAD数组内的每一个项目也以32位边界开始。
这样就确保通过32位微处理器能更有效地对色彩对照表数据寻址。
尽管BITMAPINFOHEADER最初是在Windows3.0中定义的,但是许多字段在Windows95和WindowsNT4.0中又重新定义了,并且被带入Windows98和WindowsNT5.0中。
比如现在的文件中说:
「如果biHeight是负数,则位图是由上而下的DIB,原点在左上角」。
这很好,但是在1990年刚开始定义DIB格式时,如果有人做了这个决定,那会更好。
我的建议是避免建立由上而下的DIB。
有一些程序在编写时没有考虑这种新「特性」,在遇到负的biHeight字段时会当掉。
还有如MicrosoftWord97带有的MicrosoftPhotoEditor在遇到由上而下的DIB时会报告「图像高度不合法」(虽然Word97本身不会出错)。
biPlanes字段始终是1,但biBitCount字段现在可以是16或32以及1、4、8或24。
这也是在Windows95和WindowsNT4.0中的新特性。
一会儿我将介绍这些附加格式工作的方式。
现在让我们先跳过biCompression和biSizeImage字段,一会儿再讨论它们。
biXPelsPerMeter和biYPelsPerMeter字段以每公尺多少图素这种笨拙的单位指出图像的实际尺寸。
(「pel」--pictureelement(图像元素)--是IBM对图素的称呼。
)Windows在内部不使用此类信息。
然而,应用程序能够利用它以准确的大小显示DIB。
如果DIB来源于没有方图素的设备,这些字段是很有用的。
在大多数DIB内,这些字段设定为0,这表示没有建议的实际大小。
每英寸72点的分辨率(有时用于视讯显示器,尽管实际分辨率依赖于显示器的大小)大约相当于每公尺2835个图素,300DPI的普通打印机的分辨率是每公尺11,811个图素。
biClrUsed是非常重要的字段,因为它影响色彩对照表中项目的数量。
对于4位和8位DIB,它能分别指出色彩对照表中包含了小于16或256个项目。
虽然并不常用,但这是一种缩小DIB大小的方法。
例如,假设DIB图像仅包括64个灰阶,biClrUsed字段设定为64,并且色彩对照表为256个字节大小的色彩对照表包含了64个RGBQUAD结构。
图素值的范围从0x00到0x3F。
DIB仍然每图素需要1字节,但每个图素字节的高2位为零。
如果biClrUsed字段设定为0,意味着色彩对照表包含了由biBitCount字段表示的全部项目数。
从Windows95开始,biClrUsed字段对于16位、24位或32位DIB可以为非零。
在这些情况下,Windows不使用色彩对照表解释图素位。
相反地,它指出DIB中色彩对照表的大小,程序使用该信息来设定调色盘在256色视讯显示器上显示DIB。
您可能想起在OS/2兼容格式中,24位DIB没有色彩对照表。
在Windows3.0中的扩展格式中,也与这一样。
而在Windows95中,24位DIB有色彩对照表,biClrUsed字段指出了它的大小。
总结如下:
∙对于1位DIB,biClrUsed始终是0或2。
色彩对照表始终有两个项目。
∙对于4位DIB,如果biClrUsed字段是0或16,则色彩对照表有16个项目。
如果是从2到15的数,则指的是色彩对照表中的项目数。
每个图素的最大值是小于该数的1。
∙对于8位DIB,如果biClrUsed字段是0或256,则色彩对照表有256个项目。
如果是从2到225的数,则指的是色彩对照表中的项目数。
每个图素的最大值是小于该数的1。
∙对于16位、24位或32位DIB,biClrUsed字段通常为0。
如果它不为0,则指的是色彩对照表中的项目数。
执行于256色显示卡的应用程序能使用这些项目来为DIB设定调色盘。
另一个警告:
原先使用早期DIB文件编写的程序不支持24位DIB中的色彩对照表,如果在程序使用24位DIB的色彩对照表的话,就要冒一定的风险。
biClrImportant字段实际上没有biClrUsed字段重要,它通常被设定为0以指出色彩对照表中所有的颜色都是重要的,或者它与biClrUsed有相同的值。
两种方法意味着同一件事,如果它被设定为0与biClrUsed之间的值,就意味着DIB图像能仅仅通过色彩对照表中第一个biClrImportant项目合理地取得。
当在256色显示卡上并排显示两个或更多8位DIB时,这是很有用的。
对于1位、4位、8位和24位的DIB,图素位的组织和OS/2兼容的DIB是相同的,一会儿我将讨论16位和32位DIB。
真实检查
当遇到一个由其它程序或别人建立的DIB时,您希望从中发现什么内容呢?
尽管在Windows3.0首次推出时,OS/2样式的DIB已经很普遍了,但最近这种格式却已经很少出现了。
许多程序写作者在实际编写快速DIB例程时忽略了它们。
您遇到的任何4位DIB可能是Windows的「小画家」程序使用16色视讯显示器建立的,在这些显示器上色彩对照表具有标准的16种颜色。
最普遍的DIB可能是每图素8位。
8位DIB分为两类:
灰阶DIB和混色DIB。
不幸的是,表头信息中并没有指出8位DIB的型态。
许多灰阶DIB有一个等于64的biClrUsed字段,指出色彩对照表中的64个项目。
这些项目通常以上升的灰阶层排列