Search code examples
c#imagesharp

ImageSharp: Drawing a clipped Polygon out of bounds


I'm currently in the process of migrating a project that uses System.Drawing.Bitmap over to use ImageSharp. As part of this migration, I am migrating logic that would draw circles onto the bitmap using the Graphics.FromImage function.

The problem I am faced with is, if the circle previously went outside the bounds of the Bitmap, this was previously fine and it would draw the parts of the circle it could, simply clipping the drawn circle. With ImageSharp, this would, understandably throw an out of bounds exception.

A simplified implementation:

void Main()
{
    var width = 70;
    var height = 70;
    
    SystemDrawingImpl(width, height);
    ImageSharpImpl(width, height);
}

private void SystemDrawingImpl(int width, int height)
{
    using var bitmap = new Bitmap(64, 64);
    using var graphics = Graphics.FromImage(bitmap);

    var xLocation = ((bitmap.Width / 2) - (width / 2)) - 1;
    var yLocation = ((bitmap.Height / 2) - (height / 2)) - 1;
    graphics.DrawEllipse(new System.Drawing.Pen(System.Drawing.Color.Green, 1.1f), xLocation, yLocation, width, height);

    var memoryStream = new MemoryStream();
    bitmap.Save(memoryStream, ImageFormat.Jpeg);

    Util.Image(memoryStream.ToArray()).Dump();
}

private void ImageSharpImpl(int width, int height)
{
    using var image = new Image<Rgba32>(64, 64);
    var brush = SixLabors.ImageSharp.Drawing.Processing.Brushes.Solid(SixLabors.ImageSharp.Color.Green);
    var pen = SixLabors.ImageSharp.Drawing.Processing.Pens.Solid(SixLabors.ImageSharp.Color.Green, 0.1f);
    var ellipse = new EllipsePolygon(32, 32, width, height);
    image.Mutate(ctx => ctx.Draw(pen, ellipse));

    var memoryStream = new MemoryStream();
    image.Save(memoryStream, new JpegEncoder());

    Util.Image(memoryStream.ToArray()).Dump();
}

For which the output for System.Drawing would be:

enter image description here

The output/exception from ImageSharp is:

ImageProcessingException: An error occurred when processing the image using FillRegionProcessor`1. See the inner exception for more detail.

ArgumentOutOfRangeException: Specified argument was out of the range of valid values. (Parameter 'edgeIdx')

I was wondering if there was a way to get a similar output. Is there a way in which I'd be able to still draw the parts of the ellipse that is possible?

I have attempted to remove the points that are "invalid" via a simple where:

var points = ellipse.Points.ToArray();
var validPoints = points.Where(x => (x.X <= image.Width && x.X >= 0) && (x.Y <= image.Height && x.Y >= 0)).ToArray();
image.Mutate(ctx => ctx.DrawPolygon(pen, validPoints));

However this will still try to create a fully joined path which is not the desired effect:

enter image description here

Any advice on how I might achieve this would be appreciated


Solution

  • After a lot of digging I managed to find somewhat of an answer.

    I decided to pull down the latest version of ImageSharp.Drawing and executed the following simple piece of code which I knew threw an exception:

    using var image = new Image<Rgba32>(64, 64);
    var ellipse = new EllipsePolygon(32, 32, 70, 70);
    image.Mutate(x => x.Draw(Color.Green, 2f, ellipse));
    

    This code which when I pulled the repository, works just fine! This code being the most up to date code for the repository as of this answer being posted, I reverted back to a previous commit which was around the time of the NuGet package for ImageSharp.Drawing was published, ~8th October, version 1.0.0-beta13. This code now threw the exception I had before.

    Debugging this code, I found the file where this was thrown and found where it was executed from, it was PolygonScanner.cs. The file history showed this had one change this year which referenced an issue:

    Issue 108

    This issue fixed a problem which arose around this area which seemed to fix my issue.

    Therefore the issue is fixed... In the latest version of the code. This package is somewhat out of date with the latest beta however there looks to be an alpha I can use until this package is updated and a RC is released, which sounds like it will be soon!

    Release Candidate Discussion

    Curse of using a beta I suppose!