关于c#:如何确定给定颜色的深色或浅色?

关于c#:如何确定给定颜色的深色或浅色?

How do I determine darker or lighter color variant of a given color?

给定系统或用户的任何色调的源颜色,我想使用一种简单的算法来计算出所选颜色的较浅或较深的变体。 类似于Windows Live Messenger上用于设置用户界面样式的效果。

使用.net 3.5的语言是C#。

回应评论:颜色格式为(Alpha)RGB。 值以字节或浮点数表示。

标记答案:就我使用的上下文(一些简单的UI效果)而言,我标记为接受的答案实际上是此上下文中最简单的。 但是,我也放弃了对更复杂和准确的答案的投票。 任何进行更高级的色彩操作并在将来找到该线程的人都应该检查一下。 谢谢。 :)


在XNA中,有一种Color.Lerp静态方法将其作为两种颜色之间的差异进行处理。

Lerp是两个浮点数之间的数学运算,它以两个浮点数之差的比率改变第一个浮点数的值。

这是将其扩展为float的扩展方法:

1
2
3
4
5
6
public static float Lerp( this float start, float end, float amount)
{
    float difference = end - start;
    float adjusted = difference * amount;
    return start + adjusted;
}

因此,使用RGB在两种颜色之间进行简单的lerp操作将是:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public static Color Lerp(this Color colour, Color to, float amount)
{
    // start colours as lerp-able floats
    float sr = colour.R, sg = colour.G, sb = colour.B;

    // end colours as lerp-able floats
    float er = to.R, eg = to.G, eb = to.B;

    // lerp the colours to get the difference
    byte r = (byte) sr.Lerp(er, amount),
         g = (byte) sg.Lerp(eg, amount),
         b = (byte) sb.Lerp(eb, amount);

    // return the new colour
    return Color.FromArgb(r, g, b);
}

应用此示例的示例如下:

1
2
3
4
5
6
7
8
// make red 50% lighter:
Color.Red.Lerp( Color.White, 0.5f );

// make red 75% darker:
Color.Red.Lerp( Color.Black, 0.75f );

// make white 10% bluer:
Color.White.Lerp( Color.Blue, 0.1f );

只需将RGB值乘以您要修改级别的数量即可。如果其中一种颜色已经达到最大值,则无法使其更亮(仍然使用HSV数学)。

这与使用HSV然后修改V所得到的结果完全相同,而数学运算要少得多。只要您不想开始失去饱和度,就可以得到与使用HSL然后修改L相同的结果。


HSV(色相/饱和度/亮度)也称为HSL(色相/饱和度/亮度)只是一种不同的颜色表示。

使用此表示法更容易调整亮度。因此,从RGB转换为HSV,加亮" V",然后转换回RGB。

下面是一些要转换的C代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
void RGBToHSV(unsigned char cr, unsigned char cg, unsigned char cb,double *ph,double *ps,double *pv)
{
double r,g,b;
double max, min, delta;

/* convert RGB to [0,1] */

r = (double)cr/255.0f;
g = (double)cg/255.0f;
b = (double)cb/255.0f;

max = MAXx(r,(MAXx(g,b)));
min = MINx(r,(MINx(g,b)));

pv[0] = max;

/* Calculate saturation */

if (max != 0.0)
    ps[0] = (max-min)/max;
else
    ps[0] = 0.0;

if (ps[0] == 0.0)
{
    ph[0] = 0.0f;   //UNDEFINED;
    return;
}
/* chromatic case: Saturation is not 0, so determine hue */
delta = max-min;

if (r==max)
{
    ph[0] = (g-b)/delta;
}
else if (g==max)
{
    ph[0] = 2.0 + (b-r)/delta;
}
else if (b==max)
{
    ph[0] = 4.0 + (r-g)/delta;
}
ph[0] = ph[0] * 60.0;
if (ph[0] < 0.0)
    ph[0] += 360.0;
}

