简体   繁体   English

如何确定给定颜色的更深或更浅的颜色变体?

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

Given a source color of any hue by the system or user, I'd like a simple algorithm I can use to work out a lighter or darker variants of the selected color.给定系统或用户的任何色调的源颜色,我想要一个简单的算法,我可以使用它来计算出所选颜色的更浅或更深的变体。 Similar to effects used on Windows Live Messenger for styling the user interface.类似于在 Windows Live Messenger 上用于设置用户界面样式的效果。

Language is C# with .net 3.5.语言是带有 .net 3.5 的 C#。

Responding to comment: Color format is (Alpha)RGB.回应评论:颜色格式为(Alpha)RGB。 With values as bytes or floats.将值作为字节或浮点数。

Marking answer: For the context of my use (a few simple UI effects), the answer I'm marking as accepted is actually the most simple for this context.标记答案:对于我使用的上下文(一些简单的 UI 效果),我标记为已接受的答案实际上是此上下文中最简单的。 However, I've given up votes to the more complex and accurate answers too.但是,我也放弃了对更复杂和准确的答案的投票。 Anyone doing more advanced color operations and finding this thread in future should definitely check those out.任何进行更高级颜色操作并在将来找到此线程的人都应该检查一下。 Thanks SO.谢谢。 :) :)

In XNA there is the Color.Lerp static method that does this as the difference between two colours.XNA 中有Color.Lerp静态方法,它可以作为两种颜色之间的差异来执行此操作。

Lerp is a mathematical operation between two floats that changes the value of the first by a ratio of the difference between them. Lerp是两个浮点数之间的数学运算,它通过它们之间差值的比率改变第一个浮点数的值。

Here's an extension method to do it to a float :这是一个对float执行此操作的扩展方法:

public static float Lerp( this float start, float end, float amount)
{
    float difference = end - start;
    float adjusted = difference * amount;
    return start + adjusted;
}

So then a simple lerp operation between two colours using RGB would be:那么使用 RGB 的两种颜色之间的简单 lerp 操作将是:

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);
}

An example of applying this would be something like:应用它的一个例子是这样的:

// 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 );

Simply multiply the RGB values by the amount you want to modify the level by.只需将 RGB 值乘以您想要修改级别的数量。 If one of the colors is already at the max value, then you can't make it any brighter (using HSV math anyway.)如果其中一种颜色已经达到最大值,那么你就不能让它更亮(无论如何都要使用 HSV 数学。)

This gives the exact same result with a lot less math as switching to HSV and then modifying V. This gives the same result as switching to HSL and then modifying L, as long as you don't want to start losing saturation.这给出了与切换到 HSV 然后修改 V 完全相同的结果,但数学运算要少得多。 只要您不想开始失去饱和度,这与切换到 HSL 然后修改 L 的结果相同。

HSV ( Hue / Saturation / Value ) also called HSL ( Hue / Saturation / Lightness ) is just a different color representation. HSV(色相/饱和度/值)也称为HSL(色相/饱和度/亮度)只是一种不同的颜色表示。

Using this representation is it easier to adjust the brightness.使用这种表示可以更容易地调整亮度。 So convert from RGB to HSV, brighten the 'V', then convert back to RGB.因此,从 RGB 转换为 HSV,使“V”变亮,然后再转换回 RGB。

Below is some C code to convert下面是一些要转换的C代码

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 discusses HSL color with respect to .NET System.Drawing.Color on his blog and even provides an HSLColor class that does all the work for you. Rich Newman 在他的博客上讨论了关于 .NET System.Drawing.Color 的HSL 颜色,甚至提供了一个 HSLColor 类来为您完成所有工作。 Convert your System.Drawing.Color to an HSLColor, add/subtract values against the Luminosity, and convert back to System.Drawing.Color for use in your app.将您的 System.Drawing.Color 转换为 HSLColor,根据亮度添加/减去值,然后转换回 System.Drawing.Color 以在您的应用程序中使用。

