Browse Source

ResizeWindow refactor 1

af/merge-core
Anton Firszov 7 years ago
parent
commit
fd7c5db66b
  1. 115
      src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeProcessor.cs
  2. 97
      src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeWindow.cs

115
src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeProcessor.cs

@ -195,19 +195,14 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
int sourceX = sourceRectangle.X; int sourceX = sourceRectangle.X;
int sourceY = sourceRectangle.Y; int sourceY = sourceRectangle.Y;
int startY = this.TargetRectangle.Y; int startY = this.TargetRectangle.Y;
int endY = this.TargetRectangle.Bottom;
int startX = this.TargetRectangle.X; int startX = this.TargetRectangle.X;
int endX = this.TargetRectangle.Right;
int minX = Math.Max(0, startX); var workingRect = Rectangle.Intersect(
int maxX = Math.Min(width, endX); this.TargetRectangle,
int minY = Math.Max(0, startY); new Rectangle(0, 0, width, height));
int maxY = Math.Min(height, endY);
if (this.Sampler is NearestNeighborResampler) if (this.Sampler is NearestNeighborResampler)
{ {
var workingRect = Rectangle.FromLTRB(minX, minY, maxX, maxY);
// Scaling factors // Scaling factors
float widthFactor = sourceRectangle.Width / (float)this.TargetRectangle.Width; float widthFactor = sourceRectangle.Width / (float)this.TargetRectangle.Width;
float heightFactor = sourceRectangle.Height / (float)this.TargetRectangle.Height; float heightFactor = sourceRectangle.Height / (float)this.TargetRectangle.Height;
@ -224,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 = minX; x < maxX; x++) for (int x = workingRect.Left; x < workingRect.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)];
@ -244,29 +239,25 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
// A 2-pass 1D algorithm appears to be faster than splitting a 1-pass 2D algorithm // 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 // First process the columns. Since we are not using multiple threads startY and endY
// are the upper and lower bounds of the source rectangle. // are the upper and lower bounds of the source rectangle.
//using (Buffer2D<Vector4> firstPassPixelsTransposed = source.MemoryAllocator.Allocate2D<Vector4>(sourceHeight, width)) using (var resizeWindow = new ResizeWindow(
using (var resizeWindow = new ResizeWindowOld(
configuration, configuration,
sourceRectangle, sourceRectangle,
conversionModifiers, conversionModifiers,
this.horizontalKernelMap, this.horizontalKernelMap,
this.verticalKernelMap, this.verticalKernelMap,
sourceHeight,
width, width,
minX, workingRect,
maxX,
startX)) startX))
using (IMemoryOwner<Vector4> tempBuffer = source.MemoryAllocator.Allocate<Vector4>(Math.Max(source.Width, width))) using (IMemoryOwner<Vector4> tempBuffer = source.MemoryAllocator.Allocate<Vector4>(Math.Max(sourceRectangle.Width, width)))
{ {
Span<Vector4> tempRowSpan = tempBuffer.GetSpan().Slice(sourceX, source.Width - sourceX); Span<Vector4> tempRowSpan = tempBuffer.GetSpan();
resizeWindow.Initialize(source.PixelBuffer, tempRowSpan); resizeWindow.Initialize(source.PixelBuffer, tempRowSpan);
// Now process the rows. // Now process the rows.
Span<Vector4> tempColSpan = tempBuffer.GetSpan().Slice(0, width); Span<Vector4> tempColSpan = tempBuffer.GetSpan().Slice(0, width);
for (int y = minY; y < maxY; y++) for (int y = workingRect.Top; y < workingRect.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);
@ -299,92 +290,4 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
this.verticalKernelMap = null; 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();
}
}
} }

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

@ -0,0 +1,97 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
using System.Numerics;
using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.Memory;
using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing.Processors.Transforms
{
class ResizeWindow : 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 Rectangle workingRectangle;
private readonly int startX;
public ResizeWindow(
Configuration configuration,
Rectangle sourceRectangle,
PixelConversionModifiers conversionModifiers,
ResizeKernelMap horizontalKernelMap,
ResizeKernelMap verticalKernelMap,
int destWidth,
Rectangle workingRectangle,
int startX)
{
this.configuration = configuration;
this.sourceRectangle = sourceRectangle;
this.conversionModifiers = conversionModifiers;
this.horizontalKernelMap = horizontalKernelMap;
this.verticalKernelMap = verticalKernelMap;
this.workingRectangle = workingRectangle;
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.workingRectangle.Left; x < this.workingRectangle.Right; 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();
}
}
}
Loading…
Cancel
Save