Browse Source

ResizeWindow refactor 4

pull/888/head
Anton Firszov 7 years ago
parent
commit
20ddd11e5f
  1. 29
      src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernel.cs
  2. 17
      src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeProcessor.cs
  3. 33
      src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeWindow.cs
  4. 2
      tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeKernelMapTests.ReferenceKernelMap.cs
  5. 4
      tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeKernelMapTests.cs

29
src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernel.cs

@ -19,27 +19,27 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
/// Initializes a new instance of the <see cref="ResizeKernel"/> struct. /// Initializes a new instance of the <see cref="ResizeKernel"/> struct.
/// </summary> /// </summary>
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
internal ResizeKernel(int left, float* bufferPtr, int length) internal ResizeKernel(int startIndex, float* bufferPtr, int length)
{ {
this.Left = left; this.StartIndex = startIndex;
this.bufferPtr = bufferPtr; this.bufferPtr = bufferPtr;
this.Length = length; this.Length = length;
} }
/// <summary> /// <summary>
/// Gets the left index for the destination row /// Gets the start index for the destination row.
/// </summary> /// </summary>
public int Left { get; } public int StartIndex { get; }
/// <summary> /// <summary>
/// Gets the the length of the kernel /// Gets the the length of the kernel.
/// </summary> /// </summary>
public int Length { get; } public int Length { get; }
/// <summary> /// <summary>
/// Gets the span representing the portion of the <see cref="ResizeKernelMap"/> that this window covers /// Gets the span representing the portion of the <see cref="ResizeKernelMap"/> that this window covers.
/// </summary> /// </summary>
/// <value>The <see cref="Span{T}"/> /// <value>The <see cref="Span{T}"/>.
/// </value> /// </value>
public Span<float> Values public Span<float> Values
{ {
@ -55,17 +55,22 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
public Vector4 Convolve(Span<Vector4> rowSpan) public Vector4 Convolve(Span<Vector4> rowSpan)
{ {
ref float horizontalValues = ref Unsafe.AsRef<float>(this.bufferPtr); ref Vector4 vecPtr = ref Unsafe.Add(ref MemoryMarshal.GetReference(rowSpan), this.StartIndex);
int left = this.Left;
ref Vector4 vecPtr = ref Unsafe.Add(ref MemoryMarshal.GetReference(rowSpan), left); return this.ConvolveCore(ref vecPtr);
}
[MethodImpl(InliningOptions.ShortMethod)]
public Vector4 ConvolveCore(ref Vector4 rowStartRef)
{
ref float horizontalValues = ref Unsafe.AsRef<float>(this.bufferPtr);
// Destination color components // Destination color components
Vector4 result = Vector4.Zero; Vector4 result = Vector4.Zero;
for (int i = 0; i < this.Length; i++) for (int i = 0; i < this.Length; i++)
{ {
float weight = Unsafe.Add(ref horizontalValues, i); float weight = Unsafe.Add(ref horizontalValues, i);
Vector4 v = Unsafe.Add(ref vecPtr, i); Vector4 v = Unsafe.Add(ref rowStartRef, i);
result += v * weight; result += v * weight;
} }
@ -73,7 +78,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
} }
/// <summary> /// <summary>
/// Copy the contents of <see cref="ResizeKernel"/> altering <see cref="Left"/> /// Copy the contents of <see cref="ResizeKernel"/> altering <see cref="StartIndex"/>
/// to the value <paramref name="left"/>. /// to the value <paramref name="left"/>.
/// </summary> /// </summary>
internal ResizeKernel AlterLeftValue(int left) internal ResizeKernel AlterLeftValue(int left)

17
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 workingRect = Rectangle.Intersect( var destWorkingRect = 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(
workingRect, destWorkingRect,
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 = workingRect.Left; x < workingRect.Right; x++) for (int x = destWorkingRect.Left; x < destWorkingRect.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)];
@ -248,7 +248,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
this.horizontalKernelMap, this.horizontalKernelMap,
this.verticalKernelMap, this.verticalKernelMap,
width, width,
workingRect, destWorkingRect,
startX)) startX))
using (IMemoryOwner<Vector4> tempBuffer = source.MemoryAllocator.Allocate<Vector4>(width)) using (IMemoryOwner<Vector4> tempBuffer = source.MemoryAllocator.Allocate<Vector4>(width))
{ {
@ -257,12 +257,12 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
// Now process the rows. // Now process the rows.
Span<Vector4> tempColSpan = tempBuffer.GetSpan(); Span<Vector4> tempColSpan = tempBuffer.GetSpan();
for (int y = workingRect.Top; y < workingRect.Bottom; y++) for (int y = destWorkingRect.Top; y < destWorkingRect.Bottom; 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 - startY);
if (kernel.Left + kernel.Length > resizeWindow.Bottom) if (kernel.StartIndex + kernel.Length > resizeWindow.Bottom)
{ {
resizeWindow.Slide(); resizeWindow.Slide();
} }
@ -271,10 +271,11 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
for (int x = 0; x < width; x++) for (int x = 0; x < width; x++)
{ {
Span<Vector4> firstPassColumn = resizeWindow.GetColumnSpan(x); Span<Vector4> firstPassColumn = resizeWindow.GetColumnSpan(x, kernel.StartIndex);
ref Vector4 rowStartReference = ref MemoryMarshal.GetReference(firstPassColumn);
// Destination color components // Destination color components
Unsafe.Add(ref tempRowBase, x) = kernel.Convolve(firstPassColumn); Unsafe.Add(ref tempRowBase, x) = kernel.ConvolveCore(ref rowStartReference);
} }
Span<TPixel> targetRowSpan = destination.GetPixelRowSpan(y); Span<TPixel> targetRowSpan = destination.GetPixelRowSpan(y);

33
src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeWindow.cs

@ -34,7 +34,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
private readonly ResizeKernelMap verticalKernelMap; private readonly ResizeKernelMap verticalKernelMap;
private readonly Rectangle workingRectangle; private readonly Rectangle destWorkingRect;
private readonly int diameter; private readonly int diameter;
@ -45,7 +45,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
ResizeKernelMap horizontalKernelMap, ResizeKernelMap horizontalKernelMap,
ResizeKernelMap verticalKernelMap, ResizeKernelMap verticalKernelMap,
int destWidth, int destWidth,
Rectangle workingRectangle, Rectangle destWorkingRect,
int startX) int startX)
{ {
this.configuration = configuration; this.configuration = configuration;
@ -54,7 +54,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.workingRectangle = workingRectangle; this.destWorkingRect = destWorkingRect;
this.startX = startX; this.startX = startX;
this.diameter = verticalKernelMap.MaxDiameter; this.diameter = verticalKernelMap.MaxDiameter;
@ -65,9 +65,9 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
AllocationOptions.Clean); AllocationOptions.Clean);
this.tempRowBuffer = configuration.MemoryAllocator.Allocate<Vector4>(this.sourceRectangle.Width); this.tempRowBuffer = configuration.MemoryAllocator.Allocate<Vector4>(this.sourceRectangle.Width);
this.Top = this.sourceRectangle.Top; this.Top = 0;
this.Bottom = this.sourceRectangle.Bottom; this.Bottom = this.sourceRectangle.Height;
} }
public int Bottom { get; private set; } public int Bottom { get; private set; }
@ -80,15 +80,25 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public Span<Vector4> GetColumnSpan(int x) public Span<Vector4> GetColumnSpan(int x, int startY)
{ {
return this.buffer.GetRowSpan(x); return this.buffer.GetRowSpan(x).Slice(startY);
} }
public void Initialize() public void Initialize()
{
this.Initialize(0, this.sourceRectangle.Height);
}
public void Slide()
{
throw new InvalidOperationException("Shouldn't happen yet!");
}
private void Initialize(int top, int bottom)
{ {
Span<Vector4> tempRowSpan = this.tempRowBuffer.GetSpan(); Span<Vector4> tempRowSpan = this.tempRowBuffer.GetSpan();
for (int y = 0; y < this.sourceRectangle.Height; y++) for (int y = top; y < bottom; y++)
{ {
Span<TPixel> sourceRow = this.source.GetRowSpan(y); Span<TPixel> sourceRow = this.source.GetRowSpan(y);
@ -100,17 +110,12 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
ref Vector4 firstPassBaseRef = ref this.buffer.Span[y]; ref Vector4 firstPassBaseRef = ref this.buffer.Span[y];
for (int x = this.workingRectangle.Left; x < this.workingRectangle.Right; x++) for (int x = this.destWorkingRect.Left; x < this.destWorkingRect.Right; x++)
{ {
ResizeKernel kernel = this.horizontalKernelMap.GetKernel(x - this.startX); ResizeKernel kernel = this.horizontalKernelMap.GetKernel(x - this.startX);
Unsafe.Add(ref firstPassBaseRef, x * this.sourceRectangle.Height) = kernel.Convolve(tempRowSpan); Unsafe.Add(ref firstPassBaseRef, x * this.sourceRectangle.Height) = kernel.Convolve(tempRowSpan);
} }
} }
} }
public void Slide()
{
throw new InvalidOperationException("Shouldn't happen yet!");
}
} }
} }

