1

I need to perform Source In composition on 2 images.

For example this image:
Source
and a mask image (tested with black-transparent and black-white):
mask

should produce result:
result image

I am trying to do this with ImageSharp:

img.Mutate(imgMaskIn =>
{
    using (var mask = Image.Load(maskImageFileName))
    {
        imgMaskIn.DrawImage(mask, new GraphicsOptions { AlphaCompositionMode = PixelAlphaCompositionMode.SrcIn});
    }
});

but result is mask image. It should work based on this merge request.
Did I wrongly used library, or there is a bug?

Is there any other way to do this in ASP.NET Core?

poke
  • 369,085
  • 72
  • 557
  • 602
Makla
  • 9,899
  • 16
  • 72
  • 142
  • I’m removing the ASP.NET Core tag since this has nothing to do with it. You just want to solve this in .NET with ImageSharp. Once you are able to do that, you can directly use that solution inside ASP.NET Core. – poke Oct 18 '18 at 14:16
  • It was a bug in png decoder. More information [here](https://github.com/SixLabors/ImageSharp/issues/739). – Makla Oct 19 '18 at 05:23

2 Answers2

4

Unfortunately, the syntax to do this is with ImageSharp is changing between the current preview version and the development version which should be the final API for this.

With 1.0.0-beta0005, you can blend these images like this:

using (var pattern = Image.Load("img_pattern.png"))
using (var texture = Image.Load("img_texture.png"))
{
    var options = new GraphicsOptions { BlenderMode = PixelBlenderMode.In };
    using (var result = pattern.Clone(x => x.DrawImage(options, texture)))
    {
        result.Save("img_out.png");
    }
}

Note that you have to use a pattern image with alpha transparency for this. You cannot use a keyed transparency (at least not with this solution).

I’ve made the pattern transparent for that purpose (you can get the one I used here) and got this result:

Result image


In the final release, it will look like this:

using (var pattern = Image.Load("img_pattern.png"))
using (var texture = Image.Load("img_texture.png"))
{
    var options = new GraphicsOptions { AlphaCompositionMode = PixelAlphaCompositionMode.SrcIn };
    using (var result = pattern.Clone(x => x.DrawImage(texture, options)))
    {
        result.Save("img_out.png");
    }
}

A good way to figure that out btw. is to look at the PorterDuffCompositorTests file which contains the tests for this feature and as such will always reflect the current API.

poke
  • 369,085
  • 72
  • 557
  • 602
  • The development builds contains what _should_ be the final Porter-Duff API with separable alpha and color blending modes. – James South Oct 18 '18 at 15:13
  • 1
    @JamesSouth Oh, good to know, I’ll update my answer to include the final API then too :) – poke Oct 18 '18 at 15:21
  • 1
    As of 1.0.0-dev002031 this will now work. Bear in mind if the input file is 1bbp then the library will attempt to save it out at 1bps o you would need use a new `PngEncoder` instance on save. https://www.myget.org/feed/sixlabors/package/nuget/SixLabors.ImageSharp/1.0.0-dev002031 – James South Oct 18 '18 at 19:38
1

As of March 2022 the accepted answer doesn't work anymore, with ImageSharp 2. The following code doesn't solve the exact problem in the question, but it's how I got something similar to work:

using SixLabors.ImageSharp;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing.Processors.Drawing;
...
using (var inImg = Image.Load<RgbaVector>(imagePath)) //has some transparent pixels
using (var background = new Image<RgbaVector>(inImg.Width, inImg.Height, new RgbaVector(1, 0, 0, 1))) //this is just a solid red image of the same size as the loaded image, but it could be any image
{
    var processorCreator = new DrawImageProcessor(
        inImg, 
        Point.Empty, 
        PixelColorBlendingMode.Normal, 
        PixelAlphaCompositionMode.SrcAtop, //this is the setting you want to play with to get the behavior from the original question
        1f
    ); 
                
    var pxProcessor = processorCreator.CreatePixelSpecificProcessor(
        Configuration.Default, 
        background, 
        inImg.Bounds());

    pxProcessor.Execute(); //writes to the image passed into CreatePixelSpecificProcessor, in this case background

    background.Save("some_path.png");
    }
}
Pete Michaud
  • 1,813
  • 4
  • 22
  • 36