From 4d38d7c426f4b6135230c052ce20c0a22d79862a Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sun, 14 Apr 2019 17:51:30 +0200 Subject: [PATCH] ResizeWindowOld --- .../Transforms/Resize/ResizeProcessor.cs | 122 +++++++++++++++--- .../Transforms/ResizeKernelMapTests.cs | 7 +- .../Processors/Transforms/ResizeTests.cs | 13 +- 3 files changed, 119 insertions(+), 23 deletions(-) diff --git a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeProcessor.cs index 8c911cbfab..429b709ee3 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeProcessor.cs @@ -244,26 +244,24 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms // A 2-pass 1D algorithm appears to be faster than splitting a 1-pass 2D algorithm // First process the columns. Since we are not using multiple threads startY and endY // are the upper and lower bounds of the source rectangle. - using (Buffer2D firstPassPixelsTransposed = source.MemoryAllocator.Allocate2D(sourceHeight, width)) + //using (Buffer2D firstPassPixelsTransposed = source.MemoryAllocator.Allocate2D(sourceHeight, width)) + + using (var resizeWindow = new ResizeWindowOld( + configuration, + sourceRectangle, + conversionModifiers, + this.horizontalKernelMap, + this.verticalKernelMap, + sourceHeight, + width, + minX, + maxX, + startX)) using (IMemoryOwner tempBuffer = source.MemoryAllocator.Allocate(Math.Max(source.Width, width))) { - firstPassPixelsTransposed.MemorySource.Clear(); + Span tempRowSpan = tempBuffer.GetSpan().Slice(sourceX, source.Width - sourceX); - for (int y = 0; y < sourceRectangle.Bottom; y++) - { - Span sourceRow = source.GetPixelRowSpan(y).Slice(sourceX); - Span tempRowSpan = tempBuffer.GetSpan().Slice(sourceX, source.Width - sourceX); - - PixelOperations.Instance.ToVector4(configuration, sourceRow, tempRowSpan, conversionModifiers); - - ref Vector4 firstPassBaseRef = ref firstPassPixelsTransposed.Span[y]; - - for (int x = minX; x < maxX; x++) - { - ResizeKernel kernel = this.horizontalKernelMap.GetKernel(x - startX); - Unsafe.Add(ref firstPassBaseRef, x * sourceHeight) = kernel.Convolve(tempRowSpan); - } - } + resizeWindow.Initialize(source.PixelBuffer, tempRowSpan); // Now process the rows. Span tempColSpan = tempBuffer.GetSpan().Slice(0, width); @@ -277,7 +275,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms for (int x = 0; x < width; x++) { - Span firstPassColumn = firstPassPixelsTransposed.GetRowSpan(x).Slice(sourceY); + Span firstPassColumn = resizeWindow.GetColumnSpan(x); // Destination color components Unsafe.Add(ref tempRowBase, x) = kernel.Convolve(firstPassColumn); @@ -301,4 +299,92 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms this.verticalKernelMap = null; } } + + class ResizeWindowOld : IDisposable + { + private readonly Buffer2D buffer; + + private readonly Configuration configuration; + + private readonly Rectangle sourceRectangle; + + private readonly PixelConversionModifiers conversionModifiers; + + private readonly ResizeKernelMap horizontalKernelMap; + + private readonly ResizeKernelMap verticalKernelMap; + + private readonly int minX; + + private readonly int maxX; + + private readonly int startX; + + public ResizeWindowOld( + Configuration configuration, + Rectangle sourceRectangle, + PixelConversionModifiers conversionModifiers, + ResizeKernelMap horizontalKernelMap, + ResizeKernelMap verticalKernelMap, + int sourceHeight, + int destWidth, + int minX, + int maxX, + int startX) + { + this.configuration = configuration; + this.sourceRectangle = sourceRectangle; + this.conversionModifiers = conversionModifiers; + this.horizontalKernelMap = horizontalKernelMap; + this.verticalKernelMap = verticalKernelMap; + this.minX = minX; + this.maxX = maxX; + this.startX = startX; + this.buffer = configuration.MemoryAllocator.Allocate2D(sourceRectangle.Height, destWidth, AllocationOptions.Clean); + + this.Top = sourceRectangle.Top; + + this.Bottom = sourceRectangle.Bottom; + } + + public int Top { get; private set; } + + public int Bottom { get; private set; } + + public void Initialize( + Buffer2D source, + Span tempRowSpan) + where TPixel : struct, IPixel + { + for (int y = this.sourceRectangle.Top; y < this.sourceRectangle.Bottom; y++) + { + Span sourceRow = source.GetRowSpan(y).Slice(this.sourceRectangle.X); + + PixelOperations.Instance.ToVector4( + this.configuration, + sourceRow, + tempRowSpan, + this.conversionModifiers); + + ref Vector4 firstPassBaseRef = ref this.buffer.Span[y - this.sourceRectangle.Y]; + + for (int x = this.minX; x < this.maxX; x++) + { + ResizeKernel kernel = this.horizontalKernelMap.GetKernel(x - this.startX); + Unsafe.Add(ref firstPassBaseRef, x * this.sourceRectangle.Height) = kernel.Convolve(tempRowSpan); + } + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Span GetColumnSpan(int x) + { + return this.buffer.GetRowSpan(x); + } + + public void Dispose() + { + this.buffer.Dispose(); + } + } } \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeKernelMapTests.cs b/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeKernelMapTests.cs index 5d3790f071..9de8665869 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeKernelMapTests.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeKernelMapTests.cs @@ -93,7 +93,9 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms GenerateImageResizeData(); - [Theory(Skip = "Only for debugging and development")] + [Theory( + Skip = "Only for debugging and development" + )] [MemberData(nameof(KernelMapData))] public void PrintNonNormalizedKernelMap(string resamplerName, int srcSize, int destSize) { @@ -130,7 +132,10 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms var referenceMap = ReferenceKernelMap.Calculate(resampler, destSize, srcSize); var kernelMap = ResizeKernelMap.Calculate(resampler, destSize, srcSize, Configuration.Default.MemoryAllocator); + + #if DEBUG + this.Output.WriteLine(kernelMap.Info); this.Output.WriteLine($"Expected KernelMap:\n{PrintKernelMap(referenceMap)}\n"); this.Output.WriteLine($"Actual KernelMap:\n{PrintKernelMap(kernelMap)}\n"); #endif diff --git a/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeTests.cs b/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeTests.cs index 7f1f5a26a2..5cea8ddaea 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeTests.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeTests.cs @@ -5,6 +5,7 @@ using System; using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.PixelFormats; +using SixLabors.ImageSharp.Primitives; using SixLabors.ImageSharp.Processing; using SixLabors.ImageSharp.Processing.Processors.Transforms; using SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison; @@ -37,19 +38,23 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms PixelTypes.Rgba32 | PixelTypes.Bgra32 | PixelTypes.RgbaVector; [Theory] - [WithBasicTestPatternImages(15, 12, PixelTypes.Rgba32)] - public void Resize_BasicSmall(TestImageProvider provider) + [WithBasicTestPatternImages(15, 12, PixelTypes.Rgba32, 2, 3, 1, 2)] + [WithBasicTestPatternImages(2, 256, PixelTypes.Rgba32, 1, 1, 1, 8)] + [WithBasicTestPatternImages(2, 32, PixelTypes.Rgba32, 1, 1, 1, 2)] + public void Resize_BasicSmall(TestImageProvider provider, int wN, int wD, int hN, int hD) where TPixel : struct, IPixel { // Basic test case, very helpful for debugging + // [WithBasicTestPatternImages(15, 12, PixelTypes.Rgba32, 2, 3, 1, 2)] means: // resizing: (15, 12) -> (10, 6) // kernel dimensions: (3, 4) using (Image image = provider.GetImage()) { - var destSize = new Size(image.Width * 2 / 3, image.Height / 2); + var destSize = new Size(image.Width * wN / wD, image.Height * hN / hD); image.Mutate(x => x.Resize(destSize, KnownResamplers.Bicubic, false)); - image.DebugSave(provider); + FormattableString outputInfo = $"({wN}÷{wD},{hN}÷{hD})"; + image.DebugSave(provider, outputInfo); } }