如何使用透明度混合颜色?

3
我希望能够混合两个或更多的Color对象。假设我有一个半透明的红色:

var red = Color.FromArgb(140, 255, 0, 0);

然后我想将一个半透明的绿色混合进去:

var green = Color.FromArgb(140, 0, 255, 0);

我找到的颜色混合代码片段通常会产生一种棕色的色调,但我真正想要的效果是像在(比如)Paint.Net中绘制一种颜色覆盖另一种颜色所得到的效果,从而产生更深的绿色:

enter image description here

我希望能够混合第三种颜色,比如半透明的蓝色:
var blue = Color.FromArgb(140, 0, 0, 255);
这次,我想得到这张图片中间看到的青绿色。

enter image description here

如果我尝试使用常规的代码片段,那么通常会得到灰色或棕色的结果。

顺便提一下,以下代码基本上实现了我想要的效果:

using (var bitmap = new Bitmap(300, 300))
{
    using (var g = Graphics.FromImage(bitmap))
    {
        var c1 = Color.FromArgb(alpha: 128, red: 255, green: 0, blue: 0);
        var c2 = Color.FromArgb(alpha: 200, red: 0, green: 255, blue: 0);
        var c3 = Color.FromArgb(alpha: 100, red: 0, green: 0, blue: 255);
        g.FillRectangle(new SolidBrush(c1), 100, 0, 100, 100);
        g.FillRectangle(new SolidBrush(c2), 125, 75, 100, 100);
        g.FillRectangle(new SolidBrush(c3), 75, 50, 100, 100);
    }
}

我猜这是代码版的我的Paint.Net步骤,将一个半透明的彩色矩形绘制在另一个上面。然而,我希望能够计算最终混合的颜色,并在一次调用中使用它,而不是调用该方法三次以实现混合效果。
最后,这是我之前提到的那种颜色混合代码片段的示例,当我将它们用于我的颜色时,通常会产生棕色的阴影:-
    private Color Blend(Color c1, Color c2)
    {
        var aOut = c1.A + (c1.A * (255 - c1.A) / 255);
        var rOut = (c1.R * c1.A + c2.R * c2.A * (255 - c1.A) / 255) / aOut;
        var gOut = (c1.G * c1.A + c2.G * c2.A * (255 - c1.A) / 255) / aOut;
        var bOut = (c1.B * c1.A + c2.B * c2.A * (255 - c1.A) / 255) / aOut;

        return Color.FromArgb(aOut, rOut, gOut, bOut);
    }

1
你说得很对:GDI绘图的alpha混合模式是有限的。要获得更多模式,比如Photoshop中的图层混合模式,你需要自己编写一个或多个程序。数学计算可以在这里找到(https://dev59.com/om025IYBdhLWcg3wl3Am)。我用C#为所有模式编写了相关代码,也许我应该把它发布到Git上,但目前我没有时间。另一方面,如果你想完全控制覆盖区域,可能需要将图形分解并单独填充。 - undefined
@TaW 非常感谢,我并没有完全理解你在 C# 代码片段中的四个参数,但通过一些尝试和错误,我能够简化它并让它正常工作(至少满足了我的需求)。请见下方。 - undefined
1个回答

2

感谢@TaW的早期评论(否则我永远不会解决这个问题!),我能够编写一种方法以Paint.net、Paintshop等软件的风格混合两种颜色:

var r = Color.FromArgb(140, 255, 0, 0);
var g = Color.FromArgb(140, 0, 255, 0);
var b = Color.FromArgb(140, 0, 0, 255);

// How to use:
var rg= AlphaComposite(r, g);
var rb= AlphaComposite(r, b);
var gb= AlphaComposite(g, b);
var rgb= AlphaComposite(AlphaComposite(r, g), b);

...

// A cache of all opacity values (0-255) scaled down to 0-1 for performance
private readonly float[] _opacities = Enumerable.Range(0, 256)
                                      .Select(o => o / 255f)
                                      .ToArray();

private Color AlphaComposite(Color c1, Color c2)
{
    var opa1 = _opacities[c1.A];
    var opa2 = _opacities[c2.A];
    var ar = opa1 + opa2 - (opa1 * opa2);
    var asr = opa2 / ar;
    var a1 = 1 - asr;
    var a2 = asr * (1 - opa1);
    var ab = asr * opa1;
    var r = (byte)(c1.R * a1 + c2.R * a2 + c2.R * ab);
    var g = (byte)(c1.G * a1 + c2.G * a2 + c2.G * ab);
    var b = (byte)(c1.B * a1 + c2.B * a2 + c2.B * ab);
    return Color.FromArgb((byte)(ar * 255), r, g, b);
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接