|
|
@ -2,6 +2,7 @@ |
|
|
// Licensed under the Apache License, Version 2.0.
|
|
|
// Licensed under the Apache License, Version 2.0.
|
|
|
|
|
|
|
|
|
using System; |
|
|
using System; |
|
|
|
|
|
using System.Buffers; |
|
|
using System.Runtime.CompilerServices; |
|
|
using System.Runtime.CompilerServices; |
|
|
using System.Runtime.InteropServices; |
|
|
using System.Runtime.InteropServices; |
|
|
|
|
|
|
|
|
@ -11,9 +12,10 @@ using SixLabors.Memory; |
|
|
namespace SixLabors.ImageSharp.Processing.Processors.Transforms |
|
|
namespace SixLabors.ImageSharp.Processing.Processors.Transforms |
|
|
{ |
|
|
{ |
|
|
/// <summary>
|
|
|
/// <summary>
|
|
|
/// Holds the <see cref="ResizeKernel"/> values in an optimized contigous memory region.
|
|
|
/// Provides <see cref="ResizeKernel"/> values from an optimized,
|
|
|
|
|
|
/// contigous memory region.
|
|
|
/// </summary>
|
|
|
/// </summary>
|
|
|
internal class KernelMap : IDisposable |
|
|
internal partial class ResizeKernelMap : IDisposable |
|
|
{ |
|
|
{ |
|
|
private readonly IResampler sampler; |
|
|
private readonly IResampler sampler; |
|
|
|
|
|
|
|
|
@ -25,11 +27,13 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms |
|
|
|
|
|
|
|
|
private readonly int radius; |
|
|
private readonly int radius; |
|
|
|
|
|
|
|
|
|
|
|
private readonly MemoryHandle pinHandle; |
|
|
|
|
|
|
|
|
private readonly Buffer2D<float> data; |
|
|
private readonly Buffer2D<float> data; |
|
|
|
|
|
|
|
|
private readonly ResizeKernel[] kernels; |
|
|
private readonly ResizeKernel[] kernels; |
|
|
|
|
|
|
|
|
private KernelMap( |
|
|
private ResizeKernelMap( |
|
|
MemoryAllocator memoryAllocator, |
|
|
MemoryAllocator memoryAllocator, |
|
|
IResampler sampler, |
|
|
IResampler sampler, |
|
|
int sourceSize, |
|
|
int sourceSize, |
|
|
@ -47,16 +51,18 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms |
|
|
this.DestinationSize = destinationSize; |
|
|
this.DestinationSize = destinationSize; |
|
|
int maxWidth = (radius * 2) + 1; |
|
|
int maxWidth = (radius * 2) + 1; |
|
|
this.data = memoryAllocator.Allocate2D<float>(maxWidth, bufferHeight, AllocationOptions.Clean); |
|
|
this.data = memoryAllocator.Allocate2D<float>(maxWidth, bufferHeight, AllocationOptions.Clean); |
|
|
|
|
|
this.pinHandle = this.data.Memory.Pin(); |
|
|
this.kernels = new ResizeKernel[destinationSize]; |
|
|
this.kernels = new ResizeKernel[destinationSize]; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
public int DestinationSize { get; } |
|
|
public int DestinationSize { get; } |
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
/// <summary>
|
|
|
/// Disposes <see cref="KernelMap"/> instance releasing it's backing buffer.
|
|
|
/// Disposes <see cref="ResizeKernelMap"/> instance releasing it's backing buffer.
|
|
|
/// </summary>
|
|
|
/// </summary>
|
|
|
public void Dispose() |
|
|
public void Dispose() |
|
|
{ |
|
|
{ |
|
|
|
|
|
this.pinHandle.Dispose(); |
|
|
this.data.Dispose(); |
|
|
this.data.Dispose(); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
@ -73,8 +79,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms |
|
|
/// <param name="destinationSize">The destination size</param>
|
|
|
/// <param name="destinationSize">The destination size</param>
|
|
|
/// <param name="sourceSize">The source size</param>
|
|
|
/// <param name="sourceSize">The source size</param>
|
|
|
/// <param name="memoryAllocator">The <see cref="MemoryAllocator"/> to use for buffer allocations</param>
|
|
|
/// <param name="memoryAllocator">The <see cref="MemoryAllocator"/> to use for buffer allocations</param>
|
|
|
/// <returns>The <see cref="KernelMap"/></returns>
|
|
|
/// <returns>The <see cref="ResizeKernelMap"/></returns>
|
|
|
public static KernelMap Calculate( |
|
|
public static ResizeKernelMap Calculate( |
|
|
IResampler sampler, |
|
|
IResampler sampler, |
|
|
int destinationSize, |
|
|
int destinationSize, |
|
|
int sourceSize, |
|
|
int sourceSize, |
|
|
@ -88,25 +94,40 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms |
|
|
scale = 1F; |
|
|
scale = 1F; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
int period = ImageMaths.LeastCommonMultiple(sourceSize, destinationSize) / sourceSize; |
|
|
|
|
|
int radius = (int)MathF.Ceiling(scale * sampler.Radius); |
|
|
int radius = (int)MathF.Ceiling(scale * sampler.Radius); |
|
|
|
|
|
int period = ImageMaths.LeastCommonMultiple(sourceSize, destinationSize) / sourceSize; |
|
|
var result = new KernelMap( |
|
|
float center0 = (ratio - 1) * 0.5f; |
|
|
memoryAllocator, |
|
|
int cornerInterval = (int)MathF.Ceiling((radius - center0 - 1) / ratio); |
|
|
sampler, |
|
|
|
|
|
sourceSize, |
|
|
bool useMosaic = 2 * (cornerInterval + period) < destinationSize; |
|
|
destinationSize, |
|
|
|
|
|
destinationSize, |
|
|
ResizeKernelMap result = useMosaic |
|
|
ratio, |
|
|
? new ResizeKernelMap( |
|
|
scale, |
|
|
memoryAllocator, |
|
|
radius); |
|
|
sampler, |
|
|
|
|
|
sourceSize, |
|
|
result.BasicInit(); |
|
|
destinationSize, |
|
|
|
|
|
destinationSize, |
|
|
|
|
|
ratio, |
|
|
|
|
|
scale, |
|
|
|
|
|
radius) |
|
|
|
|
|
: new MosaicKernelMap( |
|
|
|
|
|
memoryAllocator, |
|
|
|
|
|
sampler, |
|
|
|
|
|
sourceSize, |
|
|
|
|
|
destinationSize, |
|
|
|
|
|
ratio, |
|
|
|
|
|
scale, |
|
|
|
|
|
radius, |
|
|
|
|
|
period, |
|
|
|
|
|
cornerInterval); |
|
|
|
|
|
|
|
|
|
|
|
result.Init(); |
|
|
|
|
|
|
|
|
return result; |
|
|
return result; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
private void BasicInit() |
|
|
protected virtual void Init() |
|
|
{ |
|
|
{ |
|
|
for (int i = 0; i < this.DestinationSize; i++) |
|
|
for (int i = 0; i < this.DestinationSize; i++) |
|
|
{ |
|
|
{ |
|
|
@ -157,7 +178,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms |
|
|
/// <summary>
|
|
|
/// <summary>
|
|
|
/// Slices a weights value at the given positions.
|
|
|
/// Slices a weights value at the given positions.
|
|
|
/// </summary>
|
|
|
/// </summary>
|
|
|
private ResizeKernel CreateKernel(int destIdx, int left, int rightIdx) |
|
|
private unsafe ResizeKernel CreateKernel(int destIdx, int left, int rightIdx) |
|
|
{ |
|
|
{ |
|
|
int length = rightIdx - left + 1; |
|
|
int length = rightIdx - left + 1; |
|
|
|
|
|
|
|
|
@ -166,10 +187,11 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms |
|
|
throw new InvalidOperationException($"Error in KernelMap.CreateKernel({destIdx},{left},{rightIdx}): left > this.data.Width"); |
|
|
throw new InvalidOperationException($"Error in KernelMap.CreateKernel({destIdx},{left},{rightIdx}): left > this.data.Width"); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
int flatStartIndex = destIdx * this.data.Width; |
|
|
Span<float> rowSpan = this.data.GetRowSpan(destIdx); |
|
|
|
|
|
|
|
|
Memory<float> bufferSlice = this.data.Memory.Slice(flatStartIndex, length); |
|
|
ref float rowReference = ref MemoryMarshal.GetReference(rowSpan); |
|
|
return new ResizeKernel(left, bufferSlice); |
|
|
float* rowPtr = (float*)Unsafe.AsPointer(ref rowReference); |
|
|
|
|
|
return new ResizeKernel(left, rowPtr, length); |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |