Browse Source

simplify ResizeWorker logic

af/merge-core
Anton Firszov 7 years ago
parent
commit
c86551021a
  1. 1
      src/ImageSharp/Memory/RowInterval.cs
  2. 18
      src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeProcessor.cs
  3. 37
      src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeWorker.cs

1
src/ImageSharp/Memory/RowInterval.cs

@ -38,7 +38,6 @@ namespace SixLabors.ImageSharp.Memory
/// </summary>
public int Height => this.Max - this.Min;
public static bool operator ==(RowInterval left, RowInterval right)
{
return left.Equals(right);

18
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 destWorkingRect = Rectangle.Intersect(
var targetWorkingRect = 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(
destWorkingRect,
targetWorkingRect,
configuration,
rows =>
{
@ -219,7 +219,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
source.GetPixelRowSpan((int)(((y - startY) * heightFactor) + sourceY));
Span<TPixel> targetRow = destination.GetPixelRowSpan(y);
for (int x = destWorkingRect.Left; x < destWorkingRect.Right; x++)
for (int x = targetWorkingRect.Left; x < targetWorkingRect.Right; x++)
{
// X coordinates of source points
targetRow[x] = sourceRow[(int)(((x - startX) * widthFactor) + sourceX)];
@ -237,8 +237,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
BufferArea<TPixel> sourceArea = source.PixelBuffer.GetArea(sourceRectangle);
// If we want to reintroduce processing:
// it's possible to launch multiple workers for different regions of the image
// To reintroduce parallel processing, we to launch multiple workers
// for different row intervals of the image.
using (var worker = new ResizeWorker<TPixel>(
configuration,
sourceArea,
@ -246,11 +246,13 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
this.horizontalKernelMap,
this.verticalKernelMap,
width,
destWorkingRect,
startX))
targetWorkingRect,
this.TargetRectangle.Location))
{
worker.Initialize();
worker.FillDestinationPixels(destWorkingRect.Top, destWorkingRect.Bottom, startY, destination.PixelBuffer);
var workingInterval = new RowInterval(targetWorkingRect.Top, targetWorkingRect.Bottom);
worker.FillDestinationPixels(workingInterval, destination.PixelBuffer);
}
}

37
src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeWorker.cs

@ -17,7 +17,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
internal class ResizeWorker<TPixel> : IDisposable
where TPixel : struct, IPixel<TPixel>
{
private readonly Buffer2D<Vector4> buffer;
private readonly Buffer2D<Vector4> transposedFirstPassBuffer;
private readonly Configuration configuration;
@ -29,8 +29,6 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
private readonly Rectangle sourceRectangle;
private readonly int startX;
private readonly IMemoryOwner<Vector4> tempRowBuffer;
private readonly IMemoryOwner<Vector4> tempColumnBuffer;
@ -39,7 +37,9 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
private readonly int destWidth;
private readonly Rectangle destWorkingRect;
private readonly Rectangle targetWorkingRect;
private readonly Point targetOrigin;
private readonly int windowBandDiameter;
@ -54,8 +54,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
ResizeKernelMap horizontalKernelMap,
ResizeKernelMap verticalKernelMap,
int destWidth,
Rectangle destWorkingRect,
int startX)
Rectangle targetWorkingRect,
Point targetOrigin)
{
this.configuration = configuration;
this.source = source;
@ -64,8 +64,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
this.horizontalKernelMap = horizontalKernelMap;
this.verticalKernelMap = verticalKernelMap;
this.destWidth = destWidth;
this.destWorkingRect = destWorkingRect;
this.startX = startX;
this.targetWorkingRect = targetWorkingRect;
this.targetOrigin = targetOrigin;
this.windowBandDiameter = verticalKernelMap.MaxDiameter;
@ -76,7 +76,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
this.windowHeight = Math.Min(this.sourceRectangle.Height, numberOfWindowBands * this.windowBandDiameter);
this.buffer = configuration.MemoryAllocator.Allocate2D<Vector4>(
this.transposedFirstPassBuffer = configuration.MemoryAllocator.Allocate2D<Vector4>(
this.windowHeight,
destWidth,
AllocationOptions.Clean);
@ -89,7 +89,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
public void Dispose()
{
this.buffer.Dispose();
this.transposedFirstPassBuffer.Dispose();
this.tempRowBuffer.Dispose();
this.tempColumnBuffer.Dispose();
}
@ -97,23 +97,22 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Span<Vector4> GetColumnSpan(int x, int startY)
{
return this.buffer.GetRowSpan(x).Slice(startY - this.currentWindow.Min);
return this.transposedFirstPassBuffer.GetRowSpan(x).Slice(startY - this.currentWindow.Min);
}
public void Initialize()
{
this.CalculateFirstPassValues(this.currentWindow);
}
public void FillDestinationPixels(int minY, int maxY, int startY, Buffer2D<TPixel> destination)
public void FillDestinationPixels(RowInterval rowInterval, Buffer2D<TPixel> destination)
{
Span<Vector4> tempColSpan = this.tempColumnBuffer.GetSpan();
for (int y = minY; y < maxY; y++)
for (int y = rowInterval.Min; y < rowInterval.Max; y++)
{
// Ensure offsets are normalized for cropping and padding.
ResizeKernel kernel = this.verticalKernelMap.GetKernel(y - startY);
ResizeKernel kernel = this.verticalKernelMap.GetKernel(y - this.targetOrigin.Y);
while (kernel.StartIndex + kernel.Length > this.currentWindow.Max)
{
@ -141,7 +140,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private Span<Vector4> GetColumnSpan(int x)
{
return this.buffer.GetRowSpan(x);
return this.transposedFirstPassBuffer.GetRowSpan(x);
}
private void Slide()
@ -166,11 +165,11 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
this.conversionModifiers);
// ref Vector4 firstPassBaseRef = ref this.buffer.Span[y - top];
Span<Vector4> firstPassSpan = this.buffer.Span.Slice(y - window.Min);
Span<Vector4> firstPassSpan = this.transposedFirstPassBuffer.Span.Slice(y - window.Min);
for (int x = this.destWorkingRect.Left; x < this.destWorkingRect.Right; x++)
for (int x = this.targetWorkingRect.Left; x < this.targetWorkingRect.Right; x++)
{
ResizeKernel kernel = this.horizontalKernelMap.GetKernel(x - this.startX);
ResizeKernel kernel = this.horizontalKernelMap.GetKernel(x - this.targetOrigin.X);
firstPassSpan[x * this.windowHeight] = kernel.Convolve(tempRowSpan);
// Unsafe.Add(ref firstPassBaseRef, x * this.sourceRectangle.Height) = kernel.Convolve(tempRowSpan);

Loading…
Cancel
Save