diff --git a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernel.cs b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernel.cs index f349634ac0..28b3d3a4dd 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernel.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernel.cs @@ -19,27 +19,27 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms /// Initializes a new instance of the struct. /// [MethodImpl(InliningOptions.ShortMethod)] - internal ResizeKernel(int left, float* bufferPtr, int length) + internal ResizeKernel(int startIndex, float* bufferPtr, int length) { - this.Left = left; + this.StartIndex = startIndex; this.bufferPtr = bufferPtr; this.Length = length; } /// - /// Gets the left index for the destination row + /// Gets the start index for the destination row. /// - public int Left { get; } + public int StartIndex { get; } /// - /// Gets the the length of the kernel + /// Gets the the length of the kernel. /// public int Length { get; } /// - /// Gets the span representing the portion of the that this window covers + /// Gets the span representing the portion of the that this window covers. /// - /// The + /// The . /// public Span Values { @@ -55,17 +55,22 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms [MethodImpl(InliningOptions.ShortMethod)] public Vector4 Convolve(Span rowSpan) { - ref float horizontalValues = ref Unsafe.AsRef(this.bufferPtr); - int left = this.Left; - ref Vector4 vecPtr = ref Unsafe.Add(ref MemoryMarshal.GetReference(rowSpan), left); + ref Vector4 vecPtr = ref Unsafe.Add(ref MemoryMarshal.GetReference(rowSpan), this.StartIndex); + + return this.ConvolveCore(ref vecPtr); + } + [MethodImpl(InliningOptions.ShortMethod)] + public Vector4 ConvolveCore(ref Vector4 rowStartRef) + { + ref float horizontalValues = ref Unsafe.AsRef(this.bufferPtr); // Destination color components Vector4 result = Vector4.Zero; for (int i = 0; i < this.Length; i++) { float weight = Unsafe.Add(ref horizontalValues, i); - Vector4 v = Unsafe.Add(ref vecPtr, i); + Vector4 v = Unsafe.Add(ref rowStartRef, i); result += v * weight; } @@ -73,7 +78,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms } /// - /// Copy the contents of altering + /// Copy the contents of altering /// to the value . /// internal ResizeKernel AlterLeftValue(int left) diff --git a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeProcessor.cs index 38419b5dd6..73f9b4241e 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeProcessor.cs @@ -197,7 +197,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms int startY = this.TargetRectangle.Y; int startX = this.TargetRectangle.X; - var workingRect = Rectangle.Intersect( + var destWorkingRect = Rectangle.Intersect( this.TargetRectangle, new Rectangle(0, 0, width, height)); @@ -208,7 +208,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms float heightFactor = sourceRectangle.Height / (float)this.TargetRectangle.Height; ParallelHelper.IterateRows( - workingRect, + destWorkingRect, configuration, rows => { @@ -219,7 +219,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms source.GetPixelRowSpan((int)(((y - startY) * heightFactor) + sourceY)); Span targetRow = destination.GetPixelRowSpan(y); - for (int x = workingRect.Left; x < workingRect.Right; x++) + for (int x = destWorkingRect.Left; x < destWorkingRect.Right; x++) { // X coordinates of source points targetRow[x] = sourceRow[(int)(((x - startX) * widthFactor) + sourceX)]; @@ -248,7 +248,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms this.horizontalKernelMap, this.verticalKernelMap, width, - workingRect, + destWorkingRect, startX)) using (IMemoryOwner tempBuffer = source.MemoryAllocator.Allocate(width)) { @@ -257,12 +257,12 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms // Now process the rows. Span tempColSpan = tempBuffer.GetSpan(); - for (int y = workingRect.Top; y < workingRect.Bottom; y++) + for (int y = destWorkingRect.Top; y < destWorkingRect.Bottom; y++) { // Ensure offsets are normalized for cropping and padding. ResizeKernel kernel = this.verticalKernelMap.GetKernel(y - startY); - if (kernel.Left + kernel.Length > resizeWindow.Bottom) + if (kernel.StartIndex + kernel.Length > resizeWindow.Bottom) { resizeWindow.Slide(); } @@ -271,10 +271,11 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms for (int x = 0; x < width; x++) { - Span firstPassColumn = resizeWindow.GetColumnSpan(x); + Span firstPassColumn = resizeWindow.GetColumnSpan(x, kernel.StartIndex); + ref Vector4 rowStartReference = ref MemoryMarshal.GetReference(firstPassColumn); // Destination color components - Unsafe.Add(ref tempRowBase, x) = kernel.Convolve(firstPassColumn); + Unsafe.Add(ref tempRowBase, x) = kernel.ConvolveCore(ref rowStartReference); } Span targetRowSpan = destination.GetPixelRowSpan(y); diff --git a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeWindow.cs b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeWindow.cs index 05015dee20..ba5f9a9849 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeWindow.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeWindow.cs @@ -34,7 +34,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms private readonly ResizeKernelMap verticalKernelMap; - private readonly Rectangle workingRectangle; + private readonly Rectangle destWorkingRect; private readonly int diameter; @@ -45,7 +45,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms ResizeKernelMap horizontalKernelMap, ResizeKernelMap verticalKernelMap, int destWidth, - Rectangle workingRectangle, + Rectangle destWorkingRect, int startX) { this.configuration = configuration; @@ -54,7 +54,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms this.conversionModifiers = conversionModifiers; this.horizontalKernelMap = horizontalKernelMap; this.verticalKernelMap = verticalKernelMap; - this.workingRectangle = workingRectangle; + this.destWorkingRect = destWorkingRect; this.startX = startX; this.diameter = verticalKernelMap.MaxDiameter; @@ -65,9 +65,9 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms AllocationOptions.Clean); this.tempRowBuffer = configuration.MemoryAllocator.Allocate(this.sourceRectangle.Width); - this.Top = this.sourceRectangle.Top; + this.Top = 0; - this.Bottom = this.sourceRectangle.Bottom; + this.Bottom = this.sourceRectangle.Height; } public int Bottom { get; private set; } @@ -80,15 +80,25 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Span GetColumnSpan(int x) + public Span GetColumnSpan(int x, int startY) { - return this.buffer.GetRowSpan(x); + return this.buffer.GetRowSpan(x).Slice(startY); } public void Initialize() + { + this.Initialize(0, this.sourceRectangle.Height); + } + + public void Slide() + { + throw new InvalidOperationException("Shouldn't happen yet!"); + } + + private void Initialize(int top, int bottom) { Span tempRowSpan = this.tempRowBuffer.GetSpan(); - for (int y = 0; y < this.sourceRectangle.Height; y++) + for (int y = top; y < bottom; y++) { Span sourceRow = this.source.GetRowSpan(y); @@ -100,17 +110,12 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms ref Vector4 firstPassBaseRef = ref this.buffer.Span[y]; - for (int x = this.workingRectangle.Left; x < this.workingRectangle.Right; x++) + for (int x = this.destWorkingRect.Left; x < this.destWorkingRect.Right; x++) { ResizeKernel kernel = this.horizontalKernelMap.GetKernel(x - this.startX); Unsafe.Add(ref firstPassBaseRef, x * this.sourceRectangle.Height) = kernel.Convolve(tempRowSpan); } } } - - public void Slide() - { - throw new InvalidOperationException("Shouldn't happen yet!"); - } } } \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeKernelMapTests.ReferenceKernelMap.cs b/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeKernelMapTests.ReferenceKernelMap.cs index 7d842c4e1e..2c5914253a 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeKernelMapTests.ReferenceKernelMap.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeKernelMapTests.ReferenceKernelMap.cs @@ -104,7 +104,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms public static implicit operator ReferenceKernel(ResizeKernel orig) { - return new ReferenceKernel(orig.Left, orig.Values.ToArray()); + return new ReferenceKernel(orig.StartIndex, orig.Values.ToArray()); } } } diff --git a/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeKernelMapTests.cs b/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeKernelMapTests.cs index 9de8665869..1bd909e7ea 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeKernelMapTests.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeKernelMapTests.cs @@ -151,8 +151,8 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms referenceKernel.Length == kernel.Length, $"referenceKernel.Length != kernel.Length: {referenceKernel.Length} != {kernel.Length}"); Assert.True( - referenceKernel.Left == kernel.Left, - $"referenceKernel.Left != kernel.Left: {referenceKernel.Left} != {kernel.Left}"); + referenceKernel.Left == kernel.StartIndex, + $"referenceKernel.Left != kernel.Left: {referenceKernel.Left} != {kernel.StartIndex}"); float[] expectedValues = referenceKernel.Values; Span actualValues = kernel.Values;