diff --git a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernel.cs b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernel.cs index 04bf6c3a44..f349634ac0 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernel.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernel.cs @@ -80,5 +80,15 @@ internal ResizeKernel AlterLeftValue(int left) { return new ResizeKernel(left, this.bufferPtr, this.Length); } + + internal void Fill(Span values) + { + DebugGuard.IsTrue(values.Length == this.Length, nameof(values), "ResizeKernel.Fill: values.Length != this.Length!"); + + for (int i = 0; i < this.Length; i++) + { + this.Values[i] = (float)values[i]; + } + } } } \ No newline at end of file diff --git a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.PeriodicKernelMap.cs b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.PeriodicKernelMap.cs index b7b581c185..e0f5ad2613 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.PeriodicKernelMap.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.PeriodicKernelMap.cs @@ -26,8 +26,8 @@ public PeriodicKernelMap( IResampler sampler, int sourceLength, int destinationLength, - float ratio, - float scale, + double ratio, + double scale, int radius, int period, int cornerInterval) @@ -62,8 +62,8 @@ protected override void Initialize() int bottomStartDest = this.DestinationLength - this.cornerInterval; for (int i = startOfFirstRepeatedMosaic; i < bottomStartDest; i++) { - float center = ((i + .5F) * this.ratio) - .5F; - int left = (int)MathF.Ceiling(center - this.radius); + double center = ((i + .5) * this.ratio) - .5; + int left = (int)Math.Ceiling(center - this.radius); ResizeKernel kernel = this.kernels[i - this.period]; this.kernels[i] = kernel.AlterLeftValue(left); } diff --git a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.cs b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.cs index 011a4ffa22..4cd9928d30 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.cs @@ -17,13 +17,15 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms /// internal partial class ResizeKernelMap : IDisposable { + private readonly MemoryAllocator memoryAllocator; + private readonly IResampler sampler; private readonly int sourceLength; - private readonly float ratio; + private readonly double ratio; - private readonly float scale; + private readonly double scale; private readonly int radius; @@ -39,10 +41,11 @@ private ResizeKernelMap( int sourceLength, int destinationLength, int bufferHeight, - float ratio, - float scale, + double ratio, + double scale, int radius) { + this.memoryAllocator = memoryAllocator; this.sampler = sampler; this.ratio = ratio; this.scale = scale; @@ -95,19 +98,19 @@ public static ResizeKernelMap Calculate( int sourceSize, MemoryAllocator memoryAllocator) { - float ratio = (float)sourceSize / destinationSize; - float scale = ratio; + double ratio = (double)sourceSize / destinationSize; + double scale = ratio; if (scale < 1F) { scale = 1F; } - int radius = (int)MathF.Ceiling(scale * sampler.Radius); + int radius = (int)Math.Ceiling(scale * sampler.Radius); int period = ImageMaths.LeastCommonMultiple(sourceSize, destinationSize) / sourceSize; - float center0 = (ratio - 1) * 0.5f; - float firstNonNegativeLeftVal = (radius - center0 - 1) / ratio; - int cornerInterval = (int)MathF.Ceiling(firstNonNegativeLeftVal); + double center0 = (ratio - 1) * 0.5f; + double firstNonNegativeLeftVal = (radius - center0 - 1) / ratio; + int cornerInterval = (int)Math.Ceiling(firstNonNegativeLeftVal); // corner case for cornerInteval: if (firstNonNegativeLeftVal == cornerInterval) @@ -159,45 +162,48 @@ protected virtual void Initialize() /// private ResizeKernel BuildKernel(int destRowIndex, int dataRowIndex) { - float center = ((destRowIndex + .5F) * this.ratio) - .5F; + double center = ((destRowIndex + .5) * this.ratio) - .5; // Keep inside bounds. - int left = (int)MathF.Ceiling(center - this.radius); + int left = (int)Math.Ceiling(center - this.radius); if (left < 0) { left = 0; } - int right = (int)MathF.Floor(center + this.radius); + int right = (int)Math.Floor(center + this.radius); if (right > this.sourceLength - 1) { right = this.sourceLength - 1; } - float sum = 0; - ResizeKernel kernel = this.CreateKernel(dataRowIndex, left, right); - ref float kernelBaseRef = ref MemoryMarshal.GetReference(kernel.Values); - - for (int j = left; j <= right; j++) + using (IMemoryOwner tempBuffer = this.memoryAllocator.Allocate(kernel.Length)) { - float value = this.sampler.GetValue((j - center) / this.scale); - sum += value; + Span kernelValues = tempBuffer.GetSpan(); + double sum = 0; - // weights[j - left] = weight: - Unsafe.Add(ref kernelBaseRef, j - left) = value; - } + for (int j = left; j <= right; j++) + { + double value = this.sampler.GetValue((float)((j - center) / this.scale)); + sum += value; - // Normalize, best to do it here rather than in the pixel loop later on. - if (sum > 0) - { - for (int w = 0; w < kernel.Length; w++) + kernelValues[j - left] = value; + } + + // Normalize, best to do it here rather than in the pixel loop later on. + if (sum > 0) { - // weights[w] = weights[w] / sum: - ref float kRef = ref Unsafe.Add(ref kernelBaseRef, w); - kRef /= sum; + for (int j = 0; j < kernel.Length; j++) + { + // weights[w] = weights[w] / sum: + ref double kRef = ref kernelValues[j]; + kRef /= sum; + } } + + kernel.Fill(kernelValues); } return kernel;