|
|
@ -5,6 +5,7 @@ using System; |
|
|
using System.Buffers; |
|
|
using System.Buffers; |
|
|
using System.Numerics; |
|
|
using System.Numerics; |
|
|
using System.Runtime.CompilerServices; |
|
|
using System.Runtime.CompilerServices; |
|
|
|
|
|
using System.Runtime.InteropServices; |
|
|
|
|
|
|
|
|
using SixLabors.ImageSharp.Memory; |
|
|
using SixLabors.ImageSharp.Memory; |
|
|
using SixLabors.ImageSharp.PixelFormats; |
|
|
using SixLabors.ImageSharp.PixelFormats; |
|
|
@ -13,7 +14,7 @@ using SixLabors.Primitives; |
|
|
|
|
|
|
|
|
namespace SixLabors.ImageSharp.Processing.Processors.Transforms |
|
|
namespace SixLabors.ImageSharp.Processing.Processors.Transforms |
|
|
{ |
|
|
{ |
|
|
internal class ResizeWindow<TPixel> : IDisposable |
|
|
internal class ResizeWorker<TPixel> : IDisposable |
|
|
where TPixel : struct, IPixel<TPixel> |
|
|
where TPixel : struct, IPixel<TPixel> |
|
|
{ |
|
|
{ |
|
|
private readonly Buffer2D<Vector4> buffer; |
|
|
private readonly Buffer2D<Vector4> buffer; |
|
|
@ -32,15 +33,19 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms |
|
|
|
|
|
|
|
|
private readonly IMemoryOwner<Vector4> tempRowBuffer; |
|
|
private readonly IMemoryOwner<Vector4> tempRowBuffer; |
|
|
|
|
|
|
|
|
|
|
|
private readonly IMemoryOwner<Vector4> tempColumnBuffer; |
|
|
|
|
|
|
|
|
private readonly ResizeKernelMap verticalKernelMap; |
|
|
private readonly ResizeKernelMap verticalKernelMap; |
|
|
|
|
|
|
|
|
|
|
|
private readonly int destWidth; |
|
|
|
|
|
|
|
|
private readonly Rectangle destWorkingRect; |
|
|
private readonly Rectangle destWorkingRect; |
|
|
|
|
|
|
|
|
private readonly int diameter; |
|
|
private readonly int diameter; |
|
|
|
|
|
|
|
|
private readonly int windowHeight; |
|
|
private readonly int windowHeight; |
|
|
|
|
|
|
|
|
public ResizeWindow( |
|
|
public ResizeWorker( |
|
|
Configuration configuration, |
|
|
Configuration configuration, |
|
|
BufferArea<TPixel> source, |
|
|
BufferArea<TPixel> source, |
|
|
PixelConversionModifiers conversionModifiers, |
|
|
PixelConversionModifiers conversionModifiers, |
|
|
@ -56,6 +61,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms |
|
|
this.conversionModifiers = conversionModifiers; |
|
|
this.conversionModifiers = conversionModifiers; |
|
|
this.horizontalKernelMap = horizontalKernelMap; |
|
|
this.horizontalKernelMap = horizontalKernelMap; |
|
|
this.verticalKernelMap = verticalKernelMap; |
|
|
this.verticalKernelMap = verticalKernelMap; |
|
|
|
|
|
this.destWidth = destWidth; |
|
|
this.destWorkingRect = destWorkingRect; |
|
|
this.destWorkingRect = destWorkingRect; |
|
|
this.startX = startX; |
|
|
this.startX = startX; |
|
|
|
|
|
|
|
|
@ -67,22 +73,29 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms |
|
|
this.windowHeight, |
|
|
this.windowHeight, |
|
|
destWidth, |
|
|
destWidth, |
|
|
AllocationOptions.Clean); |
|
|
AllocationOptions.Clean); |
|
|
|
|
|
|
|
|
this.tempRowBuffer = configuration.MemoryAllocator.Allocate<Vector4>(this.sourceRectangle.Width); |
|
|
this.tempRowBuffer = configuration.MemoryAllocator.Allocate<Vector4>(this.sourceRectangle.Width); |
|
|
|
|
|
this.tempColumnBuffer = configuration.MemoryAllocator.Allocate<Vector4>(destWidth); |
|
|
|
|
|
|
|
|
|
|
|
this.CurrentMinY = 0; |
|
|
|
|
|
this.CurrentMaxY = this.windowHeight; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
public int Bottom { get; private set; } |
|
|
public int CurrentMaxY { get; private set; } |
|
|
|
|
|
|
|
|
public int Top { get; private set; } |
|
|
public int CurrentMinY { get; private set; } |
|
|
|
|
|
|
|
|
public void Dispose() |
|
|
public void Dispose() |
|
|
{ |
|
|
{ |
|
|
this.buffer.Dispose(); |
|
|
this.buffer.Dispose(); |
|
|
|
|
|
this.tempRowBuffer.Dispose(); |
|
|
|
|
|
this.tempColumnBuffer.Dispose(); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|
|
public Span<Vector4> GetColumnSpan(int x, int startY) |
|
|
public Span<Vector4> GetColumnSpan(int x, int startY) |
|
|
{ |
|
|
{ |
|
|
return this.buffer.GetRowSpan(x).Slice(startY - this.Top); |
|
|
return this.buffer.GetRowSpan(x).Slice(startY - this.CurrentMinY); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|
|
@ -93,23 +106,52 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms |
|
|
|
|
|
|
|
|
public void Initialize() |
|
|
public void Initialize() |
|
|
{ |
|
|
{ |
|
|
this.Initialize(0, this.windowHeight); |
|
|
this.CalculateFirstPassValues(0, this.windowHeight); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
public void Slide() |
|
|
public void FillDestinationPixels(int minY, int maxY, int startY, Buffer2D<TPixel> destination) |
|
|
{ |
|
|
{ |
|
|
int top = this.Top + this.diameter; |
|
|
Span<Vector4> tempColSpan = this.tempColumnBuffer.GetSpan(); |
|
|
int bottom = Math.Min(this.Bottom + this.diameter, this.sourceRectangle.Height); |
|
|
|
|
|
this.Initialize(top, bottom); |
|
|
for (int y = minY; y < maxY; y++) |
|
|
|
|
|
{ |
|
|
|
|
|
// Ensure offsets are normalized for cropping and padding.
|
|
|
|
|
|
ResizeKernel kernel = this.verticalKernelMap.GetKernel(y - startY); |
|
|
|
|
|
|
|
|
|
|
|
while (kernel.StartIndex + kernel.Length > this.CurrentMaxY) |
|
|
|
|
|
{ |
|
|
|
|
|
this.Slide(); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
ref Vector4 tempRowBase = ref MemoryMarshal.GetReference(tempColSpan); |
|
|
|
|
|
|
|
|
|
|
|
int top = kernel.StartIndex - this.CurrentMinY; |
|
|
|
|
|
|
|
|
|
|
|
for (int x = 0; x < this.destWidth; x++) |
|
|
|
|
|
{ |
|
|
|
|
|
Span<Vector4> firstPassColumn = this.GetColumnSpan(x).Slice(top); |
|
|
|
|
|
|
|
|
|
|
|
// Destination color components
|
|
|
|
|
|
Unsafe.Add(ref tempRowBase, x) = kernel.ConvolveCore(firstPassColumn); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
Span<TPixel> targetRowSpan = destination.GetRowSpan(y); |
|
|
|
|
|
|
|
|
|
|
|
PixelOperations<TPixel>.Instance.FromVector4Destructive(configuration, tempColSpan, targetRowSpan, conversionModifiers); |
|
|
|
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
private void Initialize(int top, int bottom) |
|
|
public void Slide() |
|
|
{ |
|
|
{ |
|
|
this.Top = top; |
|
|
this.CurrentMinY = this.CurrentMinY + this.diameter; |
|
|
this.Bottom = bottom; |
|
|
this.CurrentMaxY = Math.Min(this.CurrentMaxY + this.diameter, this.sourceRectangle.Height); |
|
|
|
|
|
this.CalculateFirstPassValues(this.CurrentMinY, this.CurrentMaxY); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private void CalculateFirstPassValues(int minY, int maxY) |
|
|
|
|
|
{ |
|
|
Span<Vector4> tempRowSpan = this.tempRowBuffer.GetSpan(); |
|
|
Span<Vector4> tempRowSpan = this.tempRowBuffer.GetSpan(); |
|
|
for (int y = top; y < bottom; y++) |
|
|
for (int y = minY; y < maxY; y++) |
|
|
{ |
|
|
{ |
|
|
Span<TPixel> sourceRow = this.source.GetRowSpan(y); |
|
|
Span<TPixel> sourceRow = this.source.GetRowSpan(y); |
|
|
|
|
|
|
|
|
@ -120,7 +162,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms |
|
|
this.conversionModifiers); |
|
|
this.conversionModifiers); |
|
|
|
|
|
|
|
|
//ref Vector4 firstPassBaseRef = ref this.buffer.Span[y - top];
|
|
|
//ref Vector4 firstPassBaseRef = ref this.buffer.Span[y - top];
|
|
|
Span<Vector4> firstPassSpan = this.buffer.Span.Slice(y - top); |
|
|
Span<Vector4> firstPassSpan = this.buffer.Span.Slice(y - minY); |
|
|
|
|
|
|
|
|
for (int x = this.destWorkingRect.Left; x < this.destWorkingRect.Right; x++) |
|
|
for (int x = this.destWorkingRect.Left; x < this.destWorkingRect.Right; x++) |
|
|
{ |
|
|
{ |