Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Draw image on top of another image with blending mode color

In Photoshop you can select "Color" (the second from the bottom) to set the blending mode to the next lower layer:

Layer blending mode selection photoshop

If you have just a gradient on top of an image the result could look like this:

Color blending example

The description of the color blending mode I found somewhere is:

Color changes the hue and saturation of the lower layer to the hue and saturation of the upper layer but leaves luminosity alone.

My code so far is:

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

But that is - of course - just painting over the lower image.

So the question is:

How can I draw an image on top of another image using the blending mode "color" as available in Photoshop?

EDIT:

To make it a bit more clear of what I want to achieve:

enter image description here

And if someone wants to use the images for testing:

enter image description hereenter image description here

like image 382
Marc Avatar asked Mar 17 '12 12:03

Marc


1 Answers

Here is my solution. I've used Rich Newman's HSLColor class to convert between RGB and HSL values.

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
}
like image 144
Balazs Tihanyi Avatar answered Nov 09 '22 14:11

Balazs Tihanyi