📄 15. 与设备无关的位图.txt
字号:
while (!(dwMask & 1))
dwMask >>= 1 ;
for (iShift = 0 ; dwMask & 1 ; iShift++)
dwMask >>= 1 ;
return 8 - iShift ;
}
然后呼叫MaskToRShift函数三次来获得右移值:
iRShift[0] = MaskToRShift (dwMask[0]) ;
iRShift[1] = MaskToRShift (dwMask[1]) ;
iRShift[2] = MaskToRShift (dwMask[2]) ;
分别得到值11、5和0。然后呼叫MaskToLShift:
iLShift[0] = MaskToLShift (dwMask[0]) ;
iLShift[1] = MaskToLShift (dwMask[1]) ;
iLShift[2] = MaskToLShift (dwMask[2]) ;
分别得到值3、2和3。现在能从图素中提取每种颜色:
Red = ((dwMask[0] & wPixel) >> iRShift[0]) << iLShift[0] ;
Green = ((dwMask[1] & wPixel) >> iRShift[1]) << iLShift[1] ;
Blue = ((dwMask[2] & wPixel) >> iRShift[2]) << iLShift[2] ;
除了颜色标记能大于0x0000FFFF(这是16位DIB的最大屏蔽值)之外,程序与32位DIB一样。
--------------------------------------------------------------------------------
注意:
对于16位或32位DIB,红色、绿色和蓝色值能大于255。实际上,在32位DIB中,如果屏蔽中有两个为0,第三个应为32位颜色值0xFFFFFFFF。当然,这有点荒唐,但不用担心这个问题。
--------------------------------------------------------------------------------
不像Windows NT,Windows 95和Windows 98在使用颜色屏蔽时有许多的限制。可用的值显示在表15-2中。
表15-2
16位DIB
16位DIB
32位DIB
红色屏蔽
0x00007C00
0x0000F800
0x00FF0000
绿色屏蔽
0x000003E0
0x000007E0
0x0000FF00
蓝色屏蔽
0x0000001F
0x0000001F
0x000000FF
速记为
5-5-5
5-6-5
8-8-8
换句话说,就是当biCompression是BI_RGB时,您能使用内定的两组屏蔽,包括前面例子中显示的屏蔽组。表格底行显示了一个速记符号来指出每图素红色、绿色和蓝色的位数。
第4版本的Header
我说过,Windows 95更改了一些原始BITMAPINFOHEADER字段的定义。Windows 95也包括了一个称为BITMAPV4HEADER的新扩展的信息表头。如果您知道Windows 95曾经称作Windows 4.0,则就会明白此结构的名称了,Windows NT 4.0也支持此结构。
typedef struct
{
DWORD bV4Size ; // size of the structure = 120
LONG bV4Width ; // width of the image in pixels
LONG bV4Height ; // height of the image in pixels
WORD bV4Planes ; // = 1
WORD bV4BitCount ; // bits per pixel (1, 4, 8, 16, 24, or 32)
DWORD bV4Compression ; // compression code
DWORD bV4SizeImage ; // number of bytes in image
LONG bV4XPelsPerMeter ; // horizontal resolution
LONG bV4YPelsPerMeter ; // vertical resolution
DWORD bV4ClrUsed ; // number of colors used
DWORD bV4ClrImportant ; // number of important colors
DWORD bV4RedMask ; // Red color mask
DWORD bV4GreenMask ; // Green color mask
DWORD bV4BlueMask ; // Blue color mask
DWORD bV4AlphaMask ; // Alpha mask
DWORD bV4CSType ; // color space type
CIEXYZTRIPLE bV4Endpoints ; // XYZ values
DWORD bV4GammaRed ; // Red gamma value
DWORD bV4GammaGreen ; // Green gamma value
DWORD bV4GammaBlue ; // Blue gamma value
}
BITMAPV4HEADER, * PBITMAPV4HEADER ;
注意前11个字段与BITMAPINFOHEADER结构中的相同,后5个字段支持Windows 95和Windows NT 4.0的图像颜色调配技术。除非使用BITMAPV4HEADER结构的后四个字段,否则您应该使用BITMAPINFOHEADER(或BITMAPV5HEADER)。
当bV4Compression字段等于BI_BITFIELDS时,bV4RedMask、bV4GreenMask和bV4BlueMask可以用于16位和32位DIB。它们作为定义在BITMAPINFOHEADER结构中的颜色屏蔽用于相同的函数,并且当使用除了明确的结构字段之外的原始结构时,它们实际上出现在DIB文件的相同位置。就我所知,bV4AlphaMask字段不被使用。
BITMAPV5HEADER结构剩余的字段包括「Windows颜色管理(Image Color Management)」,它的内容超越了本书的范围,但是了解一些背景会对您有益。
为色彩使用RGB方案的问题在于,它依赖于视讯显示器、彩色照相机和彩色扫描仪的显示技术。如果颜色指定为RGB值(255,0,0),意味着最大的电压应该加到阴极射线管内的红色电子枪上,RGB值(128,0,0)表示使用一半电压。不同显示器会产生不同的效果。而且,打印机使用了不同的颜色表示方法,以青色、洋红色、黄色和黑色的组合表示颜色。这些方法称之为CMY(cyan-magenta-yellow:青色-洋红色-黄色)和CMYK(cyan-magenta-yellow-black:青色-洋红色-黄色-黑色)。数学公式能把RGB值转化为CMY和CMYK,但不能保证打印机颜色与显示器颜色相符合。「色彩调配技术」是把颜色与对设备无关的标准联系起来的一种尝试。
颜色的现象与可见光的波长有关,波长的范围从380nm(蓝)到780nm(红)之间。一切我们能察觉的光线是可见光谱内不同波长的组合。1931年,Commission Internationale de L'Eclairage (International Commission on Illumination)或CIE开发了一种科学度量颜色的方法。这包括使用三个颜色调配函数(名称为x、y和z),它们以其省略的形式(带有每5nm的值)发表在CIE Publication 15.2-1986,「Colorimetry,Second Edition」的表2.1中。
颜色的光谱(S)是一组指出每个波长强度的值。如果知道光谱,就能够将与颜色相关的函数应用到光谱来计算X、Y和Z:
这些值称为大X、大Y和大 Z。y颜色匹配函数等于肉眼对范围在可见光谱内光线的反应。(他看上去像一条由380nm和780nm到0的时钟形曲线)。Y称之为CIE亮度,因为它指出了光线的总体强度。
如果使用BITMAPV5HEADER结构,bV4CSType字段就必须设定为LCS_CALIBRATED_RGB,其值为0。后四个字节必须设定为有效值。
CIEXYZTRIPLE结构按照如下方式定义:
typedef struct tagCIEXYZTRIPLE
{
CIEXYZ ciexyzRed ;
CIEXYZ ciexyzGreen ;
CIEXYZ ciexyzBlue ;
}
CIEXYZTRIPLE, * LPCIEXYZTRIPLE ;
而CIEXYZ结构定义如下:
typedef struct tagCIEXYZ
{
FXPT2DOT30 ciexyzX ;
FXPT2DOT30 ciexyzY ;
FXPT2DOT30 ciexyzZ ;
}
CIEXYZ, * LPCIEXYZ ;
这三个字段定义为FXPT2DOT30值,意味着它们是带有2位整数部分和30位小数部分的定点值。这样,0x40000000是1.0,0x48000000是1.5。最大值0xFFFFFFFF仅比4.0小一点点。
bV4Endpoints字段提供了三个与RGB颜色(255,0,0)、(0,255,0)和(0,0,255)相关的X、Y和Z值。这些值应该由建立DIB的应用程序插入以指明这些RGB颜色的设备无关的意义。
BITMAPV4HEADER剩余的三个字段指「伽马值」(希腊的小写字母γ),它指出颜色等级规格内的非线性。在DIB内,红、绿、蓝的范围从0到225。在显示卡上,这三个数值被转化为显示器使用的三个模拟电压,电压决定了每个图素的强度。然而,由于阴极射线管中电子枪的电子特性,图素的强度(I)并不与电压(V)线性相关,它们的关系为:
ε是由显示器的「亮度」控制设定的黑色等级(理想值为0)。指数γ由显示器的「图像」或「对比度」控制设定的。对于大多数显示器,γ大约在2.5左右。
为了对此非线性作出补偿,摄影机在线路内包含了「伽马修正」。指数0.45修正了进入摄影机的光线,这意味着视讯显示器的伽马为2.2。(视讯显示器的高伽马值增加了对比度,这通常是不需要的,因为周围的光线更适合于低对比度。)
视讯显示器的这个非线性反应实际上是很适当的,这是因为人类对光线的反应也是非线性的。我曾提过,Y被称为CIE亮度,这是线性的光线度量。CIE也定义了一个接近于人类感觉的亮度值。亮度是L* (发音为"ell star") ,通过使用如下公式从Y计算得到的:
在此Yn是白色等级。公式的第一部分是一个小的线性部分。一般,人类的亮度感觉是与线性亮度的立方根相关的,这由第二个公式指出。L* 的范围从0到100,每次L* 的增加都假定是人类能感觉到的亮度的最小变化。
根据知觉亮度而不是线性亮度对光线强度编码要更好一些。这使得位的数量减少到一个合理的程度并且在模拟线路上也降低了噪声。
让我们来看一下整个程序。图素值(P)范围从0到255,它被线性转化成电压等级,我们假定标准化为0.0到1.0之间的值。假设显示器的黑色级设定为0,则图素的强度为:
这里γ大约为2.5。人类感觉的亮度(L*)依赖于此强度的立方根和变化从0到100的范围,因此大约是:
指数值大约为0.85。如果指数值为1,那么CIE亮度与图素值完全匹配。当然不完全是那种情况,但是如果图素值指出了线性亮度就非常接近。
BITMAPV4HEADER的最后三个字段为建立DIB的程序提供了一种为图素值指出假设的伽马值的方法。这些值由16位整数值和16位的小数值说明。例如,0x10000为1.0。如果DIB是捕捉实际影像而建立的,影像捕捉硬件就可能包含这个伽马值,并且可能是2.2(编码为0x23333)。如果DIB是由程序通过算法产生的,程序会使用一个函数将它使用的任何线性亮度转化为CIE亮度。
第5版的Header
为Windows 98和Windows NT 5.0(即Windows 2000)编写的程序能使用拥有新的BITMAPV5HEADER信息结构的DIB:
typedef struct
{
DWORD bV5Size ; // size of the structure = 120
LONG bV5Width ; // width of the image in pixels
LONG bV5Height ; // height of the image in pixels
WORD bV5Planes ; // = 1
WORD bV5BitCount ; // bits per pixel (1,4,8,16,24,or32)
DWORD bV5Compression ; // compression code
DWORD bV5SizeImage ; // number of bytes in image
LONG bV5XPelsPerMeter ; // horizontal resolution
LONG bV5YPelsPerMeter ; // vertical resolution
DWORD bV5ClrUsed ; // number of colors used
DWORD bV5ClrImportant ; // number of important colors
DWORD bV5RedMask ; // Red color mask
DWORD bV5GreenMask ; // Green color mask
DWORD bV5BlueMask ; // Blue color mask
DWORD bV5AlphaMask ; // Alpha mask
DWORD bV5CSType ; // color space type
CIEXYZTRIPLE bV5Endpoints ; // XYZ values
DWORD bV5GammaRed ; // Red gamma value
DWORD bV5GammaGreen ; // Green gamma value
DWORD bV5GammaBlue ; // Blue gamma value
DWORD bV5Intent ; // rendering intent
DWORD bV5ProfileData ; // profile data or filename
DWORD bV5ProfileSize ; // size of embedded data or filename
DWORD bV5Reserved ;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -