diff --git a/src/ImageSharp.Drawing/Processing/Drawing/Processors/FillRegionProcessor.cs b/src/ImageSharp.Drawing/Processing/Drawing/Processors/FillRegionProcessor.cs index 571ca5d3f..4072f88a8 100644 --- a/src/ImageSharp.Drawing/Processing/Drawing/Processors/FillRegionProcessor.cs +++ b/src/ImageSharp.Drawing/Processing/Drawing/Processors/FillRegionProcessor.cs @@ -96,36 +96,35 @@ namespace SixLabors.ImageSharp.Processing.Drawing.Processors using (BrushApplicator applicator = this.Brush.CreateApplicator(source, rect, this.Options)) { int scanlineWidth = maxX - minX; - using (BasicArrayBuffer buffer = source.MemoryManager.AllocateFake(maxIntersections)) - using (BasicArrayBuffer scanline = source.MemoryManager.AllocateFake(scanlineWidth)) + using (IBuffer bBuffer = source.MemoryManager.Allocate(maxIntersections)) + using (IBuffer bScanline = source.MemoryManager.Allocate(scanlineWidth)) { bool scanlineDirty = true; float subpixelFraction = 1f / subpixelCount; float subpixelFractionPoint = subpixelFraction / subpixelCount; + + Span buffer = bBuffer.GetSpan(); + Span scanline = bScanline.GetSpan(); + for (int y = minY; y < maxY; y++) { if (scanlineDirty) { - // clear the buffer - for (int x = 0; x < scanlineWidth; x++) - { - scanline[x] = 0; - } - + scanline.Clear(); scanlineDirty = false; } float yPlusOne = y + 1; for (float subPixel = (float)y; subPixel < yPlusOne; subPixel += subpixelFraction) { - int pointsFound = region.Scan(subPixel + offset, buffer.GetSpan(), configuration); + int pointsFound = region.Scan(subPixel + offset, buffer, configuration); if (pointsFound == 0) { // nothing on this line skip continue; } - QuickSort(new Span(buffer.Array, 0, pointsFound)); + QuickSort(buffer.Slice(0, pointsFound)); for (int point = 0; point < pointsFound; point += 2) { @@ -181,7 +180,7 @@ namespace SixLabors.ImageSharp.Processing.Drawing.Processors } } - applicator.Apply(scanline.GetSpan(), minX, y); + applicator.Apply(scanline, minX, y); } } } @@ -189,31 +188,45 @@ namespace SixLabors.ImageSharp.Processing.Drawing.Processors } [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static void Swap(Span data, int left, int right) + private static void Swap(ref float left, ref float right) { - float tmp = data[left]; - data[left] = data[right]; - data[right] = tmp; + float tmp = left; + left = right; + right = tmp; } private static void QuickSort(Span data) { - QuickSort(data, 0, data.Length - 1); + if (data.Length < 2) + { + return; + } + else if (data.Length == 2) + { + if (data[0] > data[1]) + { + Swap(ref data[0], ref data[1]); + } + + return; + } + + QuickSort(ref data[0], 0, data.Length - 1); } - private static void QuickSort(Span data, int lo, int hi) + private static void QuickSort(ref float data0, int lo, int hi) { if (lo < hi) { - int p = Partition(data, lo, hi); - QuickSort(data, lo, p); - QuickSort(data, p + 1, hi); + int p = Partition(ref data0, lo, hi); + QuickSort(ref data0, lo, p); + QuickSort(ref data0, p + 1, hi); } } - private static int Partition(Span data, int lo, int hi) + private static int Partition(ref float data0, int lo, int hi) { - float pivot = data[lo]; + float pivot = Unsafe.Add(ref data0, lo); int i = lo - 1; int j = hi + 1; while (true) @@ -222,20 +235,20 @@ namespace SixLabors.ImageSharp.Processing.Drawing.Processors { i = i + 1; } - while (data[i] < pivot && i < hi); + while (Unsafe.Add(ref data0, i) < pivot && i < hi); do { j = j - 1; } - while (data[j] > pivot && j > lo); + while (Unsafe.Add(ref data0, j) > pivot && j > lo); if (i >= j) { return j; } - Swap(data, i, j); + Swap(ref Unsafe.Add(ref data0, i), ref Unsafe.Add(ref data0, j)); } } } diff --git a/src/ImageSharp/Memory/MemoryManager.cs b/src/ImageSharp/Memory/MemoryManager.cs index 52bdc897f..32b1c2001 100644 --- a/src/ImageSharp/Memory/MemoryManager.cs +++ b/src/ImageSharp/Memory/MemoryManager.cs @@ -27,16 +27,6 @@ namespace SixLabors.ImageSharp.Memory /// The internal abstract IManagedByteBuffer AllocateManagedByteBuffer(int length, bool clear); - /// - /// Temporal workaround. A method providing a "Buffer" based on a generic array without the 'Unsafe.As()' hackery. - /// Should be replaced with 'Allocate()' as soon as SixLabors.Shapes has Span-based API-s! - /// - internal BasicArrayBuffer AllocateFake(int length, bool dummy = false) - where T : struct - { - return new BasicArrayBuffer(new T[length]); - } - /// /// Releases all retained resources not being in use. /// Eg: by resetting array pools and letting GC to free the arrays. diff --git a/tests/ImageSharp.Tests/Drawing/FillSolidBrushTests.cs b/tests/ImageSharp.Tests/Drawing/FillSolidBrushTests.cs index 83f4fbde6..58fd4c767 100644 --- a/tests/ImageSharp.Tests/Drawing/FillSolidBrushTests.cs +++ b/tests/ImageSharp.Tests/Drawing/FillSolidBrushTests.cs @@ -12,7 +12,10 @@ using Xunit; namespace SixLabors.ImageSharp.Tests.Drawing { - + using System; + + using SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison; + using SixLabors.Primitives; [GroupOutput("Drawing")] public class FillSolidBrushTests @@ -67,6 +70,19 @@ namespace SixLabors.ImageSharp.Tests.Drawing } } + [Theory] + [WithSolidFilledImages(16, 16, "Red", PixelTypes.Rgba32, 5, 7, 3, 8)] + [WithSolidFilledImages(16, 16, "Red", PixelTypes.Rgba32, 8, 5, 6, 4)] + public void FillRegion(TestImageProvider provider, int x0, int y0, int w, int h) + where TPixel : struct, IPixel + { + FormattableString testDetails = $"(x{x0},y{y0},w{w},h{h})"; + var region = new RectangleF(x0, y0, w, h); + TPixel color = TestUtils.GetPixelOfNamedColor("Blue"); + + provider.RunValidatingProcessorTest(c => c.Fill(color, region), testDetails, ImageComparer.Exact); + } + public static readonly TheoryData BlendData = new TheoryData() { diff --git a/tests/ImageSharp.Tests/TestUtilities/TestUtils.cs b/tests/ImageSharp.Tests/TestUtilities/TestUtils.cs index f71793ff2..43ae8423e 100644 --- a/tests/ImageSharp.Tests/TestUtilities/TestUtils.cs +++ b/tests/ImageSharp.Tests/TestUtilities/TestUtils.cs @@ -113,8 +113,6 @@ namespace SixLabors.ImageSharp.Tests /// public static PixelTypes GetPixelType(this Type colorStructClrType) => ClrTypes2PixelTypes[colorStructClrType]; - - public static IEnumerable> ExpandAllTypes(this PixelTypes pixelTypes) { if (pixelTypes == PixelTypes.Undefined) diff --git a/tests/Images/External b/tests/Images/External index eb40b3c03..b1f057df3 160000 --- a/tests/Images/External +++ b/tests/Images/External @@ -1 +1 @@ -Subproject commit eb40b3c039dd8c8ca448cb8073a59ca178901e9f +Subproject commit b1f057df33b7bfa6cabe714cf7090ac6017ea5d8