2
tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeKernelMapTests.ReferenceKernelMap.cs

@ -104,7 +104,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms
public static implicit operator ReferenceKernel(ResizeKernel orig) public static implicit operator ReferenceKernel(ResizeKernel orig)
{ {
return new ReferenceKernel(orig.Left, orig.Values.ToArray()); return new ReferenceKernel(orig.StartIndex, orig.Values.ToArray());
} }
} }
} }

4
tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeKernelMapTests.cs

@ -151,8 +151,8 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms
referenceKernel.Length == kernel.Length, referenceKernel.Length == kernel.Length,
$"referenceKernel.Length != kernel.Length: {referenceKernel.Length} != {kernel.Length}"); $"referenceKernel.Length != kernel.Length: {referenceKernel.Length} != {kernel.Length}");
Assert.True( Assert.True(
referenceKernel.Left == kernel.Left, referenceKernel.Left == kernel.StartIndex,
$"referenceKernel.Left != kernel.Left: {referenceKernel.Left} != {kernel.Left}"); $"referenceKernel.Left != kernel.Left: {referenceKernel.Left} != {kernel.StartIndex}");
float[] expectedValues = referenceKernel.Values; float[] expectedValues = referenceKernel.Values;
Span<float> actualValues = kernel.Values; Span<float> actualValues = kernel.Values;

Loading…
Cancel
Save