Skip to content

IndexOutOfRangeException when drawing line near top when Stroke > 1.5f #108

@atruskie

Description

@atruskie

Prerequisites

  • I have written a descriptive issue title
  • I have verified that I am running the latest version of ImageSharp.Drawing
  • I have verified if the problem exist in both DEBUG and RELEASE mode
  • I have searched open and closed issues to ensure it has not already been reported

Description

Drawing a horizontal line across the top edge of an image results in an exception if the stroke width is greater than 1.5f and antialiasing is disabled.

Steps to Reproduce

The following test code was run and adapted from

public void DrawingLineAtTopShouldDisplay()
{
using var image = new Image<Rgba32>(Configuration.Default, 100, 100, Color.Black);
image.Mutate(x => x
.SetGraphicsOptions(g => g.Antialias = false)
.DrawLines(
this.red,
1f,
new PointF(0, 0),
new PointF(100, 0)
));
var locations = Enumerable.Range(0, 100).Select(i => (x: i, y: 0));
Assert.All(locations, l =>
{
Assert.Equal(this.red, image[l.x, l.y]);
});
}

        [Fact]
        public void DrawingLineAtTopWith1point5pxStrokeShouldDisplay()
        {
            using var image = new Image<Rgba32>(Configuration.Default, 100, 100, Color.Black);
            image.Mutate(x => x
                    .SetGraphicsOptions(g => g.Antialias = false)
                    .DrawLines(
                        this.red,
                        1.5f,
                        new PointF(0, 0),
                        new PointF(100, 0)
                    ));

            var locations = Enumerable.Range(0, 100).Select(i => (x: i, y: 0));
            Assert.All(locations, l =>
            {
                Assert.Equal(this.red, image[l.x, l.y]);
            });
        }

        [Fact]
        public void DrawingLineAtTopWith2pxStrokeShouldDisplay()
        {
            using var image = new Image<Rgba32>(Configuration.Default, 100, 100, Color.Black);
            image.Mutate(x => x
                    .SetGraphicsOptions(g => g.Antialias = false)
                    .DrawLines(
                        this.red,
                        2f,
                        new PointF(0, 0),
                        new PointF(100, 0)
                    ));

            var locations = Enumerable.Range(0, 100).Select(i => (x: i, y: 0));
            Assert.All(locations, l =>
            {
                Assert.Equal(this.red, image[l.x, l.y]);
            });
        }

        [Fact]
        public void DrawingLineAtTopWith3pxStrokeShouldDisplay()
        {
            using var image = new Image<Rgba32>(Configuration.Default, 100, 100, Color.Black);
            image.Mutate(x => x
                    .SetGraphicsOptions(g => g.Antialias = false)
                    .DrawLines(
                        this.red,
                        3f,
                        new PointF(0, 0),
                        new PointF(100, 0)
                    ));

            var locations = Enumerable.Range(0, 100).Select(i => (x: i, y: 0))
                .Concat(Enumerable.Range(0, 100).Select(i => (x: i, y: 1)));
            Assert.All(locations, l =>
            {
                Assert.Equal(this.red, image[l.x, l.y]);
            });
        }

Then: C:\Work\Github\ImageSharp.Drawing\tests\ImageSharp.Drawing.Tests> dotnet test -c Release --filter "Issue_28"

The existing tests pass, the altered stroke width tests fail:

<snip>
Error Message:
   SixLabors.ImageSharp.ImageProcessingException : An error occurred when processing the image using FillRegionProcessor`1. See the inner exception for more detail.
---- SixLabors.ImageSharp.ImageProcessingException : An error occurred when processing the image using FillRegionProcessor`1. See the inner exception for more detail.
-------- System.IndexOutOfRangeException : Index was outside the bounds of the array.
  Stack Trace:
     at SixLabors.ImageSharp.Processing.Processors.ImageProcessor`1.SixLabors.ImageSharp.Processing.Processors.IImageProcessor<TPixel>.Execute()
   at SixLabors.ImageSharp.Processing.DefaultImageProcessorContext`1.ApplyProcessor(IImageProcessor processor, Rectangle rectangle)
   at SixLabors.ImageSharp.Processing.DefaultImageProcessorContext`1.ApplyProcessor(IImageProcessor processor)
   at SixLabors.ImageSharp.Drawing.Processing.DrawLineExtensions.DrawLines(IImageProcessingContext source, IBrush brush, Single thickness, PointF[] points) in C:\Work\Github\ImageSharp.Drawing\src\ImageSharp.Drawing\Processing\Extensions\DrawLineExtensions.cs:line 43
   at SixLabors.ImageSharp.Drawing.Tests.Issues.Issue_28.<>c__DisplayClass3_0.<DrawingLineAtTopWith2pxStrokeShouldDisplay>b__0(IImageProcessingContext x) in C:\Work\Github\ImageSharp.Drawing\tests\ImageSharp.Drawing.Tests\Issues\Issue_28.cs:line 61
   at SixLabors.ImageSharp.Processing.ProcessingExtensions.Mutate[TPixel](Image`1 source, Configuration configuration, Action`1 operation)
   at SixLabors.ImageSharp.Drawing.Tests.Issues.Issue_28.DrawingLineAtTopWith2pxStrokeShouldDisplay() in C:\Work\Github\ImageSharp.Drawing\tests\ImageSharp.Drawing.Tests\Issues\Issue_28.cs:line 61
----- Inner Stack Trace -----
   at SixLabors.ImageSharp.Processing.Processors.ImageProcessor`1.Apply(ImageFrame`1 source)
   at SixLabors.ImageSharp.Processing.Processors.ImageProcessor`1.SixLabors.ImageSharp.Processing.Processors.IImageProcessor<TPixel>.Execute()
----- Inner Stack Trace -----
   at SixLabors.ImageSharp.Drawing.Shapes.Rasterization.PolygonScanner.SkipEdgesBeforeMinY() in C:\Work\Github\ImageSharp.Drawing\src\ImageSharp.Drawing\Shapes\Rasterization\PolygonScanner.cs:line 149
   at SixLabors.ImageSharp.Drawing.Shapes.Rasterization.PolygonScanner.Init() in C:\Work\Github\ImageSharp.Drawing\src\ImageSharp.Drawing\Shapes\Rasterization\PolygonScanner.cs:line 127
   at SixLabors.ImageSharp.Drawing.Shapes.Rasterization.PolygonScanner.Create(IPath polygon, Int32 minY, Int32 maxY, Int32 subsampling, IntersectionRule intersectionRule, MemoryAllocator allocator) in C:\Work\Github\ImageSharp.Drawing\src\ImageSharp.Drawing\Shapes\Rasterization\PolygonScanner.cs:line 104
   at SixLabors.ImageSharp.Drawing.Processing.Processors.Drawing.FillRegionProcessor`1.OnFrameApply(ImageFrame`1 source) in C:\Work\Github\ImageSharp.Drawing\src\ImageSharp.Drawing\Processing\Processors\Drawing\FillRegionProcessor{TPixel}.cs:line 74
   at SixLabors.ImageSharp.Processing.Processors.ImageProcessor`1.Apply(ImageFrame`1 source)
<snip>
Failed!  - Failed:     3, Passed:     4, Skipped:     0, Total:     7, Duration: 154 ms

System Configuration

  • ImageSharp.Drawing version: master (3d737b5)
  • Other ImageSharp packages and versions:
  • Environment (Operating system, version and so on): Win 10 x64, 20H2
  • .NET Framework version: net5.0 (and ImageSharp defaults for dotnet test command)
  • Additional information:

Seems to be related to the new PolygonScanner SkipEdgesBeforeMinY code.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions