|
|
|
@ -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<Vector4> firstPassPixelsTransposed = source.MemoryAllocator.Allocate2D<Vector4>(sourceHeight, width)) |
|
|
|
//using (Buffer2D<Vector4> firstPassPixelsTransposed = source.MemoryAllocator.Allocate2D<Vector4>(sourceHeight, width))
|
|
|
|
|
|
|
|
using (var resizeWindow = new ResizeWindowOld( |
|
|
|
configuration, |
|
|
|
sourceRectangle, |
|
|
|
conversionModifiers, |
|
|
|
this.horizontalKernelMap, |
|
|
|
this.verticalKernelMap, |
|
|
|
sourceHeight, |
|
|
|
width, |
|
|
|
minX, |
|
|
|
maxX, |
|
|
|
startX)) |
|
|
|
using (IMemoryOwner<Vector4> tempBuffer = source.MemoryAllocator.Allocate<Vector4>(Math.Max(source.Width, width))) |
|
|
|
{ |
|
|
|
firstPassPixelsTransposed.MemorySource.Clear(); |
|
|
|
Span<Vector4> tempRowSpan = tempBuffer.GetSpan().Slice(sourceX, source.Width - sourceX); |
|
|
|
|
|
|
|
for (int y = 0; y < sourceRectangle.Bottom; y++) |
|
|
|
{ |
|
|
|
Span<TPixel> sourceRow = source.GetPixelRowSpan(y).Slice(sourceX); |
|
|
|
Span<Vector4> tempRowSpan = tempBuffer.GetSpan().Slice(sourceX, source.Width - sourceX); |
|
|
|
|
|
|
|
PixelOperations<TPixel>.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<Vector4> tempColSpan = tempBuffer.GetSpan().Slice(0, width); |
|
|
|
@ -277,7 +275,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms |
|
|
|
|
|
|
|
for (int x = 0; x < width; x++) |
|
|
|
{ |
|
|
|
Span<Vector4> firstPassColumn = firstPassPixelsTransposed.GetRowSpan(x).Slice(sourceY); |
|
|
|
Span<Vector4> 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<Vector4> 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<Vector4>(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<TPixel>( |
|
|
|
Buffer2D<TPixel> source, |
|
|
|
Span<Vector4> tempRowSpan) |
|
|
|
where TPixel : struct, IPixel<TPixel> |
|
|
|
{ |
|
|
|
for (int y = this.sourceRectangle.Top; y < this.sourceRectangle.Bottom; y++) |
|
|
|
{ |
|
|
|
Span<TPixel> sourceRow = source.GetRowSpan(y).Slice(this.sourceRectangle.X); |
|
|
|
|
|
|
|
PixelOperations<TPixel>.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<Vector4> GetColumnSpan(int x) |
|
|
|
{ |
|
|
|
return this.buffer.GetRowSpan(x); |
|
|
|
} |
|
|
|
|
|
|
|
public void Dispose() |
|
|
|
{ |
|
|
|
this.buffer.Dispose(); |
|
|
|
} |
|
|
|
} |
|
|
|
} |