CColor - RGB 和 HLS 组合在一个类中






4.90/5 (29投票s)
一个提供 RGB 和 HLS 空间中简单颜色操作的类
引言
CColor 类源于在 HLS 模型中操作颜色的需求,这意味着我需要直接更改亮度或饱和度等属性的能力。HLS 模型使得在任意颜色之间绘制颜色渐变变得非常容易。也许 Windows 2000 会支持 HLS(或类似的 HSB)颜色模型,但我不想等到它发布。另一方面,我的代码也应该能在 NT 4.0 和 Win95/98 下运行。CColor 类封装了广为人知的 COLORREF 类型,并用 HLS 颜色模型对其进行了扩展。CColor 对象代表一个颜色,其 RGB 和 HLS 属性可以直接读取和操作。这使得 COLORREF 类型及其相关宏变得多余。
另一个我能在 Win32 API 中错过的便捷功能是命名颜色:常用的颜色可以用名称(而不是 RGB 值)来表示。如果您只使用少量颜色,例如用于强调文本的某些部分,使用命名颜色可以使代码更易于理解(在我看来)。据我所知,X11 自那时起就支持命名颜色,尽管当时可能是为了最优地利用有限的硬件调色板。在 Internet Explorer 的 HTML 文档中,我再次发现了命名颜色,并决定将它们集成到 CColor 类中。
CColor 支持用户友好的文本格式的序列化,这对于注册表或数据库特别有用。
示例应用程序演示了 CColor 类的用法。在上部区域,可以控制绘制颜色圆的参数。下部区域显示了所有命名颜色。颜色圆和命名颜色的工具提示显示颜色名称和 RGB 值。该示例应用程序还使用/演示了一些 MFC 工具提示处理技巧。整个机制通过虚函数 OnToolHitTest 实现。请观看并欣赏(或惊叹 ;-)。
示例:使用 CColor 绘制颜色渐变
void DrawGradient(CDC& dc, int x, int y,
CColor c1, CColor c2, int width, int height)
{
ASSERT(width > 0);
float dh = (c2.GetHue() - c1.GetHue()) / width;
float dl = (c2.GetLuminance() - c1.GetLuminance()) / width;
float ds = (c2.GetSaturation() - c1.GetSaturation()) / width;
for (int i = 0; i < width; ++i)
{
CPen pen(PS_SOLID, 1, c1);
CPen* pOld = dc.SelectObject(&pen);
dc.MoveTo(x + i, y);
dc.LineTo(x + i, y + height);
dc.SelectObject(pOld);
c1.SetHue(c1.GetHue() + dh);
c1.SetLuminance(c1.GetLuminance() + dl);
c1.SetSaturation(c1.GetSaturation() + ds);
}
}
版权所有 © 1999, Christian Rodemeyer
CColor 方法概述
CColor 类封装了 GDI 颜色值(COLORREF),并添加了一些方便的功能:直接操作 RGB 和 HSL 属性,转换为用于存储(注册表、数据库)的字符串值,以及用户友好的颜色名称。通过用户定义的构造函数和转换,可以在需要 COLORREF 值的地方使用 CColor 对象。
红色、绿色和蓝色分量可以单独访问。这比使用 RGB、GetRValue、GetBValue 和 GetGValue 等宏有所改进。同样,HSL 颜色模型(色相、亮度、饱和度)的属性也可以单独读取和操作。通过这种方式,可以非常容易地绘制 Windows98 应用程序标题栏或“选择颜色”对话框等颜色渐变。MSDN 库提供了一篇题为“HLS 颜色空间”的文章,其中描述了 HLS 颜色模型。
原则上,颜色可以作为 DWORD 数字存储在注册表或数据库中,但以这种形式通过 regedit 类工具或 SQL 进行操作会不必要地复杂。但更聪明的方法是将颜色以十六进制格式 RRGGBB 存储为文本。这种文本在最坏的情况下,可以由一些有经验的用户或系统管理员手动操作。要获取和设置颜色的文本表示,您可以使用方便的 GetString 和 SetString 方法。您可以使用静态方法 FromString 从字符串构建 CColor 对象。
在 X11 下,您早就可以使用命名颜色了。HTML(以及 Internet Explorer)也支持它们。对于 Internet Explorer 支持的每种命名颜色,都定义了常量和字符串。使用命名颜色可以使代码更具可读性,因为“chocolate”常量比表达式“RGB(0xD2, 0x69, 0x1E)”更容易理解。颜色的名称也可以作为一个字符串数据类型来获取。它可以作为程序和用户之间通信的手段。
注意:CColor 类不支持调色板,因此在使用超过 256 色(颜色深度大于等于 15/16 位)的窗口时,其应用效果最佳。
方法概述
CColor | 兼容 COLORREF 的构造函数 |
operator COLORREF | 兼容 COLORREF 的转换运算符 |
RGB | |
SetRed | 设置颜色的红色分量(0 - 255) |
SetGreen | 设置颜色的绿色分量(0 - 255) |
SetBlue | 设置颜色的蓝色分量(0 - 255) |
SetRGB | 一次性设置颜色的红色、绿色和蓝色分量 |
GetRed | 获取颜色的红色分量(0 - 255) |
GetGreen | 获取颜色的绿色分量(0 - 255) |
GetBlue | 获取颜色的蓝色分量(0 - 255) |
HSL | |
SetHue | 设置色相(0.0 - 360.0,色圆上的角度) |
SetLuminance | 设置亮度(0.0 - 1.0) |
SetSaturation | 设置饱和度(0.0 - 1.0) |
SetHLS | 一次性设置色相、亮度和饱和度 |
GetHue | 获取色相(0.0 - 360.0,色圆上的角度) |
GetLuminance | 获取亮度(0.0 - 1.0) |
GetSaturation | 获取颜色饱和度(范围:0.0 - 1.0) |
字符串 | |
SetString | 通过从十六进制格式 RRGGBB 的字符串中提取来设置颜色 |
GetString | 获取一个描述颜色的字符串,该字符串以十六进制格式 RRGGBB 表示 |
命名颜色 | |
GetName | 获取颜色的用户友好名称 |
静态 | |
GetNameFromIndex | 获取与 ENamedColorIndex 值对应的名称 |
GetColorFromIndex | 获取一个 CColor 对象,该对象已使用 ENamedColorIndex 值表示的颜色进行初始化 |
GetNumNames | 获取命名颜色的数量 |
FromString | 从 RRGGBB 字符串构造 CColor 对象(参见 SetString/GetString) |
常量
CColor::ENamedColor
定义了 140 种颜色的名称。这些名称与 HTML 中使用的名称相同,名称和相应的颜色值是从 Internet Explorer 文档(MSDN 1999 年 1 月:“Platform SDK/Internet/DHTML/Additional References/Color Table”)复制的。由于枚举的元素会自动转换为整数,而 COLORREF 只是整数的 typedef,因此 ENamedColor 值可以用在任何需要 COLORREF 值或 CColor 对象的地方。例如:
[...]
CClientDC dc(this)
dc.SetTextColor(CColor::blueviolet);
[...]
CToolTipCtrl* pToolTip = AfxGetThreadState()->m_pToolTip;
pToolTip->SetTipTextColor(CColor::gold);
以下颜色表从 Internet Explorer 文档复制并稍作修改(更正了“fuchia”错误并删除了颜色值)
aliceblue | antiquewhite | aqua | aquamarine |
azure | beige | bisque | black |
blanchedalmond | 蓝色 | blueviolet | brown |
burlywood | cadetblue | chartreuse | chocolate |
coral | cornflower | cornsilk | crimson |
cyan | darkblue | darkcyan | darkgoldenrod |
darkgray | darkgreen | darkkhaki | darkmagenta |
darkolivegreen | darkorange | darkorchid | darkred |
darksalmon | darkseagreen | darkslateblue | darkslategray |
darkturquoise | darkviolet | deeppink | deepskyblue |
dimgray | dodgerblue | firebrick | floralwhite |
forestgreen | fuchsia | gainsboro | ghostwhite |
gold | goldenrod | gray | green |
greenyellow | honeydew | hotpink | indianred |
indigo | ivory | khaki | lavender |
lavenderblush | lawngreen | lemonchiffon | lightblue |
lightcoral | lightcyan | lightgoldenrodyellow | lightgreen |
lightgrey | lightpink | lightsalmon | lightseagreen |
lightskyblue | lightslategray | lightsteelblue | lightyellow |
lime | limegreen | linen | magenta |
maroon | mediumaquamarine | mediumblue | mediumorchid |
mediumpurple | mediumseagreen | mediumslateblue | mediumspringgreen |
mediumturquoise | mediumvioletred | midnightblue | mintcream |
mistyrose | moccasin | navajowhite | navy |
oldlace | olive | olivedrab | 橙色 |
orangered | orchid | palegoldenrod | palegreen |
paleturquoise | palevioletred | papayawhip | peachpuff |
peru | pink | plum | powderblue |
purple | red | rosybrown | royalblue |
saddlebrown | salmon | sandybrown | seagreen |
seashell | sienna | silver | skyblue |
slateblue | slategray | snow | springgreen |
steelblue | tan | teal | thistle |
tomato | turquoise | violet | wheat |
white | whitesmoke | 黄色 | yellowgreen |
[方法概述]
CColor::ENamedColorIndex
在某些应用场景下,通过颜色索引获取颜色名称可能很有用。这就是 ENamedColorIndex 枚举存在的意义。名称是从 ENamedColor 派生的:在其前面加上前缀“i_”。因此,颜色“snow”的索引是“i_snow”。
[方法概述]
CColor::CColor
CColor(COLORREF cr = black)
构造 CColor 类的对象,并用传入的颜色 cr 进行初始化。默认参数的使用一步实现了默认构造函数和从 COLORREF 类型到 CColor 类型的转换构造函数。因此,以下代码是合法的,尽管没有定义特殊的赋值运算符:
CColor black; // initialized to black by default
CColor c1(RGB(255, 0, 0)); // initialized to red
CColor c2(CColor::seagreen); // CColor::ENamedColor is COLORREF compatible
COLORREF r = RGB(200, 50, 200);
c1 = r; // legal, implicit call of CColor::CColor(r)
c2 = RGB(100, 150, 200); // ditto, evaluates to CColor::CColor(RGB(100, 150, 250));
[方法概述]
operator COLORREF
operator COLORREF() const
实现从 CColor 到 COLORREF 的类型转换。这样,就可以在任何需要 COLORREF 的地方使用 CColor 对象。因此,以下代码是合法的:
CColor color(CColor::yellow);
[...]
COLORREF cr = color; // legal, calls implicitly CColor::operator COLORREF()
注意:期望非 const COLORREF& 引用(COLORREF&)的函数会修改返回的临时 COLORREF 值,而不是原始的 CColor 对象!
[方法概述]
SetRed
void SetRed(int red)
设置颜色的红色分量。值必须在 0 到 255 的范围内。
[方法概述]
SetGreen
void SetGreen(int green)
设置颜色的绿色分量。值必须在 0 到 255 的范围内。
[方法概述]
SetBlue
void SetBlue(int blue)
设置颜色的蓝色分量。值必须在 0 到 255 的范围内。
[方法概述]
SetRGB
void SetRGB(int red, int green, int blue)
一步组合了 SetRed、SetGreen 和 SetBlue 方法。
[方法概述]
GetRed
int GetRed() const
获取颜色的红色分量。返回值在 0 到 255 的范围内。
[方法概述]
GetGreen
int GetGreen() const
获取颜色的绿色分量。返回值在 0 到 255 的范围内。
[方法概述]
GetBlue
int GetBlue() const
获取颜色的蓝色分量。返回值在 0 到 255 的范围内。
[方法概述]
SetHue
void SetHue(float hue)
设置色相。该参数被解释为色圆上的角度(0.0 - 360.0 度)。红色位于 0 度,绿色位于 120 度,蓝色位于 240 度。
[方法概述]
SetLuminance
void SetLuminance(float luminance)
设置颜色的亮度。参数是标准化的,其值必须在 0.0(黑色)和 1.0(白色)之间。
[方法概述]
SetSaturation
void SetSaturation(float saturation)
设置颜色的饱和度。参数是标准化的,其值必须在 0.0(灰色,无任何颜色)和 1.0(纯色)之间。
[方法概述]
SetHLS
void SetHLS(float hue, float luminance, float saturation)
一步组合了 SetHue、SetLuminance 和 SetSaturation 方法。
[方法概述]
GetHue
float GetHue() const
获取色相。返回值被解释为色圆上的角度(0.0 - 360.0 度)。红色位于 0 度,绿色位于 120 度,蓝色位于 240 度。
[方法概述]
GetLuminance
float GetLuminance() const
获取颜色的亮度。返回值是标准化的,其值在 0.0(黑色)和 1.0(白色)之间。
[方法概述]
GetSaturation
float GetSaturation() const
获取颜色的饱和度。返回值是标准化的,其值在 0.0(灰色,无任何颜色)和 1.0(纯色)之间。
[方法概述]
GetString
CString GetString() const
以十六进制格式“RRGGBB”将 RGB 颜色值作为文本获取。示例:红色返回为“FF0000”,绿色返回为“00FF00”,蓝色返回为“0000FF”。
[方法概述]
SetString
bool SetString(LPCTSTR pcColor)
使用从传入的字符串 pcColor 扫描的 RGB 颜色值初始化对象。它应该包含十六进制格式 RRGGBB 的字符串。如果无法从字符串中扫描到有效颜色,该方法将返回 false,否则返回 true。示例:“FF0000”将颜色设置为红色,“00FF00”设置为绿色,“0000FF”设置为蓝色。
[方法概述]
GetName
CString GetName() const
获取颜色的用户友好名称。当颜色没有已知名称时,将返回 HTML 格式为“#RRGGBB”的字符串。
[方法概述]
GetNumNames
static int GetNumNames()
获取命名颜色的数量(ENamedColor 和 ENamedColorIndex 中枚举的值的数量)。
[方法概述]
GetNameFromIndex
static LPCSTR GetNameFromIndex(int i)
获取索引 i 的用户友好名称。
[方法概述]
GetColorFromIndex
static CColor GetColorFromIndex(int i)
获取索引 i 的颜色。
[方法概述]
FromString
static CColor FromString(LPCSTR pcColor)
从字符串 pcColor 构造 CColor 对象。该字符串必须是 RRGGBB 格式,其中 RR、GG、BB 是两位十六进制值。