使用混合模式颜色在另一个图像上绘制图像

时间:2012-03-17 12:20:29

标签: c# image-processing gdi+

在Photoshop中,您可以选择“颜色”(从底部开始的第二个)将混合模式设置为下一个较低层:

Layer blending mode selection photoshop

如果图像顶部只有一个渐变,结果可能如下所示:

Color blending example

我在某处找到的颜色混合模式的描述是:

颜色将下层的色调和饱和度更改为上层的色调和饱和度,但仅留下亮度。

到目前为止我的代码是:

using(var g = Graphics.FromImage(canvas))
{
    // draw the lower image
    g.DrawImage(lowerImg, left, top);

    // creating a gradient and draw on top
    using (Brush brush = new LinearGradientBrush(new Rectangle(0, 0, canvasWidth, canvasHeight), Color.Violet, Color.Red, 20))
    {
        g.FillRectangle(brush, 0, 0, canvasWidth, canvasHeight);
    }
}

但是 - 当然 - 只是在较低的图像上画画。

所以问题是:

如何使用Photoshop中提供的混合模式“color”在另一个图像上绘制图像?

修改

为了让我更清楚我想要实现的目标:

enter image description here

如果有人想使用这些图片进行测试:

enter image description here enter image description here

3 个答案:

答案 0 :(得分:6)

这是我的解决方案。我使用Rich Newman的HSLColor类来转换RGB和HSL值。

using (Bitmap lower = new Bitmap("lower.png"))
using (Bitmap upper = new Bitmap("upper.png"))
using (Bitmap output = new Bitmap(lower.Width, lower.Height))
{
    int width = lower.Width;
    int height = lower.Height;
    var rect = new Rectangle(0, 0, width, height);

    BitmapData lowerData = lower.LockBits(rect, ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);
    BitmapData upperData = upper.LockBits(rect, ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);
    BitmapData outputData = output.LockBits(rect, ImageLockMode.WriteOnly, PixelFormat.Format24bppRgb);

    unsafe
    {
        byte* lowerPointer = (byte*) lowerData.Scan0;
        byte* upperPointer = (byte*) upperData.Scan0;
        byte* outputPointer = (byte*) outputData.Scan0;

        for (int i = 0; i < height; i++)
        {
            for (int j = 0; j < width; j++)
            {
                HSLColor lowerColor = new HSLColor(lowerPointer[2], lowerPointer[1], lowerPointer[0]);
                HSLColor upperColor = new HSLColor(upperPointer[2], upperPointer[1], upperPointer[0]);
                upperColor.Luminosity = lowerColor.Luminosity;
                Color outputColor = (Color) upperColor;

                outputPointer[0] = outputColor.B;
                outputPointer[1] = outputColor.G;
                outputPointer[2] = outputColor.R;

                // Moving the pointers by 3 bytes per pixel
                lowerPointer += 3;
                upperPointer += 3;
                outputPointer += 3;
            }

            // Moving the pointers to the next pixel row
            lowerPointer += lowerData.Stride - (width * 3);
            upperPointer += upperData.Stride - (width * 3);
            outputPointer += outputData.Stride - (width * 3);
        }
    }

    lower.UnlockBits(lowerData);
    upper.UnlockBits(upperData);
    output.UnlockBits(outputData);

    // Drawing the output image
}

答案 1 :(得分:0)

您必须重新构建代码,以便在临时位图上绘制渐变,从临时位图和画布中读取每个像素,并将合成像素写入画布。您应该能够找到RGB和HSL颜色之间的代码转换,一旦您可以这样做,将画布中像素的色调和饱和度设置为临时位图中的值是微不足道的(尽管如果您想使用它会有点难度) alpha值)。

答案 2 :(得分:0)

这是完整性所接受答案的安全(且速度较慢)版本。

        using (var lower = new Bitmap(@"lower.png"))
        using (var upper = new Bitmap(@"upper.png"))
        using (var output = new Bitmap(lower.Width, lower.Height))
        {
            var width = lower.Width;
            var height = lower.Height;

            for (var i = 0; i < height; i++)
            {
                for (var j = 0; j < width; j++)
                {
                    var upperPixel = upper.GetPixel(j, i);
                    var lowerPixel = lower.GetPixel(j, i);

                    var lowerColor = new HSLColor(lowerPixel.R, lowerPixel.G, lowerPixel.B);
                    var upperColor = new HSLColor(upperPixel.R, upperPixel.G, upperPixel.B) {Luminosity = lowerColor.Luminosity};
                    var outputColor = (Color)upperColor;

                    output.SetPixel(j, i, outputColor);
                }
            }

            // Drawing the output image
        }