Question

Trying to figure out the most elegant way to render an image inside of a specific color of mask in C# (via System.Drawing or equivalent that will work in both desktop and ASP.NET applications).

The mask image will contain green keys where the image should be 'painted'.

(Desired Result image below is not perfect, hand lasso'd...)

Desired Result

No correct solution

OTHER TIPS

There are various techniques for this:

  1. Scan pixel data and build a mask image (as already suggested by itsme86 and Moby Disk)

  2. A variant of scanning that builds a clipping region from the mask and uses that when drawing (refer to this article by Bob Powell)

  3. Use color keys to mask in the Graphics.DrawImage call.

I'll focus on the third option.

Assuming that the image color that you want to eliminate from your mask is Color.Lime, we can use ImageAttributes.SetColorKey to stop any of that color from being drawn during a call to Graphics.DrawImage like this:

using (Image background = Bitmap.FromFile("tree.png"))
using (Image masksource = Bitmap.FromFile("mask.png"))
using (var imgattr = new ImageAttributes())
{
    // set color key to Lime 
    imgattr.SetColorKey(Color.Lime, Color.Lime);

    // Draw non-lime portions of mask onto original
    using (var g = Graphics.FromImage(background))
    {
        g.DrawImage(
            masksource,
            new Rectangle(0, 0, masksource.Width, masksource.Height),
            0, 0, masksource.Width, masksource.Height,
            GraphicsUnit.Pixel, imgattr
        );
    }

    // Do something with the composited image here...
    background.Save("Composited.png");
}

And the results: Results

You can use the same technique (with color key on Color.Fuchsia) if you want to put those bits of tree into another image.

You want something like this:

Bitmap original = new Bitmap(@"tree.jpg");
Bitmap mask = new Bitmap(@"mask.jpg");

int width = original.Width;
int height = original.Height;

// This is the color that will be replaced in the mask
Color key = Color.FromArgb(0,255,0);

// Processing one pixel at a time is slow, but easy to understand
for (int y = 0; y < height; y++)
{
    for (int x = 0; x < width; x++)
    {
        // Is this pixel "green" ?
        if (mask.GetPixel(x,y) == key)
        {
            // Copy the pixel color from the original
            Color c = original.GetPixel(x,y);

            // Into the mask
            mask.SetPixel(x,y,c);
        }
    }
}

You could probably read in the mask and translate it into an image that has the alpha channel set to 0 when the pixel is green and the alpha channel set to 0xFF when the pixel is any other color. Then you could draw the mask image over the original image.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top