23

Is there an easy way to blend two System.Drawing.Color values? Or do I have to write my own method to take in two colors and combine them?

If I do, how might one go about that?

Drew Noakes
  • 300,895
  • 165
  • 679
  • 742
Matt
  • 25,943
  • 66
  • 198
  • 303
  • 2
    Combine them how? If you mix red paint with blue paint you get purple paint, but if you look at a blue ball through red glass, the ball looks black, not purple. What kind of blending did you have in mind? – Eric Lippert Sep 15 '10 at 23:35
  • 4
    @Eric Lippert: I think it was pretty clear to everyone that he meant alpha blending. Any other type of blending is much rarer and more specialised, so he would have mentioned it explicitly. – Timwi Sep 16 '10 at 00:10
  • 8
    @Timwi: It was not clear to me, so it was not clear to everyone. Perhaps it was clear to everyone but me. – Eric Lippert Sep 16 '10 at 06:00
  • I am not entirely sure what you're trying to do with blending, but you could look into alpha blending http://en.wikipedia.org/wiki/Alpha_compositing. – Aurojit Panda Sep 15 '10 at 22:30

4 Answers4

45

I wrote a utility method for exactly this purpose. :)

/// <summary>Blends the specified colors together.</summary>
/// <param name="color">Color to blend onto the background color.</param>
/// <param name="backColor">Color to blend the other color onto.</param>
/// <param name="amount">How much of <paramref name="color"/> to keep,
/// “on top of” <paramref name="backColor"/>.</param>
/// <returns>The blended colors.</returns>
public static Color Blend(this Color color, Color backColor, double amount)
{
    byte r = (byte) (color.R * amount + backColor.R * (1 - amount));
    byte g = (byte) (color.G * amount + backColor.G * (1 - amount));
    byte b = (byte) (color.B * amount + backColor.B * (1 - amount));
    return Color.FromRgb(r, g, b);
}
Timwi
  • 65,159
  • 33
  • 165
  • 230
  • 1
    This would be interesting as an operator overload so that you could write: `Color NewColor = Color1 + Color2;` An article that deals with this: http://msdn.microsoft.com/en-us/magazine/cc163737.aspx – JYelton Sep 15 '10 at 22:32
  • 1
    You could always add in a "this" just because extensions are fun. – Blam Sep 15 '10 at 22:35
  • 7
    Depending on the colors, linear blending can darken the resulting color. – MerickOWA Sep 15 '10 at 22:45
  • @Timwi: That's true -- an operator overload would have to use some default blending value. – JYelton Sep 15 '10 at 23:24
  • 2
    What's about the alpha value? – Oliver Feb 28 '12 at 09:50
  • ^ Alpha blending is a better method. That being said, nice extension method. – Phillip Schmidt Sep 13 '12 at 13:56
  • @Phillip Schmidt - This formula looks a lot like the original formula on wiki. I'm not good at reading these formulas, so I'm wondering: is there a difference? – Léon Pelletier Apr 08 '13 at 18:08
  • 4
    Nice one. I only think the 'amount' value works backwards in my opinion ;) when I read color.Blend(target, 0.9) I would expect barely any of the original color left – Dirk Boer Sep 29 '14 at 08:48
7

If you want to blend colours in a way that looks more natural to the human eye, you should consider working in a different colour space to RGB, such as L*a*b*, HSL, HSB.

There a great code project article on colour spaces with examples in C#.

You may like to work with L*a*b*, as it was designed to linearise the perception of color differences and should therefore produce elegant gradients.

Drew Noakes
  • 300,895
  • 165
  • 679
  • 742
0

I think its easier to blend an array of colors, in case you want to blend more then 2 Here is my function:

private Color colorBlend(List<Color> clrArr)
{   
    int r = 0;
    int g = 0;
    int b = 0;
    foreach(Color color in clrArr)
    {
        r += color.R;
        g += color.G;
        b += color.B;
    }
    r = r / clrArr.Count;
    g = g / clrArr.Count;
    b = b / clrArr.Count;
    return Color.FromArgb(r, g, b);
}

The array must be as a List of color Use :

List<Color> colorList = new List<Color>();
colorList.Add(Color.Red);
colorList.Add(Color.Blue);
picturebox.backColor = colorBlend(colorList);
Gazgoh
  • 1
0

To combine two colors by using alpha blending the following method can be taken:

private const decimal Divisor = byte.MaxValue;

public static Color AlphaBlend(this Color backColor, Color foreColor)
{
    var fa = foreColor.A / Divisor;
    var fr = foreColor.R / Divisor;
    var fg = foreColor.G / Divisor;
    var fb = foreColor.B / Divisor;

    var ba = backColor.A / Divisor;
    var br = backColor.R / Divisor;
    var bg = backColor.G / Divisor;
    var bb = backColor.B / Divisor;

    var a = fa + ba - fa * ba;

    if (a <= 0)
        return Color.Transparent;

    var r = (fa * (1 - ba) * fr + fa * ba * fa + (1 - fa) * ba * br) / a;
    var g = (fa * (1 - ba) * fg + fa * ba * fa + (1 - fa) * ba * bg) / a;
    var b = (fa * (1 - ba) * fb + fa * ba * fa + (1 - fa) * ba * bb) / a;

    return Color.FromArgb(
        (int)(a * byte.MaxValue),
        (int)(r * byte.MaxValue),
        (int)(g * byte.MaxValue),
        (int)(b * byte.MaxValue));
}
Oliver
  • 43,366
  • 8
  • 94
  • 151