Нарисуйте изображение поверх другого изображения с помощью режима смешивания цветов - PullRequest
7 голосов
/ 17 марта 2012

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

Но это - конечно - просто закрашивание нижнего изображения.

Итак, вопрос:

Как нарисовать изображение поверх другого изображения, используя режим наложения "color", доступный в Photoshop?

EDIT:

Чтобы было немного яснее, чего я хочу достичь:

enter image description here

А если кто-то хочет использовать изображения для тестирования:

enter image description here enter image description here

Ответы [ 3 ]

6 голосов
/ 18 марта 2012

Вот мое решение. Я использовал класс Рича Ньюмана 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
}
0 голосов
/ 22 сентября 2015

Вот безопасная (и более медленная) версия принятого ответа для полноты.

        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
        }
0 голосов
/ 18 марта 2012

Вам придется реструктурировать свой код так, чтобы вы рисовали свой градиент на временном растровом изображении, читали каждый пиксель из временного растрового изображения и холста и записывали составной пиксель на холст. Вы должны быть в состоянии найти преобразование кода между цветами RGB и HSL, и, как только вы это сделаете, установка оттенка и насыщенности пикселей на холсте для значений из вашего временного растрового изображения будет тривиальной (хотя это будет немного сложнее, если вы хотите использовать альфа значения).

...