前言:
学习笔记,随时更新。如有谬误,欢迎指正。
说明:
- 红色字体为较为重要部分。
- 绿色字体为个人理解部分。
原文链接:https://learn.microsoft.com/en-us/windows/win32/gdi/colors
4 颜色
- 颜色是应用程序生成的图片和图像中的重要元素。
4.1 关于颜色
4.1.1 颜色基础知识
-
应用程序可以使用 GetDeviceCaps 函数获取 NUMCOLORS 值来发现给定设备可用的颜色数。
-
NUMCOLORS 值只指定颜色计数,不列举可用的颜色值。应用程序可以使用 EnumObjects 函数枚举笔来获取所有可用颜色值。有关代码示例,请参阅枚举颜色。
4.1.1.1 颜色值
-
系统和应用程序使用具有 COLORREF 类型的参数和变量来传递和存储颜色值。
-
应用程序可以通过分别使用 GetRValue 、 GetGValue 和 GetBValue 宏从颜色值中提取红色、绿色和蓝色分量的各个值。
-
应用程序可以使用 RGB 宏从单个分量值创建颜色值。
4.1.1.2 颜色近似值和抖色
-
很少有设备能保证每一个可能的颜色值的精确匹配,因此,如果应用程序请求设备无法生成的颜色,系统将使用设备可以生成的颜色来近似该颜色。
-
应用程序可以通过使用 GetNearestColor 函数来发现系统是否会近似给定的颜色。该函数接受一个颜色值,并返回设备可以生成的最接近的匹配颜色的颜色值。系统用来确定这个近似值的方法取决于设备驱动程序及其颜色能力。在大多数情况下,近似颜色的总体强度最接近请求的颜色。
-
当应用程序创建笔或为文本设置颜色时,如果不存在精确匹配,系统总是近似地使用颜色。当应用程序创建一个纯色画刷时,系统可能会尝试通过抖色来模拟所请求的颜色。
-
抖色通过在图案中交替两种或两种以上的颜色来模拟颜色。根据颜色和图案的不同,抖色可以产生合理的模拟效果。它对单色设备最有用,因为它扩展了可用“颜色”的数量。用于创建抖色的方法取决于设备驱动程序。大多数设备驱动程序使用标准抖动算法,该算法根据请求的红、绿和蓝的强度值来生成抖色模式。
4.1.1.3 位图中的颜色
-
使用 CreateBitmap 或 CreateCompatibleBitmap 函数创建的兼容位图特定于设备( DDB ),并且以与设备相关的格式保留颜色信息。不使用颜色值,并且颜色不受近似值和抖色的约束。
-
独立于设备的位图 (DIB) 将颜色信息保留为颜色值或调色板索引。如果使用颜色值,则颜色受近似值限制,但不会抖色。调色板索引只能用于支持调色板的设备。虽然系统不会近似或抖色索引标识的颜色,但结果颜色可能与预期的不同,因为索引仅在创建位图时当前调色板的上下文中生成有效结果。如果调色板发生更改,位图中的颜色也随之更改。有关调色板索引的详细信息,请参阅默认调色板 和 PALETTEINDEX 。
-
除了引用逻辑调色板之外,应用程序还可以引用 DIB 颜色表中的值。要在 DIB 颜色表中选择颜色,请调用 DIBINDEX 。注意,这只适用于选择了 DIB 的设备上下文。
4.1.1.4 颜色混合
-
颜色混合允许应用程序通过将笔或画刷的颜色与现有图像中的颜色相结合来创建新的颜色。
-
前景混合模式,也称二进制光栅操作,决定了这些颜色的混合方式。使用 SetROP2 函数设置前景混合模式,使用 GetROP2 函数查询当前模式。
-
颜色混合受近似和抖色的影响。
-
有背景混合模式,但该模式不能控制颜色的混合,它指定在绘制样式线、阴影画刷和文本时是否使用背景颜色。
4.1.2 调色板
-
调色板是一个数组,其中包含标识当前可以在输出设备上显示或绘制的颜色的颜色值。调色板由能够生成许多颜色的设备使用,但在任何给定时间只能显示或绘制其中的一个子集。对于这样的设备,系统维护一个系统调色板来跟踪和管理设备的当前颜色。应用程序不能直接访问系统调色板。相反,系统将默认调色板与每个设备上下文关联起来。应用程序可以使用默认调色板中的颜色,也可以通过创建逻辑调色板并将其与各个设备上下文关联来定义自己的颜色。
-
应用程序可以通过检查 GetDeviceCaps 函数返回的 RASTERCAPS 值中的 RC_PALETTE 位来确定设备是否支持调色板。
4.1.2.1 默认调色板
-
默认调色板是一个颜色值数组,用于标识默认情况下可以与设备上下文一起使用的颜色。每当应用程序为支持调色板的设备创建上下文时,系统都会将默认调色板与上下文关联起来。默认调色板确保颜色可供应用程序使用,而无需任何进一步操作。
-
默认调色板通常有 20 个颜色项(颜色),但颜色项的确切数量可能因设备而异。这个数字等于 GetDeviceCaps 函数返回的 NUMCOLORS 值。应用程序可以通过枚举纯色笔来查询默认调色板中颜色的颜色值。默认调色板中的颜色也取决于设备。
-
当使用默认调色板时,应用程序使用颜色值来指定笔和文本的颜色。如果请求的颜色不在调色板中,系统将使用调色板中最接近的颜色来近似该颜色。如果应用程序请求的纯色画刷颜色不在调色板中,系统将通过与调色板中的颜色抖色来模拟该颜色。
为了避免近似和抖色,应用程序还可以通过使用调色板索引而不是颜色值来指定笔、画刷和文本颜色。调色板索引是标识特定调色板颜色项的整数值。应用程序可以使用调色板索引代替颜色值,但必须使用 PALETTEINDEX 宏来创建索引。
调色板索引仅对支持调色板的设备有用。为了避免这种设备依赖性,使用相同代码绘制到调色板和非调色板设备的应用程序应该使用与调色板相关的颜色值来指定笔、画刷和文本颜色。应用程序必须使用 PALETTERGB 宏来创建与调色板相关的颜色值。
-
系统不允许应用程序更改默认调色板中的颜色项。要使用默认调色板以外的颜色,应用程序必须创建自己的逻辑调色板,并将该调色板选择到设备上下文中。
4.1.2.2 逻辑调色板
-
逻辑调色板是一个由应用程序创建并与给定设备上下文相关联的调色板。逻辑调色板允许应用程序定义和使用满足其特定需求的颜色。
-
应用程序可以创建任意数量的逻辑调色板(应用程序可以创建的最大调色板数量取决于系统的资源),将其应用于单独的设备上下文,或者在单个设备上下文中切换使用。
-
应用程序使用 CreatePalette 函数创建逻辑调色板。要使用逻辑调色板,应用程序通过使用 SelectPalette 函数将调色板选择到设备上下文中,然后使用 RealizePalette 函数实现调色板。一旦实现了逻辑调色板,调色板中的颜色就可用。
-
应用程序应该限制其逻辑调色板的大小,使其颜色项数量足以表示所需的颜色即可(不要过多)。应用程序不能创建大于最大调色板大小(与设备相关的值)的逻辑调色板。应用程序可以使用 GetDeviceCaps 函数查询 SIZEPALETTE 值来获取最大大小。
-
尽管应用程序可以为逻辑调色板中的给定颜色项指定任何颜色值,但并非所有颜色都可以由给定设备生成。系统没有提供一种方法来发现支持哪些颜色,但是应用程序可以通过查询设备的颜色分辨率来发现这些颜色的总数。颜色分辨率(以每像素的颜色位为单位)等于 GetDeviceCaps 函数返回的 COLORRES 值。颜色分辨率为 18 的设备有 262144 种可能的颜色。如果应用程序请求的颜色是不支持的,系统会选择一个适当的近似值。
-
一旦创建了逻辑调色板,应用程序就可以通过使用 SetPaletteEntries 函数来更改调色板中的颜色。如果选择并实现了逻辑调色板,则更改调色板不会立即影响所显示的颜色。应用程序必须使用 UnrealizeObject 和 RealizePalette 函数来更新颜色。如果应用程序将逻辑调色板选择到多个设备上下文中,则对逻辑调色板的更改将影响为其选择的所有设备上下文中。
-
应用程序可以通过使用 ResizePalette 函数来更改逻辑调色板中的颜色项数量。如果应用程序减小了大小,则其余条目保持不变。如果应用程序扩展大小,则系统将每个新颜色项的颜色设置为黑色 (0,0,0) ,并将标志设置为 0 。
-
应用程序可以通过使用 GetPaletteEntries 函数来查询给定逻辑调色板中颜色项的颜色和标志值。通过使用 GetNearestPaletteIndex 函数,应用程序可以查询给定逻辑调色板中与指定颜色值最接近的颜色项的索引。
-
当应用程序不再需要逻辑调色板时,可以使用 DeleteObject 函数删除它。在删除调色板之前,应用程序必须确保不再将逻辑调色板选择到设备上下文中。
4.1.2.3 调色板动画
-
调色板动画是一种通过快速改变调色板中所选颜色项的颜色来模拟运动的技术。应用程序可以通过创建包含“保留”项的逻辑调色板,然后使用 AnimatePalette 函数更改这些保留项中的颜色来执行调色板动画。
-
应用程序通过将 PALETTEENTRY 结构的 peFlags 成员设置为 PC_RESERVED 标志,在逻辑调色板中创建保留项。一旦选择并实现了这个逻辑调色板,应用程序就可以调用 AnimatePalette 函数来更改一个或多个保留项。如果给定的调色板与激活窗口相关联,系统将立即更新屏幕上的颜色。
4.1.2.4 系统调色板
-
系统为每个使用调色板的设备维护一个系统调色板。系统调色板包含设备当前可以显示或绘制的所有颜色的颜色值。除了查看系统调色板的内容外,应用程序不能直接访问系统调色板。系统完全控制系统选项板,并且只允许通过使用逻辑选项板进行访问系统调色板。
-
应用程序可以通过使用 GetSystemPaletteEntries 函数查看系统调色板的内容。颜色项总数总是等于 GetDeviceCaps 函数为 SIZEPALETTE 值返回的数字。
-
尽管应用程序不能直接更改系统调色板中的颜色,但在实现逻辑调色板时,可能会导致颜色更改。为了实现逻辑调色板,系统检查每个请求的颜色,并尝试在系统调色板中找到包含精确匹配的颜色项。如果系统找到匹配的颜色,它将逻辑调色板索引映射到相应的系统调色板索引。如果系统没有找到完全匹配的颜色,它会在映射索引之前将请求的颜色复制到未使用的系统调色板颜色项。如果所有系统调色板颜色项都在使用中,则系统将逻辑调色板索引映射到颜色与请求颜色最接近的系统调色板颜色项。
-
通过在创建逻辑调色板时将 PALETTEENTRY 结构的 peFlags 成员设置为选定的值,应用程序可以修改索引映射的方式。
-
过在SelectPalette函数中分别为bForceBackground参数指定TRUE或FALSE,调色板可以被实现为背景调色板或前景调色板。系统中一次只能有一个前景调色板。如果窗口是当前激活窗口或当前激活窗口的派生窗口,则可以实现前景调色板。否则,无论bForceBackground参数的值如何,调色板都将被实现为背景调色板。前景调色板的关键属性是,当实现时,它可以覆盖系统调色板中的所有项(静态项除外)。在实现前景调色板之前,系统通过将系统调色板中所有非静态的项标记为未使用来完成此操作,从而消除所有已使用的项。对于背景调色板实现,系统调色板上不进行预处理。前景调色板设置所有可能的非静态颜色。背景调色板可以只设置仍然开放的内容,并以先到先得的方式优先考虑。通常,应用程序为实现自己的独立调色板的子窗口使用背景调色板。这有助于最大限度地减少发生在系统选项板上的更改数量。
-
未使用的系统调色板颜色项是未保留且不包含静态颜色的任何项。保留项用 PC_RESERVED 值显式标记。这些颜色项是在应用程序实现调色板动画的逻辑调色板时创建的。静态颜色项由系统创建,并与默认调色板中的颜色相对应。 GetDeviceCaps 函数可用于查询 NUMRESERVED 值,该值指定为静态颜色保留的系统调色板颜色项的数量。
-
由于系统调色板的颜色项数量有限,选择和实现给定设备的逻辑调色板可能会影响与同一设备的其他逻辑调色板关联的颜色。当这些颜色变化出现在显示器上时,它们尤其引人注目。应用程序可以通过在每次使用之前重置调色板来确保为其当前选择的逻辑调色板使用合理的颜色。应用程序通过调用 UnrealizeObject 和 RealizePalette 函数来重置调色板。使用这些函数可以使系统将逻辑调色板中的颜色重新映射为系统调色板中的合理颜色。
4.1.2.5 系统调色板和静态颜色
-
通常,系统为静态颜色保留的系统调色板项不能更改。应用程序可以通过使用 SetSystemPaletteUse 函数来覆盖此默认行为,以减少静态颜色项的数量,从而增加未使用的系统调色板项的数量。然而,因为改变静态颜色会对显示器上的所有窗口产生直接和显著的影响,应用程序不应该调用 SetSystemPaletteUse ,除非它有一个最大化的窗口和输入焦点。
-
当应用程序使用 SYSPAL_NOSTATIC 值调用 SetSystemPaletteUse 时,系统将释放除两个保留项外的所有保留项,允许这些项在应用程序随后实现其逻辑调色板时接收新的颜色值。其余两个静态颜色项保留并设置为白色和黑色。应用程序可以通过调用带有 SYSPAL_STATIC 值的 SetSystemPaletteUse 来恢复保留的颜色项。可以通过使用 GetSystemPaletteUse 函数来发现当前系统调色板的使用情况。
-
在将系统调色板的使用设置为 SYSPAL_NOSTATIC 之后,应用程序必须立即实现其逻辑调色板,调用 GetSysColor 函数保存当前系统颜色设置,调用 SetSysColors 函数将系统颜色设置为使用黑色和白色的合理值,最后将 WM_SYSCOLORCHANGE 消息发送给其他顶层窗口,以允许它们使用新的系统颜色重新绘制。当使用黑色和白色设置系统颜色时,应用程序应确保相邻或重叠的项目(如窗口框架和边框)分别设置为黑色和白色。
-
在应用程序失去输入焦点、关闭窗口或终止之前,它必须立即使用 SYSPAL_STATIC 值调用 SetSystemPaletteUse ,实现其逻辑调色板,将系统颜色恢复到之前的值,并发送 WM_SYSCOLORCHANGE 消息。系统发送 WM_PAINT 消息到任何受系统颜色变化影响的窗口。使用现有系统颜色的画笔的应用程序应该删除这些画笔,并使用新的系统颜色重新创建它们。
4.1.2.6 调色板消息
-
对显示设备的系统调色板的更改可能会对桌面窗口中使用的颜色产生严重的、有时是不希望看到的影响。为了尽量减少这些更改的影响,系统提供了一组消息,帮助应用程序管理其逻辑调色板,同时确保激活窗口中的颜色尽可能接近预期的颜色。
-
在激活窗口之前,系统发送一个 WM_QUERYNEWPALETTE 消息到顶层或重叠的窗口。此消息使应用程序有机会选择并实现其逻辑调色板,以便为其逻辑调色板接收最佳的颜色映射。当应用程序接收到消息时,它应该使用 SelectPalette 、 UnrealizeObject 和 RealizePalette 函数来选择和实现逻辑调色板。这样做将引导系统更新系统调色板中的颜色,以便其颜色与逻辑调色板中的尽可能多的颜色匹配。
-
当应用程序由于实现其逻辑调色板而导致系统调色板发生更改时,系统将向所有顶级窗口和重叠窗口发送 WM_PALETTECHANGED 消息。此消息使应用程序有机会更新其窗口客户端区域中的颜色,用更接近预期颜色的颜色替换已更改的颜色。接收到 WM_PALETTECHANGED 消息的应用程序应该使用 UnrealizeObject 和 RealizePalette 来重置与所有非激活窗口关联的逻辑调色板,然后使用 UpdateColors 函数更新每个非激活窗口的客户端区域的颜色。这种技术不能保证最大数量的精确颜色匹配;但是,它确保逻辑调色板中的颜色映射到系统调色板中的合理颜色。(为了避免创建无限循环,应用程序永远不应该实现句柄与 WM_PALETTECHANGED 消息的 wParam 参数传递的句柄相同的窗口的调色板。)
-
UpdateColors 函数更新非激活窗口的客户端区域的速度通常比重新绘制该区域快。但是,由于 UpdateColors 在系统调色板更改之前基于每个像素的颜色执行颜色转换,因此每次调用此函数都会导致一些颜色准确性的损失。这意味着当窗口变为激活状态时, UpdateColors 不能用于更新颜色。在这种情况下,应用程序应该重新绘制客户端区域。
-
当对逻辑调色板进行更改时,系统可能发送 WM_QUERYNEWPALETTE 消息。同样,当系统调色板即将改变时,系统可能会发送 WM_PALETTEISCHANGING 消息给所有顶层和重叠的窗口。
4.1.2.7 半色调调色板和颜色调整
-
当设备上下文的拉伸模式设置为 HALFTONE 时,将使用半色调调色板。应用程序通过使用 CreateHalftonePalette 函数创建半色调调色板。在调用 StretchBlt 或 StretchDIBits 函数之前,应用程序必须在设备上下文中选择并实现这个调色板。
-
当应用程序调用 StretchBlt 和 StretchDIBits 函数并且设备上下文的拉伸模式设置为 HALFTONE 时,系统自动调整源位图的输入颜色。这些颜色调整会影响图像的某些属性,例如对比度和亮度。应用程序可以使用 SetColorAdjustment 函数设置颜色调整值。应用程序可以通过使用 GetColorAdjustment 函数来查询指定设备上下文的颜色调整值。
4.2 使用颜色
4.2.1 枚举颜色
- 有关详细信息,请参阅使用颜色。
4.2.2 创建彩色笔和画刷
- 有关详细信息,请参阅创建彩色笔和画刷。
4.3 颜色参考
4.3.1 颜色函数
- 有关详细信息,请参阅颜色函数。
4.3.2 颜色结构体
- 有关详细信息,请参阅颜色结构体。
4.3.3 颜色宏
- 有关详细信息,请参阅颜色宏。
4.3.4 颜色消息
- 有关详细信息,请参阅颜色消息。