You can convert your color into the HSL color-space, manipulate it there and convert back to your color-space of choice (most likely that's RGB)您可以将您的颜色转换为 HSL 颜色空间,在那里对其进行操作并转换回您选择的颜色空间(很可能是 RGB)

Lighter colors have a higher L-value, darker a lower.颜色越浅,L 值越高,颜色越深,L 值越低。

Here's the relevant stuff and all the equations:这是相关的东西和所有的方程式:

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

Another method is to simply interpolate your color with white or black.另一种方法是简单地用白色或黑色插入颜色。 This will also desaturate the color a bit but it's cheaper to calculate.这也会稍微降低颜色的饱和度,但计算起来更便宜。

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

I'm guessing you're using RGB with byte values (0 to 255) as that's very common everywhere.我猜你正在使用带有字节值(0 到 255)的 RGB,因为这在任何地方都很常见。

For brighter, average the RGB values with the RGB of white.为了更亮,用白色的 RGB 平均 RGB 值。 Or, to have some control over how much brightening, mix in them in some proportion.或者,为了控制增亮的程度,按一定比例混合它们。 Let f vary from 0.0 to 1.0, then:f从 0.0 变化到 1.0,然后:

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

For darker, use the RGB of black - which, being all zeros, makes the math easier.对于更暗的颜色,请使用黑色的 RGB - 它全为零,使数学更容易。

I leave out details such as converting the result back into bytes, which probably you'd want to do.我省略了一些细节,例如将结果转换回字节,这可能是您想要做的。

If you are using RGB colors I would transform this color paramaters to HSL (hue, saturation, lightness), modify the lightness parameter and then transform back to RGB.如果您使用的是 RGB 颜色,我会将这些颜色参数转换为HSL (色调、饱和度、亮度),修改亮度参数,然后再转换回 RGB。 Google around and you'll find a lot of code samples on how to do these color representation transformations (RGB to HSL and viceversa).谷歌一下,你会发现很多关于如何进行这些颜色表示转换(RGB 到 HSL,反之亦然)的代码示例。

This is what I quickly found: http://bytes.com/forum/thread250450.html这是我很快发现的: http : //bytes.com/forum/thread250450.html

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

Assuming you get the color as RGB, first convert it to HSV (hue, saturation, value) color space.假设您将颜色设为 RGB,首先将其转换为 HSV(色调、饱和度、值)颜色空间。 Then increase/decrease the value to produce lighter/darker shade of the color.然后增加/减少该值以产生更浅/更深的颜色阴影。 Then convert back to RGB.然后转换回RGB。

If your colours are in RGB format (or, presumably CMYK), you can use the fairly crude method of increasing the value of each component of the colour.如果您的颜色是 RGB 格式(或者,大概是 CMYK),您可以使用相当粗略的方法来增加颜色的每个分量的值。 Eg, in HTML colours are represented as three two-digit hex numbers.例如,在 HTML 中,颜色表示为三个两位的十六进制数字。 #ff0000 will give you a bright red, which can then be faded by increasing the values of the G and B componenets by the same amount, such as #ff5555 (gives a lighter red). #ff0000 会给你一个亮红色,然后可以通过将 G 和 B 组件的值增加相同的数量来淡化,例如#ff5555(给出更浅的红色)。 Presumably for Hue, Saturation and Lightness (HSL) colours, you can just raise the L component, but I can't say for certain;大概对于色相、饱和度和亮度 (HSL) 颜色,您可以只提高 L 分量,但我不能肯定; I'm less familiar with this colour space.我对这个色彩空间不太熟悉。

As I say, though, this method is quite crude.不过,正如我所说,这种方法非常粗糙。 From my memories of Live Messenger, it sounds like you're trying to do gradients, which can be applied really quite easily in Windows Presentation Foundation (WPF, part of .NET 3.0).根据我对 Live Messenger 的记忆,听起来您正在尝试进行渐变,这在 Windows Presentation Foundation(WPF,.NET 3.0 的一部分)中可以非常轻松地应用。 WPF supports many different types of gradient brush, including linear and radial gradients. WPF 支持许多不同类型的渐变画笔,包括线性渐变和径向渐变。

I can highly recommend Adam Nathan's book Windows Presentation Foundation Unleashed as a good and thorough introduction to WPF.我强烈推荐 Adam Nathan 的书Windows Presentation Foundation Unleashed作为对 WPF 的一个很好的全面介绍。

HTH HTH

Any variations in color are better done in HSL/HSV.在 HSL/HSV 中可以更好地完成颜色的任何变化。

A good test is to interpolate between two equivalent values in RGB space and HSL space.一个很好的测试是在 RGB 空间和 HSL 空间中的两个等效值之间进行插值。 The ramp in HSL space looks like a natural progression. HSL 空间的斜坡看起来是一个自然的过程。 In RGB space it typically looks quite unnatural.在 RGB 空间中,它通常看起来很不自然。 HSL maps to our visual color space perception much better than RGB. HSL 映射到我们的视觉色彩空间感知比 RGB 好得多。

The idea of converting to HSV or some other color space seems good, and may be necessary for precise color work, but for ordinary purposes the error of working in RGB may not be enough to matter.转换为 HSV 或其他一些颜色空间的想法似乎不错,并且对于精确的颜色工作可能是必要的,但对于普通目的,在 RGB 中工作的错误可能还不够重要。 Also, it can be a pain to deal with boundary cases: RGB is a cube-shaped space, while HSV is not.此外,处理边界情况可能会很痛苦:RGB 是一个立方体形状的空间,而 HSV 不是。 If working with byte values, you can have many-to-one and one-to-many mappings between the spaces.如果使用字节值,则可以在空间之间进行多对一和一对多映射。 This may or may not be a problem depending on the application.这可能是也可能不是问题,具体取决于应用程序。 YMMV青年会

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM