Browse Source

refactor SixLabors.ImageSharp.Primitives.Region

pull/607/head
Anton Firszov 8 years ago
parent
commit
d71ba3d761
  1. 7
      src/ImageSharp.Drawing/Primitives/Region.cs
  2. 21
      src/ImageSharp.Drawing/Primitives/ShapeRegion.cs
  3. 2
      src/ImageSharp.Drawing/Processing/Drawing/Processors/FillRegionProcessor.cs
  4. 46
      tests/ImageSharp.Tests/Drawing/FillRegionProcessorTests.cs
  5. 4
      tests/ImageSharp.Tests/Drawing/Paths/ShapeRegionTests.cs

7
src/ImageSharp.Drawing/Primitives/Region.cs

@ -1,6 +1,7 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Primitives
@ -19,7 +20,7 @@ namespace SixLabors.ImageSharp.Primitives
/// Gets the bounding box that entirely surrounds this region.
/// </summary>
/// <remarks>
/// This should always contains all possible points returned from <see cref="Scan(float, float[], int)"/>.
/// This should always contains all possible points returned from <see cref="Scan"/>.
/// </remarks>
public abstract Rectangle Bounds { get; }
@ -28,8 +29,8 @@ namespace SixLabors.ImageSharp.Primitives
/// </summary>
/// <param name="y">The position along the y axis to find intersections.</param>
/// <param name="buffer">The buffer.</param>
/// <param name="offset">The point in the buffer to start setting offset.</param>
/// <param name="configuration">A <see cref="Configuration"/> instance in the context of the caller.</param>
/// <returns>The number of intersections found.</returns>
public abstract int Scan(float y, float[] buffer, int offset);
public abstract int Scan(float y, Span<float> buffer, Configuration configuration);
}
}

21
src/ImageSharp.Drawing/Primitives/ShapeRegion.cs

@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0.
using System;
using SixLabors.ImageSharp.Memory;
using SixLabors.Primitives;
using SixLabors.Shapes;
@ -39,21 +40,23 @@ namespace SixLabors.ImageSharp.Primitives
public override Rectangle Bounds { get; }
/// <inheritdoc/>
public override int Scan(float y, float[] buffer, int offset)
public override int Scan(float y, Span<float> buffer, Configuration configuration)
{
var start = new PointF(this.Bounds.Left - 1, y);
var end = new PointF(this.Bounds.Right + 1, y);
// TODO: This is a temporary workaround because of the lack of Span<T> API-s on IPath. We should use MemoryManager.Allocate() here!
var innerBuffer = new PointF[buffer.Length];
int count = this.Shape.FindIntersections(start, end, innerBuffer, 0);
for (int i = 0; i < count; i++)
using (IBuffer<PointF> tempBuffer = configuration.MemoryManager.Allocate<PointF>(buffer.Length))
{
buffer[i + offset] = innerBuffer[i].X;
}
Span<PointF> innerBuffer = tempBuffer.GetSpan();
int count = this.Shape.FindIntersections(start, end, innerBuffer);
return count;
for (int i = 0; i < count; i++)
{
buffer[i] = innerBuffer[i].X;
}
return count;
}
}
}
}

2
src/ImageSharp.Drawing/Processing/Drawing/Processors/FillRegionProcessor.cs

@ -118,7 +118,7 @@ namespace SixLabors.ImageSharp.Processing.Drawing.Processors
float yPlusOne = y + 1;
for (float subPixel = (float)y; subPixel < yPlusOne; subPixel += subpixelFraction)
{
int pointsFound = region.Scan(subPixel + offset, buffer.Array, 0);
int pointsFound = region.Scan(subPixel + offset, buffer.GetSpan(), configuration);
if (pointsFound == 0)
{
// nothing on this line skip

46
tests/ImageSharp.Tests/Drawing/FillRegionProcessorTests.cs

@ -4,7 +4,8 @@
using System.Numerics;
using Moq;
using System;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Primitives;
using SixLabors.ImageSharp.Processing;
@ -13,13 +14,15 @@ using SixLabors.ImageSharp.Processing.Drawing.Brushes;
using SixLabors.ImageSharp.Processing.Drawing.Pens;
using SixLabors.ImageSharp.Processing.Drawing.Processors;
using SixLabors.Primitives;
using Xunit;
namespace SixLabors.ImageSharp.Tests.Drawing
{
public class FillRegionProcessorTests
{
[Theory]
[InlineData(true, 1, 4)]
[InlineData(true, 2, 4)]
@ -29,21 +32,20 @@ namespace SixLabors.ImageSharp.Tests.Drawing
[InlineData(false, 16, 4)] // we always do 4 sub=pixels when antialising is off.
public void MinimumAntialiasSubpixelDepth(bool antialias, int antialiasSubpixelDepth, int expectedAntialiasSubpixelDepth)
{
var bounds = new SixLabors.Primitives.Rectangle(0, 0, 1, 1);
var bounds = new Rectangle(0, 0, 1, 1);
var brush = new Mock<IBrush<Rgba32>>();
var region = new Mock<Region>();
region.Setup(x => x.Bounds).Returns(bounds);
var region = new MockRegion2(bounds);
var options = new GraphicsOptions(antialias)
{
AntialiasSubpixelDepth = 1
};
var processor = new FillRegionProcessor<Rgba32>(brush.Object, region.Object, options);
var processor = new FillRegionProcessor<Rgba32>(brush.Object, region, options);
var img = new Image<Rgba32>(1, 1);
processor.Apply(img, bounds);
region.Verify(x => x.Scan(It.IsAny<float>(), It.IsAny<float[]>(), It.IsAny<int>()), Times.Exactly(4));
Assert.Equal(4, region.ScanInvocationCounter);
}
[Fact]
@ -52,7 +54,7 @@ namespace SixLabors.ImageSharp.Tests.Drawing
var bounds = new Rectangle(-100, -10, 10, 10);
var brush = new Mock<IBrush<Rgba32>>();
var options = new GraphicsOptions(true);
var processor = new FillRegionProcessor<Rgba32>(brush.Object, new MockRegion(), options);
var processor = new FillRegionProcessor<Rgba32>(brush.Object, new MockRegion1(), options);
var img = new Image<Rgba32>(10, 10);
processor.Apply(img, bounds);
}
@ -71,13 +73,11 @@ namespace SixLabors.ImageSharp.Tests.Drawing
}
// Mocking the region throws an error in netcore2.0
private class MockRegion : Region
private class MockRegion1 : Region
{
public override Rectangle Bounds => new Rectangle(-100, -10, 10, 10);
public override int MaxIntersections => 10;
public override int Scan(float y, float[] buffer, int offset)
public override int Scan(float y, Span<float> buffer, Configuration configuration)
{
if (y < 5)
{
@ -87,6 +87,28 @@ namespace SixLabors.ImageSharp.Tests.Drawing
}
return 0;
}
public override int MaxIntersections => 10;
}
private class MockRegion2 : Region
{
public MockRegion2(Rectangle bounds)
{
this.Bounds = bounds;
}
public override int MaxIntersections => 100;
public override Rectangle Bounds { get; }
public int ScanInvocationCounter { get; private set; }
public override int Scan(float y, Span<float> buffer, Configuration configuration)
{
this.ScanInvocationCounter++;
return 0;
}
}
}
}

4
tests/ImageSharp.Tests/Drawing/Paths/ShapeRegionTests.cs

@ -86,7 +86,7 @@ namespace SixLabors.ImageSharp.Tests.Drawing.Paths
Assert.True(e.X > this.bounds.Right);
}).Returns(0);
int i = region.Scan(yToScan, new float[0], 0);
int i = region.Scan(yToScan, new float[0], Configuration.Default);
this.pathMock.Verify(
x => x.FindIntersections(It.IsAny<PointF>(), It.IsAny<PointF>(), It.IsAny<PointF[]>(), It.IsAny<int>()),
@ -114,7 +114,7 @@ namespace SixLabors.ImageSharp.Tests.Drawing.Paths
Assert.True(e.X > this.bounds.Right);
}).Returns(0);
int i = region.Scan(yToScan, new float[0], 0);
int i = region.Scan(yToScan, new float[0], Configuration.Default);
this.pathMock.Verify(
x => x.FindIntersections(It.IsAny<PointF>(), It.IsAny<PointF>(), It.IsAny<PointF[]>(), It.IsAny<int>()),

Loading…
Cancel
Save