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> /// </summary>
public int Height => this.Max - this.Min; public int Height => this.Max - this.Min;
public static bool operator ==(RowInterval left, RowInterval right) public static bool operator ==(RowInterval left, RowInterval right)
{ {
return left.Equals(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 startY = this.TargetRectangle.Y;
int startX = this.TargetRectangle.X; int startX = this.TargetRectangle.X;
var destWorkingRect = Rectangle.Intersect( var targetWorkingRect = Rectangle.Intersect(
this.TargetRectangle, this.TargetRectangle,
new Rectangle(0, 0, width, height)); new Rectangle(0, 0, width, height));
@ -208,7 +208,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
float heightFactor = sourceRectangle.Height / (float)this.TargetRectangle.Height; float heightFactor = sourceRectangle.Height / (float)this.TargetRectangle.Height;
ParallelHelper.IterateRows( ParallelHelper.IterateRows(
destWorkingRect, targetWorkingRect,
configuration, configuration,
rows => rows =>
{ {
@ -219,7 +219,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
source.GetPixelRowSpan((int)(((y - startY) * heightFactor) + sourceY)); source.GetPixelRowSpan((int)(((y - startY) * heightFactor) + sourceY));
Span<TPixel> targetRow = destination.GetPixelRowSpan(y); 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 // X coordinates of source points
targetRow[x] = sourceRow[(int)(((x - startX) * widthFactor) + sourceX)]; 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); BufferArea<TPixel> sourceArea = source.PixelBuffer.GetArea(sourceRectangle);
// If we want to reintroduce processing: // To reintroduce parallel processing, we to launch multiple workers
// it's possible to launch multiple workers for different regions of the image // for different row intervals of the image.
using (var worker = new ResizeWorker<TPixel>( using (var worker = new ResizeWorker<TPixel>(
configuration, configuration,
sourceArea, sourceArea,
@ -246,11 +246,13 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
this.horizontalKernelMap, this.horizontalKernelMap,
this.verticalKernelMap, this.verticalKernelMap,
width, width,
destWorkingRect, targetWorkingRect,
startX)) this.TargetRectangle.Location))
{ {
worker.Initialize(); 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 internal class ResizeWorker<TPixel> : IDisposable
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
private readonly Buffer2D<Vector4> buffer; private readonly Buffer2D<Vector4> transposedFirstPassBuffer;
private readonly Configuration configuration; private readonly Configuration configuration;
@ -29,8 +29,6 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
private readonly Rectangle sourceRectangle; private readonly Rectangle sourceRectangle;
private readonly int startX;
private readonly IMemoryOwner<Vector4> tempRowBuffer; private readonly IMemoryOwner<Vector4> tempRowBuffer;
private readonly IMemoryOwner<Vector4> tempColumnBuffer; private readonly IMemoryOwner<Vector4> tempColumnBuffer;
@ -39,7 +37,9 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
private readonly int destWidth; private readonly int destWidth;
private readonly Rectangle destWorkingRect; private readonly Rectangle targetWorkingRect;
private readonly Point targetOrigin;
private readonly int windowBandDiameter; private readonly int windowBandDiameter;
@ -54,8 +54,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
ResizeKernelMap horizontalKernelMap, ResizeKernelMap horizontalKernelMap,
ResizeKernelMap verticalKernelMap, ResizeKernelMap verticalKernelMap,
int destWidth, int destWidth,
Rectangle destWorkingRect, Rectangle targetWorkingRect,
int startX) Point targetOrigin)
{ {
this.configuration = configuration; this.configuration = configuration;
this.source = source; this.source = source;
@ -64,8 +64,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
this.horizontalKernelMap = horizontalKernelMap; this.horizontalKernelMap = horizontalKernelMap;
this.verticalKernelMap = verticalKernelMap; this.verticalKernelMap = verticalKernelMap;
this.destWidth = destWidth; this.destWidth = destWidth;
this.destWorkingRect = destWorkingRect; this.targetWorkingRect = targetWorkingRect;
this.startX = startX; this.targetOrigin = targetOrigin;
this.windowBandDiameter = verticalKernelMap.MaxDiameter; 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.windowHeight = Math.Min(this.sourceRectangle.Height, numberOfWindowBands * this.windowBandDiameter);
this.buffer = configuration.MemoryAllocator.Allocate2D<Vector4>( this.transposedFirstPassBuffer = configuration.MemoryAllocator.Allocate2D<Vector4>(
this.windowHeight, this.windowHeight,
destWidth, destWidth,
AllocationOptions.Clean); AllocationOptions.Clean);
@ -89,7 +89,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
public void Dispose() public void Dispose()
{ {
this.buffer.Dispose(); this.transposedFirstPassBuffer.Dispose();
this.tempRowBuffer.Dispose(); this.tempRowBuffer.Dispose();
this.tempColumnBuffer.Dispose(); this.tempColumnBuffer.Dispose();
} }
@ -97,23 +97,22 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
[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.currentWindow.Min); return this.transposedFirstPassBuffer.GetRowSpan(x).Slice(startY - this.currentWindow.Min);
} }
public void Initialize() public void Initialize()
{ {
this.CalculateFirstPassValues(this.currentWindow); 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(); 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. // 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) while (kernel.StartIndex + kernel.Length > this.currentWindow.Max)
{ {
@ -141,7 +140,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
private Span<Vector4> GetColumnSpan(int x) private Span<Vector4> GetColumnSpan(int x)
{ {
return this.buffer.GetRowSpan(x); return this.transposedFirstPassBuffer.GetRowSpan(x);
} }
private void Slide() private void Slide()
@ -166,11 +165,11 @@ 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 - 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); firstPassSpan[x * this.windowHeight] = kernel.Convolve(tempRowSpan);
// Unsafe.Add(ref firstPassBaseRef, x * this.sourceRectangle.Height) = kernel.Convolve(tempRowSpan); // Unsafe.Add(ref firstPassBaseRef, x * this.sourceRectangle.Height) = kernel.Convolve(tempRowSpan);

Loading…
Cancel
Save