调色盘料理器第四色播
壹佰软件开发小组 整理编译要是硬件允许,本章就莫得存在的必要。尽管很多当代的娇傲卡提供24位神采(也称「true color」或「数百万色」)或16位神采(「增强色」或「数万种神采」),一些娇傲卡-尤其是在便携式计较机上或高分辨率模式中-每个图素只允许8位。这意味着仅有256种神采。
咱们用256种神采能作念什么呢?很较着,要娇傲真实寰宇的图像,仅16种神采是不够的,至少要使用数千或数百万种神采,256种神采位于中间情景。是的,用256种神采来娇傲真实寰宇的图像鼓胀了,但需要证明特定的图像来指定这些神采。这意味着操作系统不可浅近地遴荐「规范」系列的256种神采,就但愿它们对每个应用门径齐是理念念的神采。
这即是Windows调色盘料理器所要触及的全部内容。它用于指定门径在8位娇傲模式下实施时所需要的神采。要是知说念门径治服不会在8位娇傲模式下实施,那么您也不需要使用调色盘料理器。不外,由于补充了位图的一些细节,是以本章如故包含宏大信息的。
使用调色盘
传统上讲,调色盘是画家用来夹杂神采的板子。这个词也不错指画家在绘画经由中使用的扫数神采。在计较机图形中,调色盘是在图形输出开拓(举例视讯娇傲器)上可用的神采领域。这个名词也不错指接济256色模式的娇傲卡上的对照表。
视频硬件
娇傲卡上的调色盘对照表运作经由如下图所示:
在8位娇傲模式中,每个图素占8位。图素值查询包含256RGB值的对照表的地址。这些RGB值不错只怕24位宽,或者小少许,平素是18位宽(即主要的红、绿和蓝各6位)。每种神采的值齐输入到数字模拟调理器,以得到发送给监视器的红、绿和蓝三个模拟信号。
平素,软件不错用恣意值来加载调色盘对照表,但这对开拓无关的窗口接口,举例Microsoft Windows,会有一些侵扰。开端,Windows必须提供软件接口,以便在不径直侵扰硬件的情况下,应用门径就不错存取调色盘料理器。第二个问题更严重:因为扫数的应用门径齐分享归并个视讯娇傲器,而且同期实施,是以一个应用门径使用了调色盘对照表可能会影响其它门径的使用。
这时就需要使用Windows调色盘料理器(在Windows 3.0中提倡)了。Windows保留了256种神采中的20种,而允许应用门径修改其余的236种。(在某些情况下,应用门径最多不错变嫌256种神采中的254种-唯有玄色和白色除外-但这有少许辛劳)。Windows为系统保留的20种神采(有时称为20种「静态」神采)如表16-1所示。
在256种神采娇傲模式下实施时,由Windows推奖系统调色盘,此调色盘与娇傲卡上的硬件调色盘对照表相易。内定的系统调色盘如表16-1所示。应用门径不错通过指定「逻辑调色盘(logical palettes)」来修改其余236种神采。要是有多个应用门径使用逻辑调色盘,那么Windows就给行动窗口最高优先权(咱们知说念,行动窗口有高亮娇傲标题列,何况娇傲在其它扫数窗口的前边)。咱们将用一些浅近的表率门径来查验它是何如使命的。
要实施本章其它部分的门径,您可能需要将娇傲卡切换成256色模式。在桌面上单擎鼠标右键,从菜单中遴荐「属性」,然后遴荐「设定」页面标签。
娇傲灰阶
门径16-1所示的GRAYS1门径莫得使用Windows调色盘料理器,而尝试用正常娇傲的65级种阶作为从黑到白的多种彩色的「来源」。
在WM_PAINT音讯处理时期,门径呼唤了65次FillRect函数,每次齐使用不同灰阶建筑的画刷。灰阶值是RGB值(0,0,0)、(4,4,4)、(8,8,8)等等,直到临了一个值(255,255,255)。临了一个值来自CreateSolidBrush函数中的min宏。
要是在256色娇傲模式下实施该门径,您将看到从黑到白的65种灰阶,而且它们简直齐用混色着色。纯神采唯有玄色、暗灰色(128,128,128)、亮灰色(192,192,192)和白色。其它神采是夹杂了这些纯神采的多位模式。要是咱们在娇傲行或笔墨,而不是用这65种灰阶填充区域,Windows将不使用混色而只使用这四种纯色。要是咱们正在娇傲位图,则图像将用20种规范Windows神采近似。这时正如同您在实施临了一章中的门径的同期又加载了彩色或灰阶DIB所见到的一样。平素,Windows在位图中不使用混色。
门径16-2所示的GRAYS2门径用较少的外部门径代码考据了调色盘料理器中最宏大的函数和音讯。
平素,使用调色盘料理器的第一步即是呼唤CreatePalette函数来建筑逻辑调色盘。逻辑调色盘包含门径所需要的全部神采-即236种神采。GRAYS1门径在WM_CREATE音讯处理时期处理此功课。它驱动化LOGPALETTE(「logical palette:逻辑调色盘」)结构的字段,并将这个结构的指针传递给CreatePalette函数。CreatePalette传回逻辑调色盘的句柄,并将此句柄储存在静态变量hPalette中。
LOGPALETTE结构界说如下:
第一个字段平素设为0x0300,暗示兼容Windows 3.0。第二个字段设定为调色盘表中的名目数。LOGPALETTE结构中的第三个字段是一个PALETTEENTRY结构的数组,此结构亦然一个调色盘名目。PALETTEENTRY结构界说如下:
每个PALETTEENTRY结构齐界说了一个咱们要在调色盘中使用的RGB神采值。
夺目,LOGPALETTE中只能界说一个PALETTEENTRY结构的数组。您需要为LOGPALETTE结构和附加的PALETTEENTRY结构设立鼓胀大的内存空间。GRAYS2需要65种灰阶,因此它为LOGPALETTE结构和64个附加的PALETTEENTRY结构设立了鼓胀大的内存空间。GRAYS2将palNumEntries字段设定为65,然后从0到64轮回,计较灰阶等第(一般是轮回索引的4倍,但不超越255),将结构中的peRed、peGreen和peBlue字段设定为此灰阶等第。peFlags字段设为0。门径将指向这个内存块的指针传递给CreatePalette,在一个静态变量中储存该调色盘句柄,然后开释内存。
逻辑调色盘是GDI对象。门径应该删除它们建筑的扫数逻辑调色盘。WndProc透过在WM_DESTROY音讯处理时期呼唤DeleteObject,仔细地删除了逻辑调色盘。
夺目逻辑调色盘是孤独的开拓内容。在真实使用之前,必须确保将其选进开拓内容。在WM_PAINT音讯处理时期,SelectPalette将逻辑调色盘选进开拓内容。除了含有第三个参数之外,此函数与SelectObject函数相似。平素,第三个参数设为FALSE。要是SelectPalette的第三个参数设为TRUE,那么调色盘将恒久是「布景调色盘」,这意味着当其它扫数门径齐透露了各自的调色盘之后,该调色盘才不错得到仍位于系统调色盘中的一个未使用名目。
在职何时候齐唯有一个逻辑调色盘能选进开拓内容。函数将传回前一个选进开拓内容的逻辑调色盘句柄。要是您但愿将此逻辑调色盘重新选进开拓内容,则不错储存此句柄。
通过将神采映像到系统调色盘,RealizePalette函数使Windows在开拓内容中「透露」逻辑调色盘,而系统调色盘是与娇傲卡本体的本体调色盘相对应。本体使命在此函数呼唤时期进行。Windows必须决定呼唤函数的窗口是行动的还口角行动的,并尽可能将系统调色盘已变嫌奉告给其它窗口(咱们将简要评释一下奉告的门径)。
回忆一下GRAYS1,它用RGB宏来指定纯色画刷的神采。RGB宏建构一个32位长整数(记作COLORREF值),其中高字节是0,3个低字节是红、绿和蓝的亮度。
使用Windows调色盘料理器的门径不错连接使用RGB神采值来指定神采。不外,这些RGB神采值将不可存取逻辑调色盘中的附加神采。它们的作用与莫得使用调色盘料理器相易。要在逻辑调色盘中使用附加的神采,就要用到PALETTERGB宏。除了COLORREF值的高字节设为2而不是0之外,「调色盘RGB」神采与RGB神采很相似。
底下是宏大的国法:
为了使用逻辑调色盘中的神采,请用调色盘RGB值或调色盘索引来指定(我将简要接洽调色盘索引)。不要使用惯例的RGB值。要是使用了惯例的RGB值,您将得到一种规范神采,而不是逻辑调色盘中的神采。 莫得将调色盘选进开拓内容时,不要使用调色盘RGB值或调色盘索引。 尽管不错使用调色盘RGB值来指定逻辑调色盘中莫得的神采,但您如故要从逻辑调色盘得到神采。举例,在GRAYS2中处理WM_PAINT时期,当您遴荐并透露了逻辑调色盘之后,要是试图娇傲红色,则将娇傲灰阶。您必须用RGB神采值来遴荐不在逻辑调色盘中的神采。
夺目,GRAYS2从不查验视讯娇傲驱动门径是否接济调色盘料理门径。在不接济调色盘料理门径的娇傲模式(即扫数非256种神采的娇傲模式)下实施GRAYS2时,GRAYS2的功能与GRASY1相易。
调色盘信息
要是门径在逻辑调色盘中指定一种神采,该神采又是20种保珍爱采之一,那么Windows将把逻辑调色盘名目映像给该神采。另外,要是两个或多个应用门径齐在它们的逻辑调色盘中指定了归并种神采,那么这些应用门径将分享系统调色盘名目。门径不错通过将PALETTEENTRY结构的peFlags字段指定为常数PC_NOCOLLAPSE来忽略该内定情景(其余两个可能的标记是PC_EXPLICIT(用于娇傲系统调色盘)和PC_RESERVED(用于调色盘动画),我将在本章的背面展示这两个标记)。
要匡助组织系统调色盘,Windows调色盘料理器含有两个发送给主窗口的音讯。
第一个是QM_QUERYNEWPALETTE。当主窗口行动时,该音讯发送给主窗口。要是门径在您的窗口上绘画时使用了调色盘料理器,则它必须处理该音讯。GRAYS2展示具体的作法。门径得到开拓内容句柄,并选进调色盘,呼唤RealizePalette,然后使窗口失效以产生WM_PAINT音讯。要是透露了逻辑调色盘,则窗口音讯处理门径从该音讯传回TRUE,不然传回FALSE。
当系统调色盘改成与WM_QUERYNEWPALETTE音讯的收尾相易期,Windows将WM_PALETTECHANGED音讯发送给由目前行动的窗口来启动并断绝处理窗口链的扫数主窗口。这允许前台窗口有优先权。传递给窗口音讯处理门径的wParam值是行动窗口的句柄。唯有当wParam不等于门径的窗口句柄时,使用调色盘料理器的门径才会处理该音讯。
平素,在处理WM_PALETTECHANGED时,使用自订调色盘的任何门径齐呼唤SelectPalette和RealizePalette。后续的窗口在音讯处理时期呼唤RealizePalette时,Windows开端查验逻辑调色盘中的RGB神采是否与已加载到系统调色盘中的RGB神采相匹配。要是两个门径需要相易的神采,那么这两个门径就共同使用一个系统调色盘名目。接下来,Windows查验未使用的系统调色盘名目。要是齐已使用,则逻辑调色盘中的神采从20种保留名目映像到最近的神采。
要是不关爱门径非行动时娇傲区域的外不雅,那么您不必处理WM_PALETTECHANGED音讯。不然,您有两个遴荐。GRAYS2娇傲其中之一:在处理WM_QUERYNEWPALETTE音讯时,它得到开拓内容,选进调色盘,然后呼唤RealizePalette。这时就不错在处理WM_QUERYNEWPALETTE时呼唤InvalidateRect了。相暗自,GRAYS2呼唤UpdateColors。这个函数平素比重新画图窗口更有用,同期它变嫌窗口中图素的值来匡助保护当年的神采。
使用调色盘料理器的很多门径齐将让WM_QUERYNEWPALETTE和WM_PALETTECHANGED音讯用GRAYS2所娇傲的方法来处理。
调色盘索引方法
门径16-3所示的GRAYS3门径与GRAYS2非常相似,仅仅在处理WM_PAINT时期使用了呼唤PALETTEINDEX的宏,而不是PALETTERGB。
「调色盘」索引的神采不同于调色盘RGB神采,其高字节是1,而低字节的值是目前在开拓内容中遴荐的、逻辑调色盘中的索引。在GRAYS3中,逻辑调色盘有65个名目,用于这些名主义索引从0到64。值
指玄色,
指灰色,而
指白色。
因为Windows不需要实施最近神采的搜索,是以使用调色盘索引比使用RGB值更有用。
查询调色盘接济
您不错容易地考据:当Windows在16位或24位娇傲模式下实施时,GRAYS2和GRAYS3门径实施细腻。但是在某些情况下,要使用调色盘料理器的Windows应用门径可能要先细则开拓驱动门径是否接济它。这时,您不错呼唤GetDeviceCaps,并以视讯娇傲的开拓内容句柄和PASTERCAPS作为参数。函数将传回由一系列旗标构成的整数。通过在传回值和常数RC_PALETTE之间实施位操作来考研接济的调色盘:
要是此值非零,则视讯娇傲器开拓驱动门径将接济调色盘操作。在这种情况之下,来自GetDeviceCaps的其它三个宏大名目亦然可用的。函数呼唤
将传回在娇傲卡上调色盘表的总尺寸。这与同期娇傲的神采总和相易。因为调色盘料理器只用于每图素8位的视讯娇傲模式,是以此值将是256。
函数呼唤
传回在调色盘表中的神采数,该表是开拓驱动门径为系统保留的,此值是20。不呼唤调色盘料理器,这些仅仅Windows应用门径在256色娇傲模式下使用的纯色。要使用其余的236种神采,门径必须使用调色盘料理器函数。
一个附加名目也可用:
此值告诉您加载到硬件调色盘表的RGB神采值分辨率(以位计)。这些是投入数字模拟调理器的位。某些视讯娇傲卡只使用6位ADC,是以该值是18。其余使用8位的ADC,是以值是24。
Windows门径夺目神采分辨率并因此遴选一些动作是很有用的。举例,要是该神采分辨率是18,那么门径将不可能条款到128种灰阶,因为唯有64个龙套的灰阶可用。条款到128种灰阶就不必用过剩的名目来填充硬件调色盘表。
系统调色盘
我在前边提过,Windows系统调色盘径直与娇傲卡上的硬件调色盘查询表相符(关联词,硬件调色盘查询表可能比系统调色盘的神采分辨率低)。门径不错通过呼唤底下的函数来得到系统调色盘中的某些或全部的RGB名目:
唯有娇傲卡模式接济调色盘操作时,该函数才略实施。第二个和第三个参数是无正负号整数,娇傲第一个调色盘名主义索引和调色盘名目数。临了一个参数是指向PALETTEENTRY型态的指针。
您不错在几种情况下使用该函数。门径不错界说PALETTEENTRY结构如下:
然后可按底下的方法屡次呼唤GetSystemPaletteEntries:
其中的i从0到某个值,该值小于从GetDeviceCaps(带有SIZEPALETTE索引255)传回的值。或者,门径要得到扫数的系统调色盘名目,不错通过界说指向PALETTEENTRY结构的指针,然后重新设立鼓胀的内存块,以储存与调色盘大小指定雷同多的PALETTEENTRY结构。
GetSystemPaletteEntries函数如实允许您考研硬件调色盘表。系统调色盘中的名目按图素值加多的规定枚举,这些值用于暗示视讯娇傲缓冲区中的神采。我将浅近地接洽一下具体作法。
其它调色盘函数
咱们在前边看过,Windows门径概况变嫌系统调色盘,但仅仅辗转变嫌:第一步建筑逻辑调色盘,它基本上是门径要使用的RGB神采值数组。CreatePalette函数不会导致系统调色盘或者娇傲卡调色盘表的任何变化。逻辑调色盘必须在职何事情发生之前就选进开拓内容并透露。
门径不错通过呼唤
来查询逻辑调色盘中的RGB神采值。您不错按使用GetSystemPaletteEntries的方法来使用此函数。但是要夺目,第一个参数是逻辑调色盘的句柄,而不是开拓内容的句柄。
建筑逻辑调色盘以后,让您变嫌其中的值的相应函数是:
另外,记着呼唤此函数不引起系统调色盘的任何变化-即使目前调色盘选进了开拓内容。此函数也不变嫌逻辑调色盘的尺寸。要变嫌逻辑调色盘的尺寸,请使用ResizePalette。
底下的函数领受RGB神采援用值作为临了的参数,并将索引传回给逻辑调色盘,该逻辑调色盘与和它最接近的RGB神采值相对应:
第二个参数是COLORREF值。要是但愿的话,呼唤GetPaletteEntries就不错得到逻辑调色盘中本体的RGB神采值。
要是门径在8位娇傲模式下需要多于236种自订神采,则不错呼唤GetSystemPaletteUse。这允许门径设定254种自订神采;系统仅保留玄色和白色。不外,门径仅在最大化充满全屏幕时才允许这么,而且它还将一些系统神采设为玄色和白色,以便标题列和菜单等仍然可见。
位映像操作问题
从第五章不错了解到,GDI允许使用不同的「绘画模式」或「位映像操作」来画线并填充区域。用SetROP2设定绘画模式,其中的「2」暗示两个对象之间的二元(binary)位映像操作。三元位映像操作用于处理BitBlt和雷同功能。这些位映像操作决定了正在画的对象图素与名义图素的引诱格局。举例,您不错画一条直线,以便在线的图素与娇傲的图素按位异或的格局相引诱。
位映像操作即是在图素位上照着各个位的规定进行操作。变嫌调色盘会影响到这些位映像操作。位映像操作的操作对象是图素位,而这些图素位可能与本体神采没联系联。
透过实施GRAYS2或GRAYS3门径,您我方就不错得出这个论断。调整尺寸时,拖动顶部或底部的鸿沟穿过窗口,Windows愚弄回转布景图素位的位映像操作来娇傲拖动尺寸的鸿沟,其主义是使拖动尺寸鸿沟老是可见的。但在GRAYS2和GRAYS3门径中,您将看到各式就地变换的神采,这些神采恰好与对应于调色盘表中未使用的名目,那是回转娇傲图素位的收尾。可视神采莫得回转-唯有图素位回转了。
正如您在表16-1中所看到的一样,20种规范保珍爱采位于系统调色盘的顶部和底部,以便位映像操作的收尾仍然正常。关联词,一朝您着手修改调色盘-尤其是替换了保珍爱采-那么神采对象的位映像操作就变得没特意旨了。
惟一保证的是位映像操作将用玄色和白色运作。玄色是系统调色盘中的第一个名目(扫数的图素位齐设为0),而白色是临了的名目(扫数的图素位齐设为1)。这两个名目不可变嫌。要是需要先见在神采对象上进行位映像操作的收尾,则不错先得到系统调色盘表,然后检察不同图素位值的RGB神采值。
检察系统调色盘
在Windows下实施的门径将处理逻辑调色盘,为使逻辑调色盘更好地行状于扫数使用逻辑调色盘的门径,Windows将在系统调色盘中设定神采。该系统调色盘复制了娇傲卡的硬件对照表内容。这么,检察系统调色盘有助于调适调色盘应用门径。
因为对于这个问题有三种毫不相易的处理格局,是以我将向您展示三个门径,以娇傲系统调色盘的内容。
SYSPAL1门径,如门径16-4所示,使用了前边所讲的GetSystemPaletteEntries函数。
与SYSPAL系列中的其它门径一样,除非带有SIZEPALETTE参数的GetDeviceCaps传回值为256,不然SYSPAL1不会实施。
夺目无论SYSPAL1的娇傲区域什么时候收到WM_PALETTECHANGED音讯,它齐是无效的。在合并WM_PAINT音讯处理时期,SYSPAL1呼唤GetSystemPaletteEntries,并用一个含256个PALETTEENTRY结构的数组作为参数。RGB值作为笔墨字符串娇傲在娇傲区域。门径实施时,夺目20种保珍爱采是RGB值列表中的前10个和后10个,这与表16-1所示相易。
当SYSPAL1娇傲有用的信息时,它与本体看到的256种神采不同。那即是SYSPAL2的功课,如门径16-5所示。
SYSPAL2在WM_CREATE音讯处理时期建筑了逻辑调色盘。但是请夺目:逻辑调色盘中扫数的256个值齐是从0到255的调色盘索引,何况peFlags字段是PC_EXPLICIT。该旗标是这么界说的:「逻辑调色盘名主义较低字组指定了一个硬件调色盘索引。此旗标允许应用门径娇傲硬件调色盘的内容。」该旗标即是专为咱们要作念的这件事情而打算的。
在WM_PAINT音讯处理时期,SYSPAL2将该调色盘选进开拓内容并透露它。这不会引起系统调色盘的任何重组,而是允许门径使用PALETTEINDEX宏来指定系统调色盘中的神采。按此方法,SYSPAL2娇傲了256个矩形。另外,当您实施该门径时,夺目顶行和底行的前10种和后10种神采是20种保珍爱采,如表16-1所示。当您实施使用我方逻辑调色盘的门径时,娇傲就变嫌了。
要是您既心爱看SYSPAL2中的神采,又心爱RGB的值,那么请与第八章的WHATCLR门径同期实施。
SYSPAL系列中的第三版使用的技巧对我来说是最近才出现的-从我着手筹商Windows调色盘料理器七年多后,才出现了那些技巧。
事实上,扫数的GDI函数齐径直或辗转地指定神采作为RGB值。在GDI里面,这将调理成与阿谁神采联系的图素位。在某些娇傲模式中(举例,16位或24位神采模式),这些调理是相等径直的。在其它娇傲模式中(4位或8位神采),这可能触及最接近神采的搜索。
关联词,有两个GDI函数让您径直指定图素位中的神采。天然在这种格局中使用的这两个函数齐与开拓高度联系。它们太依赖开拓了,以至于它们不错径直娇傲视讯娇傲卡上本体的调色盘对照表。这两个函数是BitBlt和StretchBlt。
门径16-6所示的SYSPAL3门径娇傲了使用StretchBlt娇傲系统调色盘中神采的方法。
在WM_CREATE音讯处理时期,SYSPAL3使用CreateBitmap来建筑16×16的每图素8位的位图。该函数的临了一个参数是包括数值0到255的256字节数组。这些是256种可能的图素位值。在处理WM_PAINT音讯的门径中,门径将这个位图选进内存开拓内容第四色播,用StretchBlt来娇傲并填充该娇傲区域。Windows仅将位图中的图素位传输到视讯娇傲器硬件,从而允许这些图素位存取调色盘对照表中的256个名目。门径的娇傲区域致使不必使继承WM_PALETTECHANGED音讯无效-对于对照表的任何修改齐会立即影响到SYSPAL3的娇傲。
调色盘动画
在本节的标题中看到「动画」一词,并着手研讨屏幕周围实施的「计较机宠物」时,您的咫尺可能会为之一亮。是的,您不错使用Windows调色盘料理器作一些动画,而且是有一定专科水平的动画。
平素,Windows下的动画即是快速连气儿地娇傲一系诸位图。调色盘动画与这种方法有很大的区别。您透过在屏幕上画图您所需要的每件东西着手,然后您处理调色盘来变嫌这些对象的神采,可能是画一些相对于屏幕布景来说是不可见的图像。您用这种方法就不错得到动画成果,情色亚洲而不必重画任何东西。调色盘动画的速率是相等快的。
对于调色盘动画,领先的建筑使命与咱们前边看见的有些不同:对于动画时期要修改的每种RGB神采值,PALETTEENTRY结构的peFlags字段必须设定为PC_RESERVED。
平素,就像咱们所看到的一样,在建筑逻辑调色盘时,您将peFlags标记设为0。这允许GDI将多个逻辑调色盘中雷同的神采映像到相易的系统调色盘名目。举例,假设两个Windows门径齐建筑了包含RGB名目10-10-10的逻辑调色盘,那么在系统调色盘表中,Windows只需要一个10-10-10名目。但要是这两个门径中的一个使用调色盘动画,那您就不要再让GDI使用调色盘了。调色盘动画意味着速率非常快-而且要是不重画,它也只能能提高速率。当使用调色盘动画的门径修改调色盘时,它不会影响其它门径,或者迫使GDI重组系统调色盘表。PC_RESERVED的peFlags值为单个逻辑调色盘储存系统调色盘名目。
使用调色盘动画时,平素您不错在WM_PAINT音讯处理时期呼唤SelectPalette和RealizePalette,使用PALETTEINDEX宏来指定神采。该宏将一个索引带进逻辑调色盘表。
对于动画,您可能要通过变嫌调色盘来反应WM_TIMER音讯。要变嫌逻辑调色盘中的RGB神采值,请使用一个PALETTEENTRY结构的数组来呼唤函数AnimatePalette。此函数速率很快,因为它只需要变嫌系统调色盘以及娇傲卡硬件调色盘表中的名目。
高出的球
门径16-7娇傲了BOUNCE门径的组件,但还有一个门径可娇傲高出的球。为了浅近起见,证明娇傲区域的大小将球画成了卵形。因为本章有几个调色盘动画门径,是以PALANIM.C(「调色盘动画」)文献包含一些通用内容。
除非Windows处于接济调色盘的娇傲模式下,不然调色盘动画将不可使命。因此,PALANIM.C通过呼唤CheckDisplay函数(与SYSPAL门径中的函数相易)来着手处理WM_CREATE。
PALANIM.C呼唤BOUNCE.C中的四个函数:在WM_CREATE音讯处理时期呼唤CreateRoutine(在BOUNCE顶用于建筑逻辑调色盘);在WM_PAINT音讯处理时期呼唤PaintRoutine;在WM_TIMER音讯处理时期呼唤TimerRoutine;在WM_DESTROY音讯处理时期呼唤DestroyRoutine(在BOUNCE顶用于撤废)。在呼唤PaintRoutine和TimerRoutine之前,PALANIM.C得到开拓内容,并将其选进逻辑调色盘。在呼唤PaintRoutine之前,它也透露调色盘。PALANIM.C盼愿TimerRoutine呼唤AnimatePalette。尽管AnimatePalette需要从开拓内容中遴荐调色盘,但它不需要呼唤RealizePalette。
BOUNCE中的球按「W」道路在娇傲区域中来去高出。娇傲区域布景是白色,球是红色。任何时候,齐不错在33个不重迭的位置之一看见球。这需要34个调色盘名目:一个用于布景,其它33个用于不同位置的球。在CreateRoutine中,BOUNCE驱动化PALETTEENTRY结构的一个数组,将第一个调色盘名目(与球在左上角的位置对应)设定为红色,其它的设定为白色。夺目,对于除布景之外的扫数名目,peFlags字段齐设定为PC_RESERVED(布景是临了的一个调色盘名目)。BOUNCE通过将Windows定时器的间隔设定为50毫秒来断绝CreateRoutine。
BOUNCE在PaintRoutine完成扫数的绘画使命。窗口布景用一个实心画刷和调色盘索引33所指定的神采来画图。33个球的神采是依据从0到32的调色盘索引的神采。当BOUNCE第一次在娇傲区域内绘画时,0的调色盘索引映像成红色,其它调色盘索引映像到白色。这导致球出当今左上角。
当WndProc处理WM_TIMER音讯并呼唤TimerRoutine时,动画就发生了。TimerRoutine通过呼唤AnimatePalette来齐备,语法如下:
其中,第一个参数是调色盘句柄,临了一个参数是指向数组的指针,该数组由一个或多个PALETTEENTRY结构构成。该函数变嫌逻辑调色盘中从uStart名目到uNum名目之间的若干名目。逻辑调色盘中新的uStart名目是PALETTEENTRY结构中的第一个成员。当心!uStart参数是投入原始逻辑调色盘表的索引,而不是投入PALETTEENTRY数组的索引。
为了便捷起见,BOUNCE使用PALETTEENTRY结构的数组,该结构是建筑逻辑调色盘时使用的LOGPALETTE结构的一部分。球的目前位置(从0到32)储存在静态变量iBall中。在TimerRoutine时期,BOUNCE将PALETTEENTRY成员设为白色。然后计较球的下一个位置,并将该元素设为红色。用底下的呼唤来变嫌调色盘:
GDI变嫌33逻辑调色盘名目中的第一个(尽管本体上只变嫌了两个),使它与系统调色盘表中的变化相对应,然后修改娇傲卡上的硬件调色盘表。这么,无用重画球就着手迁移了。
BOUNCE实施时,您会发现同期实施SYSPAL2或SYSPAL3成果会更好。
尽管AnimatePalette实施得非常快,但是当唯有一两个名目变嫌时,您还应该尽量幸免变嫌扫数的逻辑调色盘名目。这在BOUNCE中有点复杂,因为球要来去地跳-iBall要先加多,然后再减少。一种方法是使用两个变量:分一名为iBallOld(设定球的目前位置)和iBallMin(iBall和iBallOld中较小的)。然后您就不错像底下这么呼唤AnimatePalette来变嫌两个名目了:
还有另一种方法:咱们先假设您界说了一个PALETTEENTRY结构:
在TimerRoutine时期,您将PALETTEENTRY字段设为白色,并呼唤AnimatePalette来变嫌逻辑调色盘中iBall位置的一个名目:
然后计较娇傲在BOUNCE中的iBall的新值,将PALETTEENTRY结构的字段界说为红色,然后再次呼唤AnimatePalette:
尽管高出的球是对动画的一个传统的浅近评释,但它本体上并不相宜调色盘动画,因为必须先画出球的扫数可能位置。调色盘动画更相宜于娇傲通顺的叠加图案。
一个名主义调色盘动画
调色盘动画中一个更真理的方面即是,不错只使用一个调色盘名目来完成一些真理的技巧。举例门径16-8所示的FADER门径。这个门径也需要前边的PALANIM.C文献。
FADER在娇傲区域上娇傲满了笔墨字符串「Fade In And Out」。笔墨开端娇傲为白色,这对于白色布景的窗口来说是看不出来的。通过使用调色盘动画,FADER缓缓地将笔墨的神采改为蓝色,然后再改回白色,这么一遍一随处叠加。笔墨就有渐现渐隐的娇傲成果了。
FADER用CreateRoutine函数建筑了逻辑调色盘,它只需要一个调色盘名目,并将神采驱动化为白色-红色、绿色和蓝色值齐设为255。在PaintRoutine中(您可能念念起,当逻辑调色盘选进开拓内容并透露以后,PALANIM呼唤过此函数),FADER呼唤SetTextColor将笔墨神采设定为PALETTEINDEX(0)。这意味着笔墨神采设定为调色盘表格中的第一个名目,此名目驱动为白色。然后FADER用「Fade In And Out」笔墨字符串填充娇傲区域。这时,窗口布景是白色,笔墨亦然白色,是以笔墨不可见。
在TimerRoutine函数中,FADER通过变嫌PALETTEENTRY结构并将其传递给AnimatePalette来完成调色盘动画。领先,对每一个WM_TIMER音讯,门径齐将红色和绿色值减4,直到等于3;然后将这些值加4,直到等于255。这将使笔墨神采缓缓从白色变到蓝色,然后又回到白色。
门径16-9所示的ALLCOLOR门径只用了逻辑调色盘的一个名目来娇傲娇傲卡不错着色的扫数神采。天然,门径不是同期娇傲这些神采,而是连气儿娇傲。要是娇傲卡有18位的分辨率(这时能有262144种不同的神采),那么在两种神采间隔55毫秒的速率下,只需要4小时就不错在屏幕上看到扫数的神采。
在结构上,ALLCOLOR与FADER非常相似。在CreateRoutine中,ALLCOLOR只用一个设为玄色的调色盘名目(PALETTEENTRY结构的red、green和blue字段设为0)来建筑调色盘。在PaintRoutine中,ALLCOLOR用PALETTEINDEX(0)建筑实心画刷,并呼唤FillRect来用此画刷为悉数娇傲区域着色。
在TimerRoutine中,ALLCOLOR通过变嫌PALETTEENTRY神采并呼唤AnimatePalette来启动调色盘。我编写ALLCOLOR门径,以便神采变化顺畅。开端,蓝色值渐渐加多。达到最大时,绿色值加多,而蓝色值渐渐减少。红色、绿色和蓝色值的加多和减少取决于iIncr变量。在CreateRoutine时期,这将证明用COLORRES参数从GetDeviceCaps传回的值来计较。举例,要是GetDeviceCaps传回18,那么iIncr设为4-得到扫数神采所需要的最小值。
ALLCOLOR还在娇傲区域的左上角娇傲目前的RGB神采值。我领先添加这个门径代码是出于测试主义,但是当今讲解它是有用的,是以我保留了它。
工程应用门径
在工程应用门径中,动画对于娇傲机械或电的作用经由很有用。在计较机屏幕上娇傲内燃引擎天然浅近,但是动画不错使它变得愈加活泼,且更了了地娇傲其使命门径。
使用调色盘动画的一个好表率即是娇傲流体通过管子的经由。这是一个例子,图像不必十分精准-本体上,要是图像很精准(就像看穿明的管子),则很难评释管子里的流体是何如通顺的。这时用标记会更好一些。门径16-10所示的PIPES门径是此技巧的浅近示范:在娇傲区域有两个水平的管子,流体在上头的管子里从左向右流动,而不才面的管子里从右向降级移。
门径16-10 PIPES
PIPES为动画使用了16个调色盘名目,而您可能会使用更少的名目。最小化时,真实需要的是有鼓胀的名目来娇傲流动的标的。用三个调色盘名目要比用一个静态箭头好。
门径16-11所示的TUNNEL门径是这组门径中最贪念的门径,它为动画使用了128个调色盘名目,但是从成果来看,值得这么作念。
TUNNEL在128个调色盘名目中使用64种迁移的灰阶-从黑到白,再从白到黑-表当今纯正旅行的成果。
调色盘和真实寰宇图像
天然,尽管咱们还是完成了很多真理的事:连气儿娇傲颜色的底纹、作念了调色盘动画,但调色盘料理器的真实主义是允许在8位娇傲模式下娇傲真实寰宇中的图像。对于本章的其余部分,咱们只怕筹商一下。正如您所盼愿的,在使用packed DIB、GDI位图对象和DIB区块时,必须按照不同的方法来使用调色盘。底下的六个门径发达了用调色盘来处理位图的各式技巧。
调色盘和Packed DIB
底下三个门径,有助于咱们建筑处理packed DIB内存块的一系列函数。这些函数齐在门径16-12所示的PACKEDIB文献中。
第一个函数是PackedDibLoad,它将惟一的参数作为文献名,并传回指向内存中packed DIB的指针。其它扫数函数齐将这个packed DIB主义作为它们的第一个参数并传回联系DIB的信息。这些函数按「由下而上」规定枚举到文献中。每个函数齐使用从前边函数得到的信息。
我不倾向于说这是在处理packed DIB时有用的「齐备」函数集。而且,我也不念念汇编一个真实的推广集,因为我不以为这是处理packed DIB的一个好方法。在写雷同底下的函数时,您会很较着地发现这少许:
这种函数包括太多的巢状函数呼唤,以致于效用非常低而且很慢。本章的背面将接洽一种我以为更好的方法。
另外,您将夺目到,其中很多函数齐需要对OS/2兼容的DIB遴选不同的处理门径;这么,函数将频繁地查验BITMAPINFO结构的第一个字段是否与BITMAPCOREHEADER结构的大小相易。
迥殊夺目临了一个函数PackedDibCreatePalette。这个函数用DIB中的神采表来建筑调色盘。要是DIB中莫得神采表(这意味着DIB的每图素有16、24或32位),那么就不建筑调色盘。咱们有时会将从DIB神采表建筑的调色盘称为DIB 我方的调色盘。
PACKEDIB文献齐放在SHOWDIB3,如门径16-13所示。
SHOWDIB3中的窗口音讯处理门径将packed DIB指针作为静态变量来推奖,窗口音讯处理门径在「File Open」敕令时期呼唤PACKEDIB.C中的PackedDibLoad函数时得到了此主义。在处理此敕令的经由中,SHOWDIB3也呼唤PackedDibCreatePalette来得到可能用于DIB的调色盘。夺目,无论SHOWDIB3什么时候准备加载新的DIB,齐应先开释前一个DIB的内存,并删除前一个DIB的调色盘。在处理WM_DESTROY音讯的门径中,临了的DIB临了开释,临了的调色盘临了删除。
处理WM_PAINT音讯很浅近:要是存在调色盘,则SHOWDIB3将它选进开拓内容并透露它。然后它呼唤SetDIBitsToDevice,并传递联系DIB的函数信息(举例宽、高和指向DIB图素位的指针),这些信息从PACKEDIB中的函数得到。
另外,请记着SHOWDIB3依据DIB中的神采表建筑了调色盘。要是在DIB中莫得神采表-平素是16位、24位和32位DIB的情况-就不建筑调色盘。在8位娇傲模式下娇傲DIB时,它只能用规范保留的20种神采娇傲。
对这个问题有两种搞定方法:第一种是浅近地使用「通用」调色盘,这种调色盘适用于很多图形。您也不错我方建筑调色盘。第二种搞定方法是分析DIB的图素位,并决定要娇傲图像的最好神采。很较着,第二种方法将触及更多的使命(对于门径写稿家和处理器齐是如斯),但是我将在本章齐备之前告诉您何如使用第二种方法。
「通用」调色盘
门径16-14所示的SHOWDIB4门径建筑了一个通用的调色盘,它用于娇傲加载到门径中的扫数DIB。另外,SHOWDIB4与SHOWDIB3非常相似。
在处理WM_CREATE音讯时,SHOWDIB4将呼唤CreateAllPurposePalette,并在门径中保留该调色盘,而在WM_DESTROY音讯处理时期删除它。因为门径知说念调色盘一定存在,是以在处理WM_PAINT、WM_QUERYNEWPALETTE或WM_PALETTECHANGED音讯时,不必查验调色盘的存在。
CreateAllPurposePalette函数似乎是用247个名目来建筑逻辑调色盘,它超出了系统调色盘中允许门径正常存取的236个名目。真实如斯,不外这么作念很便捷。这些名目中有15个被复制或者映射到20种规范的保珍爱采中。
CreateAllPurposePalette从建筑31种灰阶着手,即0x00、0x09、0x11、0x1A、0x22、0x2B、0x33、0x3C、0x44、0x4D、0x55、0x5E、0x66、0x6F、0x77、0x80、0x88、0x91、0x99、0xA2、0xAA、0xB3、0xBB、0xC4、0xCC、0xD5、0xDD、0xE6、0xEE、0xF9和0xFF的红色、绿色和蓝色值。夺目,第一个、临了一个和中间的名目齐在规范的20种保珍爱采中。下一个函数用红色、绿色和蓝色值的扫数组合建筑了神采0x00、0x33、0x66、0x99、0xCC和0xFF。这么就共有216种神采,但是其中8种神采复制了规范的20种保珍爱采,而另外4个复制了前边计较的灰阶。要是将PALETTEENTRY结构的peFlags字段设为0,则Windows将不把复制的名目放进系统调色盘。
明显地,本体的门径不但愿计较16位、24位或者32位DIB的最好调色盘,门径将连接使用DIB神采表来娇傲8位DIB。SHOWDIB4不完成这项使命,它只对每件事齐使用通用调色盘。因为SHOWDIB4是一个展示门径,而且您不错与SHOWDIB3娇傲的8位DIB进行比拟。要是看一些东说念主像的彩色DIB,那么您可能会得出这么的论断:SHOWDIB4莫得鼓胀的神采来精准地暗示美丽的色调。
要是用SHOWDIB4中的CreateAllPurposePalette函数来实验(可能是通过将逻辑调色盘的大小减少到唯有几个名主义方法),您将发现当调色盘选进开拓内容时,Windows将只使用调色盘中的神采,而不使用规范的20种神采调色盘的神采。
中间色调色盘
Windows API包括一个通用调色盘,门径不错通过呼唤CreateHalftonePalette来得到该调色盘。使用此调色盘的方法与使用从SHOWDIB4中的CreateAllPurposePalette得到调色盘的方法相易,或者您也不错与位图缩放模式中的HALFTONE设定-用SetStretchBltMode设定-通盘使用。门径16-15所示的SHOWDIB5门径展示了使用中间色调色盘的方法。
SHOWDIB5门径雷同于SHOWDIB4,SHOWDIB4中不使用DIB中的神采表,而使用适用于图像领域更大的调色盘。为此,SHOWDIB5使用了由Windows接济的逻辑调色盘,其句柄不错从CreateHalftonePalette函数得到。
中间色调色盘并不比SHOWDIB4中的CreateAllPurposePalette函数所建筑的调色盘更复杂。真实,要是仅仅拿来私用,收尾是相似的。关联词,要是您呼唤底下两个函数:
其中,x和y是DIB左上角的开拓坐标,何况要是您用StretchDIBits而不是SetDIBitsToDevice来娇傲DIB,那么收尾会让您吃惊:神采色调要比不设定位图缩放模式来使用CreateAllPurposePalette或者CreateHalftonePalette更精准。Windows使用一种混色图案来处理中间色调色盘上的神采,以使其更接近8位娇傲卡上原始图像的神采。与您所念念象的一样,这么作念的过失是需要更多的处理时刻。
索引调色盘神采
当今着手处理SetDIBitsToDevice、StretchDIBits、CreateDIBitmap、SetDIBits、GetDIBits和CreateDIBSection的fClrUse参数。平素,您将这个参数设定为DIB_RGB_COLORS(等于0)。不外,您也能将它设定为DIB_PAL_COLORS。在这种情况下,假设BITMAPINFO结构中的神采表不包括RGB神采值,而是包括逻辑调色盘中神采名主义16位索引。逻辑调色盘是作为第一个参数传递给函数的开拓内容中目前遴荐的阿谁。本体上,在CreateDIBSection中,之是以需要指定一个非NULL的开拓内容句柄作为第一个参数,仅仅因为使用了DIB_PAL_COLORS。
DIB_PAL_COLORS能为您作念些什么呢?它可能提高一些性能。研讨一下在8位娇傲模式下呼唤SetDIBitsToDevice娇傲的8位DIB。Windows开端必须在DIB神采表的扫数神采中搜索与开拓可用神采最接近的神采。然后设定一个小表,以便将DIB图素值映像到开拓图素。也即是说,最多需要搜索256次最接近的神采。但是要是DIB神采表中含有从开拓内容中遴荐神采的逻辑调色盘名目索引,那么就可能跳过搜索。
除了使用调色盘索引之外,门径16-16所示的SHOWDIB6门径与SHOWDIB3相似。
SHOWDIB6将DIB加载到内存并由此建筑了调色盘以后,SHOWDIB6浅近地用以0着手的WORD索引替换了DIB神采表中的神采。PackedDibGetNumColors函数将暗示有若干种神采,而PackedDibGetColorTablePtr函数传回指向DIB神采表肇端位置的指针。
夺目,唯有径直从DIB神采表来建筑调色盘时,此技巧才可行。要是使用通用调色盘,则必须搜索最接近的神采,以得到放入DIB的索引。
要是要使用调色盘索引,那么请在将DIB储存到磁盘之前,如实替换掉DIB中的神采表。另外,不要将包含调色盘索引的DIB放入剪贴簿。本体上,在娇傲之前,将调色盘索引放入DIB,然后将RGB神采值放回,会更安全一些。
调色盘和位图对象
门径16-17中的SHOWDIB7门径娇傲了何如使用与DIB联系联的调色盘,这些DIB是使用CreateDIBitmap函数调理成GDI位图对象的。
与前边的门径一样,SHOWDIB7得到了一个指向packed DIB的主义,该DIB回话菜单的「File」、「Open」敕令。门径从packed DIB建筑了调色盘,然后-如故在WM_COMMAND音讯的处理经由中-得到了用于视讯娇傲的开拓内容,并选进调色盘,透露调色盘。然后SHOWDIB7呼唤CreateDIBitmap以便从DIB建筑DDB。要是调色盘莫得选进开拓内容并透露,那么CreateDIBitmap建筑的DDB将不使用逻辑调色盘中的附加神采。
呼唤CreateDIBitmap以后,该门径将开释packed DIB占用的内存空间。pPackedDib变量不是静态变量。相背的,SHOWDIB7按静态变量保留了位图句柄(hBitmap)和逻辑调色盘句柄(hPalette)。
在WM_PAINT音讯处理时期,调色盘再次选进开拓内容并透露。GetObject函数可得到位图的宽度和高度。然后,门径通过建筑兼容的内存开拓内容在娇傲区域娇傲位图,选进位图,并实施BitBlt。娇傲DDB时所用的调色盘,必须与从CreateDIBitmap呼唤建筑时所用的一样。
要是将位图复制到剪贴簿,则最好使用packed DIB形势。然后Windows不错将位图对象提供给但愿使用这些位图的门径。关联词,要是需要将位图对象复制到剪贴簿,则开端要得到视讯开拓内容并透露调色盘。这允许Windows依据目前的系统调色盘将DDB调理为DIB。
调色盘和DIB区块
临了,门径16-18所示的SHOWDIB8评释了何如使用带有DIB区块的调色盘。
在SHOWDIB7和SHOWDIB8中的WM_PAINT处理是一样的:两个门径齐将位图句柄(hBitmap)和逻辑调色盘句柄(hPalette)作为静态变量。调色盘被选进开拓内容并透露,位图的宽度和高度从GetObject函数得到,门径建筑内存开拓内容并选进位图,然后通过呼唤BitBlt将位图娇傲到娇傲区域。
两个门径之间最大的死别在于处理「File」、「Open」菜单敕令的门径。在得到指向packed DIB的主义并建筑了调色盘以后,SHOWDIB7必须将调色盘选进视讯开拓内容,并在呼唤CreateDIBitmap之前透露。SHOWDIB8在得到packed DIB主义以后呼唤CreateDIBSection。不必将调色盘选进开拓内容,这是因为CreateDIBSection不将DIB调理成开拓联系的形势。真实,CreateDIBSection的第一个参数(即开拓内容句柄)的惟一用途在于您是否使用DIB_PAL_COLORS旗标。
呼唤CreateDIBSection以后,SHOWDIB8将图素位从packed DIB复制到从CreateDIBSection函数传回的内存位置,然后呼唤PackedDibCreatePalette。尽管此函数便于门径使用,但是SHOWDIB8将依据从GetDIBColorTable函数传回的信息建筑调色盘。
DIB 处理链接库
即是当今-经过咱们万古刻地学习GDI位图对象、开拓无关位图、DIB区块和Windows调色盘料理器之后-咱们才作念好了开发一套有助于处理位图的函数的准备。
前边的PACKEDIB文献展示了一种可能的方法:内存中的packed DIB只用指向它的主义暗示。门径所的联系DIB的全部信息齐不错从存取表头信息结构的函数得到。关联词,本体上到「get pixel」和「set pixel」例程时,这种方法就会产生严重的实施问题。图像处理任务天然需要存取位图位,何况这些函数也应该尽可能地快。
可能的C++的搞定格局中包括建筑DIB类别,这时指向packed DIB的主义只怕是一个成员变量。其它成员变量和成员函数有助于更快地实施得到和设定DIB中的图素的例程。不外,因为我在第一章还是指出,对于本书您只需要了解C,使用C++将是其它书的领域。
天然,用C++能作念的事情用C也能作念。一个好的例子即是很多Windows函数齐使用句柄。除了将句柄算作数值之外,应用门径对它还了解什么呢?门径知说念句柄援用格外的函数对象,还知说念函数用于处理现有的对象。明显,操作系统按某种格局用句柄来援用对象的里面信息。句柄不错与结构指针一样浅近。
举例,假设有一个函数集,这些函数齐使用一个称为HDIB的句柄。HDIB是什么呢?它可能在某个表头文献中界说如下:
此界说用「不关您的事」回答了「HDIB是什么」这个问题。
关联词,本体上HDIB可能是结构指针,该结构不仅包括指向packed DIB的指针,还包括其它信息:
此结构的其它五个字段包括从packed DIB中引出的信息。天然,结构中这些值允许更快速地存取它们。不同的DIB链接库函数齐不错处理这个结构,而不是pPackedDib主义。不错按底下的方法来实施DibGetPixelPointer函数:
天然,这种方法可能要比PACKEDIB.C中实施「get pixel」例程快。
由于这种方法非常合理,是以我决定毁灭packed DIB,并改用处理DIB区块的DIB链接库。这本体上使咱们对packed DIB的处理有更大的弹性(也即是说,概况在开拓无关的格局下驾驭DIB图素位),而且在Windows NT下实施时将更有用。
DIBSTRUCT结构
DIBHELP.C文献-如斯定名是因为对处理DIB提供匡助-有上千行,并在几个小部分中娇傲。但是开端让咱们看一下DIBHELP函数所处理的结构,该结构在DIBHELP.C中界说如下:
当今跳过第一个字段。它之是以为第一个字段是因为它使某些宏更易于使用-在接洽完其它字段以后再来意会第一个字段就更容易了。
在DIBHELP.C中,当DIB建筑的函数开端设定了此结构时,第二个字段就设定为笔墨字符串「Dib」的二进制值。通过一些DIBHELP函数,第二个字段将用于结构有用指针的一个标记。
第三个字段,即hBitmap,是从CreateDIBSection函数传回的位图句柄。您将念念起该句柄可有多种使用格局,它与咱们在 第十四章遭受的GDI位图对象的句柄用法一样。不外,从CreateDIBSection传回的句柄将触及按开拓无关形势储存的位图,该位图形势一直储存到通过呼唤BitBlt和StretchBlt来将位丹青到输出开拓。
DIBSTRUCT的第四个字段是指向位图位的指针。此值也可由CreateDIBSection函数设定。您将念念起,操作系统将截至这个内存块,但应用门径有存取它的权限。在删除位图句柄时,内存块将自动开释。
DIBSTRUCT的第五个字段是DIBSECTION结构。要是您有从CreateDIBSection传回的位图句柄,那么您不错将句柄传递给GetObject函数以得到联系DIBSECTION结构中的位图信息:
作为辅导,DIBSECTION结构在WINGDI.H中界说如下:
第一个字段是BITMAP结构,它与CreateBitmapIndirect通盘建筑位图对象,与GetObject通盘传回对于DDB的信息。第二个字段是BITMAPINFOHEADER结构。不管位图信息结构是否传递给CreateDIBSection函数,DIBSECTION结构总有BITMAPINFOHEADER结构而不是其它结构,举例BITMAPCOREHEADER结构。这意味着在存取此结构时,DIBHELP.C中的很多函数齐不必查验与OS/2兼容的DIB。
对于16位和32位的DIB,要是BITMAPINFOHEADER结构的biCompression字段是BI_BITFIELDS,那么在信息表头结构背面平素有三个屏蔽值。这些屏蔽值决定何如将16位和32位图素值调理成RGB神采。屏蔽储存在DIBSECTION结构的第三个字段中。
DIBSECTION结构的临了两个字段指的是DIB区块,此区块由文献映射建筑。DIBHELP不使用CreateDIBSection的这个特点,因此不错忽略这些字段。
DIBSTRUCT的临了两个字段储存控制移位值,这些值用于处理16位和32位DIB的神采屏蔽。咱们将在 第十五章接洽这些移位值。
让咱们再追思看一下DIBSTRUCT的第一个字段。正如咱们所看到的一样,在着手建筑DIB时,此字段设定为指向一个指针数组的指针,该数组中的每个指针齐指向DIB中的一滑图素。这些主义允许以更快的格局来得到DIB图素位,同期也被界说,以便顶行不错开端援用DIB图素位。此数组的临了一个元素-援用DIB图像的最底行-平素等于DIBSTRUCT的pBits字段。
信息函数
DIBHELP.C以界说DIBSTRUCT结构着手,然后提供一个函数集,此函数集允许应用门径得到联系DIB区块的信息。门径16-19娇傲了DIBHELP.C的第一部分。
DIBHELP.C中的大部分函数是无用解释的。DibIsValid函数能有助于保护悉数系统。在试图援用DIBSTRUCT中的信息之前,其它函数齐呼唤DibIsValid。扫数这些函数齐有(而且平素是唯有)HDIB型态的第一个参数,( 咱们将立即看到)该参数在DIBHELP.H中界说为空主义。这些函数不错将此参数储存到PDIBSTRUCT,然后再存取结构中的字段。
夺目传回BOOL值的DibIsAddressable函数。DibIsNotCompressed函数也不错呼唤此函数。传回值暗示孤独的DIB图素能否寻址。
以DibInfoHeaderSize着手的函数集将取得DIB区块中不同组件出当今packed DIB中的大小。与咱们所看到的一样,这些函数有助于将DIB区块调理成packed DIB,并储存DIB文献。这些函数的背面是得到指向不同DIB组件的指针的函数集。
尽管DIBHELP.C包括称号为DibInfoHeaderPtr的函数,而且该函数将得到指向BITMAPINFOHEADER结构的指针,但如故莫得函数不错得到BITMAPINFO结构指针-即接在DIB神采表背面的信息结构。这是因为在处理DIB区块时,应用门径并不径直存取这种型态的结构。BITMAPINFOHEADER结构和神采屏蔽齐在DIBSECTION结构中有用,而且从CreateDIBSection函数传回指向图素位的指针,这时通过呼唤GetDIBColorTable和SetDIBColorTable,就只能辗转存取DIB神采表。这些功能齐封装到DIBHELP的DibGetColor和DibSetColor函数里头了。
在DIBHELP.C的背面,文献DibCopyToInfo设立一个指向BITMAPINFO结构的指针,并填充信息,但是那与得到指向内存中现有结构的指针不全齐相易。
读、写图素
应用门径推奖packed DIB或DIB区块的一个引东说念主庄重的优点是概况径直操作DIB图素位。门径16-20所示的DIBHELP.C第二部分列出了提供此功能的函数。
这部分DIBHELP.C从DibPixelPtr函数着手,该函数得到指向储存(或部分储存)有格外图素的字节的指针。回念念一下DIBSTRUCT结构的ppRow字段,那是个指向DIB中由顶步履手枚举的图素行地址的指针。这么,
即是指向DIB顶行最左端图素的主义,而
是指向位于(x,y)的图素的主义。夺目,要是DIB中的图素不可被寻址(即要是已压缩),或者要是函数的x和y参数是负数或相对位于DIB外面的区域,则函数将传回NULL。此查验裁汰了函数(和扫数依赖于DibPixelPtr的函数)的实施速率,底下我将叙述一些更快的例程。
文献背面的DibGetPixel和DibSetPixel函数愚弄了DibPixelPtr。对于8位、16位和32位DIB,这些函数只记载指向合适数据尺寸的指针,并存取图素值。对于1位和4位的DIB,则需要屏蔽和移位角度。
DibGetColor函数按RGBQUAD结构得到图素神采。对于1位、4位和8位DIB,这包括使用图素值来从DIB神采表得到神采。对于16位、24位和32位DIB,平素必须将图素值屏蔽和移位以得到RGB神采。DibSetPixel函数则相背,它允许从RGBQUAD结构设定图素值。该函数只为16位、24位和32位DIB界说。
建筑和调理
门径16-21所示的DIBHELP第三部分和临了部分展示了何如建筑DIB区块,以及何如将DIB区块与packed DIB相互调理。
这部分的DIBHELP.C文献从两个小函数着手,这两个函数证明16位和32位DIB的神采屏蔽得到左、右移位值。这些函数在 第十五章「神采屏蔽」一节评释。
DibCreateFromInfo函数是DIBHELP中惟一呼唤CreateDIBSection并为DIBSTRUCT结构设立内存的函数。其它扫数建筑和复制函数齐叠加此函数。DibCreateFromInfo惟一的参数是指向BITMAPINFO结构的指针。此结构的神采表必须存在,但是它不必用有用的值填充。呼唤CreateDIBSection之后,该函数将驱动化DIBSTRUCT结构的扫数字段。夺目,在设定DIBSTRUCT结构的ppRow字段的值时(指向DIB行地址的指针),DIB有由下而上和由上而下的不同储存格局。ppRow着手的元素即是DIB的顶行。
DibDelete删除DibCreateFromInfo中建筑的位图,同期开释在该函数中设立的内存。
DibCreate可能比DibCreateFromInfo更像一个从应用门径呼唤的函数。前三个参数提供图素的宽度、高度和每图素的位数。临了一个参数不错设定为0(用于神采表的内定尺寸),或者设定为非0(暗示比每图素位数所需要的神采表更小的神采表)。
DibCopy函数证明现有的DIB区块建筑新的DIB区块,并用DibCreateInfo函数为BITMAPINFO结构设立了内存,还填了扫数的数据。DibCopy函数的一个BOOL参数指出是否在建筑新的DIB时交换了DIB的宽度和高度。咱们将在背面看到此函数的用法。
DibCopyToPackedDib和DibCopyFromPackedDib函数的使用平素与透过剪贴簿传递DIB联系。DibFileLoad函数从DIB文献建筑DIB区块;DibFileSave函数将数据储存到DIB文献。
临了,DibCopyToDdb函数证明DIB建筑GDI位图对象。夺目,该函数需要目前调色盘的句柄和门径窗口的句柄。门径窗口句柄用于得到选进并透露调色盘的开拓内容。唯有这么,函数才不错呼唤CreateDIBitmap。这曾在本章前边的SHOWDIB7中展示。
DIBHELP表头文献和宏
DIBHELP.H表头文献如门径16-22所示。
这个表头文献将HDIB界说为空主义(void* )。应用门径真实不需要了解HDIB所指结构的里面结构。此表头文献还包括DIBHELP.C中扫数函数的评释,还有一些宏-非常格外的宏。
要是再看一看DIBHELP.C中的DibPixelPtr、DibGetPixel和DibSetPixel函数,并试图提高它们的实施速率阐扬,那么您将看到两种可能的搞定方法。第一种,不错删除扫数的查验保护,并信赖应用门径不会使用无效参数呼唤函数。还不错删除一些函数呼唤,举例DibBitCount,并使用指向DIBSTRUCT结构里面的指针来径直得到信息。
提高实施速率阐扬另一项较不较着的方法是删除扫数对每图素位数的处理格局,同期分离出处理不同DIB函数-举例DibGetPixel1、DibGetPixel4、DibGetPixel8等等。下一个最好化智商是删除悉数函数呼唤,将其处理动作透过inline function或宏中进行合并。
好色妖姬杨贵妃DIBHELP.H遴选宏的方法。它依据DibPixelPtr、DibGetPixel和DibSetPixel函数提倡了三套宏。这些宏齐明确对应于格外的图素位数。
DIBBLE门径
DIBBLE门径,如门径16-23所示,使用DIBHELP函数和宏使命。尽管DIBBLE是本书中最长的门径,它如实仅仅一些功课的粗陋表率,这些功课不错在浅近的数字影像处理门径中找到。对DIBBLE的较着矫恰是调理成了多重文献接口(MDI:multiple document interface),咱们将在 第十九章学习联系多重文献接口的常识。
DIBBLE使用了两个其它文献,我将简要塞评释它们。DIBCONV文献(DIBCONV.C和DIBCONV.H)在两种不同形势之间调理-举例,从每图素24位调理成每图素8位。DIBPAL文献(DIBPAL.C和DIBPAL.H)建筑调色盘。
DIBBLE推奖WndProc中的三个宏大的静态变量。这些是呼唤hdib的HDIB句柄、呼唤hPalette的HPALETTE句柄和呼唤hBitmap的HBITMAP句柄。HDIB来自DIBHELP中的不同函数;HPALETTE来自DIBPAL中的不同函数或CreateHalftonePalette函数;而HBITMAP句柄来自DIBHELP.C中的DibCopyToDdb函数并匡助加快屏幕娇傲,迥殊是在256色娇傲模式下。不外,无论在门径建筑新的「DIB Section」(显而易观点)或在门径建筑不同的调色盘(不很较着)时,这个句柄齐必须重新建筑。
让咱们从功能上而非按序渐进地来先容一下DIBBLE。
文献载入和储存
DIBBLE不错在反应IDM_FILE_LOAD和IDM_FILE_SAVE的WM_COMMAND音讯处理经由中加载DIB文献并储存这些文献。在处理这些音讯处理时期,DIBBLE通过差别呼唤GetOpenFileName和GetSaveFileName来启动公用文献对话框。
对于「File」、「Save」菜单敕令,DIBBLE只需要呼唤DibFileSave。对于「File」、「Open」菜单敕令,DIBBLE必须开端删除前边的HDIB、调色盘和位图对象。它透过发送一个WM_USER_DELETEDIB音讯来完成这件事,此音讯通过呼唤DibDelete和DeleteObject来处理。然后DIBBLE呼唤DIBHELP中的DibFileLoad函数,发送WM_USER_SETSCROLLS和WM_USER_CREATEPAL音讯来重新设定转动条并建筑调色盘。WM_USER_CREATEPAL音讯也位于门径从DIB区块建筑的新的DDB位置。
娇傲、卷动和打印
DIBBLE的菜单允许它以本体尺寸在娇傲区域左上角娇傲DIB,或在娇傲区域中间娇傲DIB,或伸展到填充娇傲区域,或者在保握纵横比的情况下尽量填充娇傲区域。您不错在DIBBLE的「Show」菜单上来遴荐需要的选项。夺目,这些与上一章的SHOWDIB2门径中四个选项相易。
在WM_PAINT音讯处理时期-亦然处理「File」、「Print」敕令的经由中-DIBBLE呼唤DisplayDib函数。夺目,DisplayDib使用BitBlt和StretchBlt,而不是使用SetDIBitsToDevice和StretchDIBits。在WM_PAINT音讯处理时期,传递给函数的位图句柄由DibCopyToDdb函数建筑,并在WM_USER_CREATEPAL音讯处理时期呼唤。其中DDB与视讯开拓内容兼容。当处理「File」、「Print」敕令时,DIBBLE呼唤DisplayDib,其中可用的DIB区块句柄来自DIBHELP.C中的DibBitmapHandle函数。
另外要夺目,DIBBLE保留一个称作fHalftonePalette的静态BOOL变量,要是从CreateHalftonePalette函数中得到hPalette,则此变量设定为TRUE。这将迫使DisplayDib函数呼唤StretchBlt而不是呼唤BitBlt,即使DIB被指定按本体尺寸娇傲。fHalftonePalette变量也导致WM_PAINT处理门径将DIB区块句柄传递给DisplayDib函数,而不是由DibCopyToDdb函数建筑的位图句柄。本章前边接洽过中间色调色盘的使用,并在SHOWDIB5门径中进行了展示。
第一次使用表率门径时,DIBBLE允许在娇傲区域中卷动DIB。唯有按本体尺寸娇傲DIB时,才娇傲转动条。在处理WM_PAINT时,WndProc浅近地将转动条的目前位置传递给DisplayDib函数。
剪贴簿
对于「Cut」和「Copy」菜单项,DIBBLE呼唤DIBHELP中的DibCopyToPackedDib函数。该函数将得到扫数的DIB组件并将它们放入大的内存块中。
对于第一次使用本书中的某些表率门径来说,DIBBLE从剪贴簿中粘贴DIB。这包括呼唤DibCopyFromPackedDib函数,并替换窗口音讯处理门径前边储存的HDIB、调色盘和位图。
翻转和旋转
DIBBLE中的「Edit」菜单中除了常见的「Cut」、「Copy」、「Paste」和「Delete」选项之外,还包括两个附加项-「Flip」和「Rotate」。「Flip」选项使位图绕水平轴翻转-即险峻倒置翻转。「Rotate」选项使位图顺时针旋转90度。这两个函数齐需要透过将它们从一个DIB复制到另一个来存取扫数的DIB图素(因为这两个函数不需要建筑新的调色盘,是以不删除和重新建筑调色盘)。
「Flip」菜单选项使用DibFlipHorizontal函数,此函数也位于DIBBLE.C文献。此函数呼唤DibCopy来得到DIB精准的副本。然后,投入将原DIB中的图素复制到新DIB的轮回,但是复制这些图素是为了险峻翻转图像。夺目,此函数呼唤DibGetPixel和DibSetPixel。这些是DIBHELP.C中的通用(但不像咱们所但愿的那么快)函数。
为了评释DibGetPixel和DibSetPixel函数与DIBHELP.H中实施更快的DibGetPixel和DibSetPixel宏之间的区别,DibRotateRight函数使用了宏。关联词,开端要夺主义是,该函数呼唤DibCopy时,第二个参数设定为TRUE。这导致DibCopy翻转原DIB的宽度和高度来建筑新的DIB。另外,图素位不可由DibCopy函数复制。但是,DibRotateRight函数有六个不同的轮回将图素位从原DIB复制到新的DIB-每一个齐对应不同的DIB图素宽度(1位、4位、8位、16位、24位和32位)。天然包括了更多的门径代码,但是函数更快了。
尽管不错使用「Flip Horizontal」和「Rotate Right」选项来产生「Flip Vertical」、「Rotate Left」和「Rotate 180°」功能,但平素门径将径直实施扫数选项。毕竟,DIBBLE仅仅个展示门径良友。
浅近调色盘;最好化调色盘
在DIBBLE中,您不错在256色视讯娇傲器上遴荐不同的调色盘来娇傲DIB。这些齐在DIBBLE的「Palette」菜单中列出。除了中间色调色盘之外,其余的齐径直由Windows函数呼唤建筑,建筑不同调色盘的扫数函数齐由门径16-24所示的DIBPAL文献提供。
第一个函数-DibPalDibTable-看起来应该很练习。它证明DIB的神采表建筑了调色盘。这与本章前边的SHOWDIB3中所用到的PACKEDIB.C里的PackedDibCreatePalette函数相似。在SHOWDIB3中,唯有当DIB有神采表时才实施此函数。在8位娇傲模式下试图娇傲16位、24位或32位DIB时,此函数就没用了。
预设情况下,实施在256色娇傲模式下时,DIBBLE将开端尝试呼唤DibPalDibTable来证明DIB神采表建筑调色盘。要是DIB莫得神采表,则DIBBLE将呼唤CreateHalftonePalette并将fHalftonePalette变量设定为TRUE。此逻辑发生在WM_USER_CREATEPAL音讯处理时期。
DIBPAL.C也实施函数DibPalAllPurpose,因为此函数与SHOWDIB4中的CreateAllPurposePalette函数非常相似,是以它看起来也很练习。您也不错从DIBBLE菜单中遴荐此调色盘。
在256色模式下娇傲位图最真理的是,您不错径直截至Windows用于娇傲图像的神采。要是您遴荐并透露调色盘,则Winsows将使用此调色盘中的神采,而不是其它调色盘中的神采。
举例,您不错用DibPalUniformGrays函数来单独建筑一种灰阶调色盘。使用两种灰阶的调色盘则只含有00-00-00(玄色)和FF-FF-FF(白色)。用此调色盘来输出图像将提供某些相片中常用的高对比「口角」成果。使用3种灰阶将在玄色和白色中间添加中间灰色,使用4种灰阶将添加2种灰阶。
用8种灰阶,您就有可能看到较着的空洞-相易灰阶的无国法雀斑,天然很较着地实施了最接近神采算法,但是一般仍不带有任何审好意思判断。平素到16种灰阶就不错较着改善图像画质。使用32种灰阶差未几就不错排除全部空洞了。而目前渊博以为64种灰阶是当今大渊博娇傲开拓的极限。在这点以上,再擢升也没什么边缘效益了。在6位神采分辨率的开拓上提供超越64种灰阶看不出有什么矫正之处。
迄今为止,对于8位娇傲模式下娇傲16位、24位和32位彩色DIB,咱们最多即是概况打算通用调色盘(这对灰阶图像很有用,但平素不适于彩色图像)或者使用中间色调色盘,它用混色娇傲与通用神采调色盘合用。
还应夺目,当您在8位神采模式下为大张16位、24位或32位DIB遴荐通用调色盘时,为了要娇傲这些图像,门径将挥霍一些时刻依据DIB的内容来建筑GDI位图对象。要是不需要调色盘,则门径证明DIB来建筑DDB的时刻会更少(用8位彩色模式娇傲大24位DIB时,比拟SHOWDIB1和SHOWDIB4的性能,您也能看出这点区别)。这是为什么呢?
它按最接近神采搜寻。平素,用8位娇傲模式娇傲24位DIB时(或者将DIB调理为DDB),GDI必须将DIB中的每个图素齐与静态20种神采中的一种相迫临。完成此操作的惟一方法是决定哪种静态神采与图素神采最接近。这包括计较图素与三维RGB神采中每种静态神采的距离。这将花些时刻,迥殊是在DIB图像中有上百万个图素时。
在建筑232色调色盘时,举例DIBBLE和SHOWDIB4中的通用调色盘,您会很快将搜索最接近神采的时刻加多到超越11倍!GDI当今必须透澈查验232种神采,而不是20种。那即是娇傲DIB的悉数功课延缓的原因。
这里的训戒是幸免在8位娇傲模式下娇傲24位(或16位,或32位)DIB。您应该找出最接近DIB图像神采领域的256色调色盘,来将它们调理成8位DIB。这通常称为「最好调色盘」。当我筹商这个问题的时候,Paul Heckbert编写的〈Color Image Quantization for Frame Buffer Displays〉(刊登在1982年7月出书的《Computer Graphics》)对此问题有所匡助。
均匀分散
建筑256色调色盘最浅近的方法是遴荐领域和洽的RGB神采值,它与DibPalAllPurpose中的方法相似。此方法的优点是您不必查验DIB中的本体图素。这个函数是DibPalCreateUniformColors,它依据领域和洽的RGB三原色索引建筑调色盘。
一个合理的分散包括8阶红色和绿色以及4阶蓝色(肉眼对蓝色较不解锐)。调色盘是RGB神采值的蚁合,它是红色和绿色值0x00、0x24、0x49、0x6D、0x92、0xB6、0xDB和0xFF以及蓝色值0x00、0x55、0xAA和0xFF的扫数可能的组合,共有256种神采。另一种可能的和洽分散调色盘使用6阶红色、绿色和蓝色。此调色盘是红色、绿色和蓝色值为0x00、0x33、0x66、0x99、0xCC和0xFF的扫数可能的组合,调色盘中的神采数是6的3次方,即216。
这两个选项和其它几个选项齐由DIBBLE提供。
「Popularity」算法
「Popularity」算法是256色调色商量题相等较着的搞定方法。您要作念的即是走遍位图中的扫数图素,并找出256种最普通的RGB神采值。这些即是您在调色盘中使用的值。DIBPAL的DibPalPopularity函数中实作了这种算法。
不外,要是每种神采齐使用悉数24位,而且假设需要用整数来计较扫数的神采,那么数组将占据64MB内存。另外,您不错发现位图中本体上莫得(或很少)叠加的24位图素值,这么就莫得所谓常见的神采了。
要搞定这个问题,您不错只使用每个红色、绿色和蓝色值中最宏大的n位-举例,6位而不是8位。因为大渊博的彩色扫描仪和视讯娇傲卡齐唯有6位的分辨率,是以这么章程更特意旨。这将数组减少到大小更合理的256KB或1MB。只使用5位能将可用的神采总和减少到32,768。平素,使用5位要比6位的性能更好。对此,您不错用DIBBLE和一些图像神采来我方考研。
「Median Cut」算法
DIBPAL.C中的DibPalMedianCut函数实施Paul Heckbert的Median Cut算法。此算法在看法上相等浅近,但在门径代码中实作要比Popularity算法更繁难,它相宜递归函数。
画出RGB神采立方体。图像中的每个图素齐是此立方体中的一个点。一些点可能代表图像中的多个图素。找出包括图像中扫数图素的立体方块,找出此方块的最大尺寸,并将方块分红两个,每个方块齐包括相易数目的图素。对于这两个方块,实施相易的操作。当今您就有4个方块,将这4个方块分红8个,然后再分红16个、32个、64个、128个和256个。
当今您有256个方块,每个方块齐包括相易数目的图素。取每个方块中图素RGB神采值的平均值,并将收尾用于调色盘。
本体上,这些方块平素包含图素的数目并不相易。举例,平素包括单个点的方块会有更多的图素。这发生在玄色和白色上。有时,一些方块里头根柢莫得图素。要是这么,您就不错省下更多的方块,但是我决定不这么作念。
另一种最好化调色盘的技巧称为「octree quantization」,此技巧由Jeff Prosise提倡,并于1996年8月发表在《Microsoft Systems Journal》上(包含在MSDN的CD中)。
调理形势
DIBBLE还允许将DIB从一种形势调理到另一种形势。这用到了DIBCONV文献中的DibConvert函数,如门径16-25所示。
将DIB从一种形势调理成另一种形势需要几种不同的方法。
要将带有神采表的DIB调理成另一种也带有神采表但有较大的图素宽度的DIB(亦即,将1位DIB调理成4位或8位DIB,或将4位DIB调理成8位DIB),所需要作念的即是透过呼唤DibCreate来建筑新的DIB,并在呼唤时带有但愿的位数以及与原始DIB中的神采数迥殊的神采数。然后函数复制图素位和神采表名目。
要是新的DIB莫得神采表(即位数是16、24或32),那么DIB只需要按新形势建筑,而且通过呼唤DibGetPixelColor和DibSetPixelColor从现有的DIB中复制图素位。
底下的情况可能更渊博:现有的DIB莫得神采表(即位数是16、24或32),而新的DIB每图素占8位。这种情况下,DibConvert呼唤DibPalMedianCut来为图像建筑最好化的调色盘。新DIB的神采表设定为调色盘中的RGB值。DibGetPixelColor函数从现有的DIB中得到图素神采。透过呼唤GetNearestPaletteIndex来调理成8位DIB中的图素值,并透过呼唤DibSetPixel将图素值储存到DIB。
当DIB需要调理成单色DIB时,用包括两个名目-玄色和白色-的神采表建筑新的DIB。另外,GetNearestPaletteIndex有助于将现有DIB中的神采调理成图素值0或1。雷同地,当8个图素位或更多位的DIB要调理成4位DIB时,可从DibPalVga函数得到DIB神采表,同期GetNearestPaletteIndex也有助于计较图素值。
尽管DIBBLE示范了何如着手写一个图像处理门径基础第四色播,但是门径临了如故莫得全部完成,咱们老是会念念到还有些功能莫得加进去里头。但是很可惜的是,咱们当今得住手连接筹商这些东西,而往下接洽别的东西了。