void HSVToRGB(double h,double s,double v,unsigned char *pr,unsigned char *pg,unsigned char *pb)
{
int i;
double f, p, q, t;
double r,g,b;

if( s == 0 )
{
    // achromatic (grey)
    r = g = b = v;
}
else
{
    h /= 60;            // sector 0 to 5
    i = (int)floor( h );
    f = h - i;          // factorial part of h
    p = v * ( 1 - s );
    q = v * ( 1 - s * f );
    t = v * ( 1 - s * ( 1 - f ) );
    switch( i )
    {
    case 0:
        r = v;
        g = t;
        b = p;
    break;
    case 1:
        r = q;
        g = v;
        b = p;
    break;
    case 2:
        r = p;
        g = v;
        b = t;
    break;
    case 3:
        r = p;
        g = q;
        b = v;
    break;
    case 4:
        r = t;
        g = p;
        b = v;
    break;
    default:        // case 5:
        r = v;
        g = p;
        b = q;
    break;
    }
}
r*=255;
g*=255;
b*=255;

pr[0]=(unsigned char)r;
pg[0]=(unsigned char)g;
pb[0]=(unsigned char)b;
}

Rich Newman在他的博客中讨论了有关.NET System.Drawing.Color的HSL颜色,甚至提供了一个HSLColor类来为您完成所有工作。将您的System.Drawing.Color转换为HSLColor,针对光度添加/减去值,然后转换回System.Drawing.Color以在您的应用中使用。


您可以将颜色转换为HSL颜色空间,在此处进行处理,然后转换回您选择的颜色空间(最有可能是RGB)

较浅的颜色具有较高的L值,较深的颜色具有较低的L值。

这是相关的东西和所有方程式:

http://en.wikipedia.org/wiki/HSL_color_space

另一种方法是简单地用白色或黑色插入颜色。这也会使颜色略微降低饱和度,但计算起来更便宜。


我在System.Windows.Forms中使用了ControlPaint.Dark()和.Light()。


我猜您正在使用带字节值(0到255)的RGB,因为在任何地方都很常见。

为了更亮,请用白色的RGB平均RGB值。或者,要控制多少亮度,可以按一定比例混合。设f在0.0到1.0之间变化,然后:

1
2
3
Rnew = (1-f)*R + f*255
Gnew = (1-f)*G + f*255
Bnew = (1-f)*B + f*255

对于较暗的情况,请使用黑色的RGB-全为零,使数学运算更容易。

我省略了一些细节,例如将结果转换回字节,这可能是您想要的。


如果您使用的是RGB颜色,则可以将此颜色参数转换为HSL(色相,饱和度,亮度),修改亮度参数,然后转换回RGB。到处都是Google,您会发现很多有关如何进行这些颜色表示转换(从RGB到HSL,反之亦然)的代码示例。

这是我很快发现的:
http://bytes.com/forum/thread250450.html


该网站指出,您可以在BCL C#System.Windows.Forms命名空间中使用ControlPaint类。


转换为HSV或其他颜色空间的想法似乎不错,并且对于精确的颜色工作可能是必需的,但是对于普通目的,使用RGB工作的错误可能并不重要。同样,处理边界情况可能会很痛苦:RGB是一个立方体形的空间,而HSV不是。如果使用字节值,则空间之间可以具有多对一和一对多的映射。取决于应用程序,这可能是问题,也可能不是问题。青年汽车


在HSL / HSV中更好地完成颜色的任何变化。

一个好的测试是在RGB空间和HSL空间中的两个等效值之间进行插值。 HSL空间中的坡度看起来像是自然发展。在RGB空间中,它通常看起来非常不自然。 HSL比RGB更好地映射到我们的视觉色彩空间感知。


如果您的颜色是RGB格式(或者大概是CMYK),则可以使用相当粗糙的方法来增加颜色的每个成分的值。例如,在HTML中,颜色表示为三个两位数的十六进制数字。 #ff0000将为您提供明亮的红色,然后可以通过将G和B组件的值增加相同的量来淡化,例如#ff5555(提供较浅的红色)。大概对于色相,饱和度和亮度(HSL)颜色,您可以提高L分量,但是我不能肯定地说。我对这个色彩空间不太熟悉。

正如我所说,这种方法非常粗糙。从我对Live Messenger的记忆中,听起来好像您正在尝试进行渐变,可以非常轻松地在Windows Presentation Foundation(WPF,.NET 3.0的一部分)中应用渐变。 WPF支持许多不同类型的渐变笔刷,包括线性和径向渐变。

我强烈推荐Adam Nathan的书《 Windows Presentation Foundation Unleashed》作为WPF的详尽介绍。

高温超导


假设您获得的颜色为RGB,请首先将其转换为HSV(色相,饱和度,值)颜色空间。然后增加/减少该值以产生较浅/较深的颜色阴影。然后转换回RGB。


推荐阅读