Browse Source

Make ResizeKernelMap non-generic.

pull/1118/head
James Jackson-South 6 years ago
parent
commit
f9fb732e22
  1. 13
      src/ImageSharp/Processing/Processors/Transforms/Resize/ResamplerExtensions.cs
  2. 4
      src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernel.cs
  3. 15
      src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.PeriodicKernelMap.cs
  4. 34
      src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.cs
  5. 12
      src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeWorker.cs
  6. 8
      tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeKernelMapTests.ReferenceKernelMap.cs
  7. 21
      tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeKernelMapTests.cs
  8. 2
      tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeTests.cs

13
src/ImageSharp/Processing/Processors/Transforms/Resize/ResamplerExtensions.cs

@ -78,13 +78,13 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
// Since all image frame dimensions have to be the same we can calculate
// the kernel maps and reuse for all frames.
MemoryAllocator allocator = configuration.MemoryAllocator;
using var horizontalKernelMap = ResizeKernelMap<TResampler>.Calculate(
using var horizontalKernelMap = ResizeKernelMap.Calculate(
in sampler,
destinationRectangle.Width,
sourceRectangle.Width,
allocator);
using var verticalKernelMap = ResizeKernelMap<TResampler>.Calculate(
using var verticalKernelMap = ResizeKernelMap.Calculate(
in sampler,
destinationRectangle.Height,
sourceRectangle.Height,
@ -135,17 +135,16 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
in operation);
}
private static void ApplyResizeFrameTransform<TResampler, TPixel>(
private static void ApplyResizeFrameTransform<TPixel>(
Configuration configuration,
ImageFrame<TPixel> source,
ImageFrame<TPixel> destination,
ResizeKernelMap<TResampler> horizontalKernelMap,
ResizeKernelMap<TResampler> verticalKernelMap,
ResizeKernelMap horizontalKernelMap,
ResizeKernelMap verticalKernelMap,
Rectangle sourceRectangle,
Rectangle destinationRectangle,
Rectangle interest,
bool compand)
where TResampler : unmanaged, IResampler
where TPixel : struct, IPixel<TPixel>
{
PixelConversionModifiers conversionModifiers =
@ -155,7 +154,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
// To reintroduce parallel processing, we would launch multiple workers
// for different row intervals of the image.
using (var worker = new ResizeWorker<TResampler, TPixel>(
using (var worker = new ResizeWorker<TPixel>(
configuration,
sourceArea,
conversionModifiers,

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

@ -8,7 +8,7 @@ using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.Processing.Processors.Transforms
{
/// <summary>
/// Points to a collection of of weights allocated in <see cref="ResizeKernelMap{T}"/>.
/// Points to a collection of of weights allocated in <see cref="ResizeKernelMap"/>.
/// </summary>
internal readonly unsafe struct ResizeKernel
{
@ -44,7 +44,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
}
/// <summary>
/// Gets the span representing the portion of the <see cref="ResizeKernelMap{T}"/> that this window covers.
/// Gets the span representing the portion of the <see cref="ResizeKernelMap"/> that this window covers.
/// </summary>
/// <value>The <see cref="Span{T}"/>.
/// </value>

15
src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.PeriodicKernelMap.cs

@ -5,13 +5,12 @@ using SixLabors.ImageSharp.Memory;
namespace SixLabors.ImageSharp.Processing.Processors.Transforms
{
internal partial class ResizeKernelMap<TResampler>
where TResampler : unmanaged, IResampler
internal partial class ResizeKernelMap
{
/// <summary>
/// Memory-optimized <see cref="ResizeKernelMap{TResampler}"/> where repeating rows are stored only once.
/// Memory-optimized <see cref="ResizeKernelMap"/> where repeating rows are stored only once.
/// </summary>
private sealed class PeriodicKernelMap : ResizeKernelMap<TResampler>
private sealed class PeriodicKernelMap : ResizeKernelMap
{
private readonly int period;
@ -19,7 +18,6 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
public PeriodicKernelMap(
MemoryAllocator memoryAllocator,
TResampler sampler,
int sourceLength,
int destinationLength,
double ratio,
@ -29,7 +27,6 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
int cornerInterval)
: base(
memoryAllocator,
sampler,
sourceLength,
destinationLength,
(cornerInterval * 2) + period,
@ -43,14 +40,14 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
internal override string Info => base.Info + $"|period:{this.period}|cornerInterval:{this.cornerInterval}";
protected internal override void Initialize()
protected internal override void Initialize<TResampler>(in TResampler sampler)
{
// Build top corner data + one period of the mosaic data:
int startOfFirstRepeatedMosaic = this.cornerInterval + this.period;
for (int i = 0; i < startOfFirstRepeatedMosaic; i++)
{
this.kernels[i] = this.BuildKernel(i, i);
this.kernels[i] = this.BuildKernel(in sampler, i, i);
}
// Copy the mosaics:
@ -67,7 +64,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
int bottomStartData = this.cornerInterval + this.period;
for (int i = 0; i < this.cornerInterval; i++)
{
this.kernels[bottomStartDest + i] = this.BuildKernel(bottomStartDest + i, bottomStartData + i);
this.kernels[bottomStartDest + i] = this.BuildKernel(in sampler, bottomStartDest + i, bottomStartData + i);
}
}
}

34
src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.cs

@ -12,14 +12,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
/// <summary>
/// Provides resize kernel values from an optimized contiguous memory region.
/// </summary>
/// <typeparam name="TResampler">The type of sampler.</typeparam>
internal partial class ResizeKernelMap<TResampler> : IDisposable
where TResampler : unmanaged, IResampler
internal partial class ResizeKernelMap : IDisposable
{
private static readonly TolerantMath TolerantMath = TolerantMath.Default;
private readonly TResampler sampler;
private readonly int sourceLength;
private readonly double ratio;
@ -41,7 +37,6 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
private ResizeKernelMap(
MemoryAllocator memoryAllocator,
TResampler sampler,
int sourceLength,
int destinationLength,
int bufferHeight,
@ -49,7 +44,6 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
double scale,
int radius)
{
this.sampler = sampler;
this.ratio = ratio;
this.scale = scale;
this.radius = radius;
@ -79,7 +73,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
$"radius:{this.radius}|sourceSize:{this.sourceLength}|destinationSize:{this.DestinationLength}|ratio:{this.ratio}|scale:{this.scale}";
/// <summary>
/// Disposes <see cref="ResizeKernelMap{TResampler}"/> instance releasing it's backing buffer.
/// Disposes <see cref="ResizeKernelMap"/> instance releasing it's backing buffer.
/// </summary>
public void Dispose()
=> this.Dispose(true);
@ -111,16 +105,18 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
/// <summary>
/// Computes the weights to apply at each pixel when resizing.
/// </summary>
/// <typeparam name="TResampler">The type of sampler.</typeparam>
/// <param name="sampler">The <see cref="IResampler"/></param>
/// <param name="destinationSize">The destination size</param>
/// <param name="sourceSize">The source size</param>
/// <param name="memoryAllocator">The <see cref="MemoryAllocator"/> to use for buffer allocations</param>
/// <returns>The <see cref="ResizeKernelMap{IResampler}"/></returns>
public static ResizeKernelMap<TResampler> Calculate(
/// <returns>The <see cref="ResizeKernelMap"/></returns>
public static ResizeKernelMap Calculate<TResampler>(
in TResampler sampler,
int destinationSize,
int sourceSize,
MemoryAllocator memoryAllocator)
where TResampler : unmanaged, IResampler
{
double ratio = (double)sourceSize / destinationSize;
double scale = ratio;
@ -158,10 +154,9 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
// If we don't have at least 2 periods, we go with the basic implementation:
bool hasAtLeast2Periods = 2 * (cornerInterval + period) < destinationSize;
ResizeKernelMap<TResampler> result = hasAtLeast2Periods
ResizeKernelMap result = hasAtLeast2Periods
? new PeriodicKernelMap(
memoryAllocator,
sampler,
sourceSize,
destinationSize,
ratio,
@ -169,9 +164,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
radius,
period,
cornerInterval)
: new ResizeKernelMap<TResampler>(
: new ResizeKernelMap(
memoryAllocator,
sampler,
sourceSize,
destinationSize,
destinationSize,
@ -179,7 +173,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
scale,
radius);
result.Initialize();
result.Initialize(in sampler);
return result;
}
@ -187,11 +181,12 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
/// <summary>
/// Initializes the kernel map.
/// </summary>
protected internal virtual void Initialize()
protected internal virtual void Initialize<TResampler>(in TResampler sampler)
where TResampler : unmanaged, IResampler
{
for (int i = 0; i < this.DestinationLength; i++)
{
this.kernels[i] = this.BuildKernel(i, i);
this.kernels[i] = this.BuildKernel(in sampler, i, i);
}
}
@ -200,7 +195,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
/// referencing the data at row <paramref name="dataRowIndex"/> within <see cref="data"/>,
/// so the data reusable by other data rows.
/// </summary>
private ResizeKernel BuildKernel(int destRowIndex, int dataRowIndex)
private ResizeKernel BuildKernel<TResampler>(in TResampler sampler, int destRowIndex, int dataRowIndex)
where TResampler : unmanaged, IResampler
{
double center = ((destRowIndex + .5) * this.ratio) - .5;
@ -224,7 +220,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
for (int j = left; j <= right; j++)
{
double value = this.sampler.GetValue((float)((j - center) / this.scale));
double value = sampler.GetValue((float)((j - center) / this.scale));
sum += value;
kernelValues[j - left] = value;

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

@ -6,7 +6,6 @@ using System.Buffers;
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
@ -19,8 +18,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
/// When sliding the window, the contents of the bottom window band are copied to the new top band.
/// For more details, and visual explanation, see "ResizeWorker.pptx".
/// </summary>
internal sealed class ResizeWorker<TResampler, TPixel> : IDisposable
where TResampler : unmanaged, IResampler
internal sealed class ResizeWorker<TPixel> : IDisposable
where TPixel : struct, IPixel<TPixel>
{
private readonly Buffer2D<Vector4> transposedFirstPassBuffer;
@ -29,7 +27,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
private readonly PixelConversionModifiers conversionModifiers;
private readonly ResizeKernelMap<TResampler> horizontalKernelMap;
private readonly ResizeKernelMap horizontalKernelMap;
private readonly BufferArea<TPixel> source;
@ -39,7 +37,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
private readonly IMemoryOwner<Vector4> tempColumnBuffer;
private readonly ResizeKernelMap<TResampler> verticalKernelMap;
private readonly ResizeKernelMap verticalKernelMap;
private readonly int destWidth;
@ -57,8 +55,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
Configuration configuration,
BufferArea<TPixel> source,
PixelConversionModifiers conversionModifiers,
ResizeKernelMap<TResampler> horizontalKernelMap,
ResizeKernelMap<TResampler> verticalKernelMap,
ResizeKernelMap horizontalKernelMap,
ResizeKernelMap verticalKernelMap,
int destWidth,
Rectangle targetWorkingRect,
Point targetOrigin)

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

@ -13,8 +13,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms
/// <summary>
/// Simplified reference implementation for <see cref="ResizeKernelMap"/> functionality.
/// </summary>
internal class ReferenceKernelMap<TResampler>
where TResampler : unmanaged, IResampler
internal class ReferenceKernelMap
{
private readonly ReferenceKernel[] kernels;
@ -27,7 +26,8 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms
public ReferenceKernel GetKernel(int destinationIndex) => this.kernels[destinationIndex];
public static ReferenceKernelMap<TResampler> Calculate(TResampler sampler, int destinationSize, int sourceSize, bool normalize = true)
public static ReferenceKernelMap Calculate<TResampler>(in TResampler sampler, int destinationSize, int sourceSize, bool normalize = true)
where TResampler : unmanaged, IResampler
{
double ratio = (double)sourceSize / destinationSize;
double scale = ratio;
@ -85,7 +85,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms
result.Add(new ReferenceKernel(left, floatVals));
}
return new ReferenceKernelMap<TResampler>(result.ToArray());
return new ReferenceKernelMap(result.ToArray());
}
}

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

@ -89,7 +89,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms
public void PrintNonNormalizedKernelMap<TResampler>(TResampler resampler, int srcSize, int destSize)
where TResampler : unmanaged, IResampler
{
var kernelMap = ReferenceKernelMap<TResampler>.Calculate(resampler, destSize, srcSize, false);
var kernelMap = ReferenceKernelMap.Calculate<TResampler>(in resampler, destSize, srcSize, false);
this.Output.WriteLine($"Actual KernelMap:\n{PrintKernelMap(kernelMap)}\n");
}
@ -117,8 +117,8 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms
private void VerifyKernelMapContentIsCorrect<TResampler>(TResampler resampler, int srcSize, int destSize)
where TResampler : unmanaged, IResampler
{
var referenceMap = ReferenceKernelMap<TResampler>.Calculate(resampler, destSize, srcSize);
var kernelMap = ResizeKernelMap<TResampler>.Calculate(resampler, destSize, srcSize, Configuration.Default.MemoryAllocator);
var referenceMap = ReferenceKernelMap.Calculate(in resampler, destSize, srcSize);
var kernelMap = ResizeKernelMap.Calculate(in resampler, destSize, srcSize, Configuration.Default.MemoryAllocator);
#if DEBUG
this.Output.WriteLine(kernelMap.Info);
@ -153,23 +153,20 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms
}
}
private static string PrintKernelMap<TResampler>(ResizeKernelMap<TResampler> kernelMap)
where TResampler : unmanaged, IResampler
=> PrintKernelMap<TResampler, ResizeKernelMap<TResampler>>(kernelMap, km => km.DestinationLength, (km, i) => km.GetKernel(i));
private static string PrintKernelMap(ResizeKernelMap kernelMap)
=> PrintKernelMap(kernelMap, km => km.DestinationLength, (km, i) => km.GetKernel(i));
private static string PrintKernelMap<TResampler>(ReferenceKernelMap<TResampler> kernelMap)
where TResampler : unmanaged, IResampler
=> PrintKernelMap<TResampler, ReferenceKernelMap<TResampler>>(kernelMap, km => km.DestinationSize, (km, i) => km.GetKernel(i));
private static string PrintKernelMap(ReferenceKernelMap kernelMap)
=> PrintKernelMap(kernelMap, km => km.DestinationSize, (km, i) => km.GetKernel(i));
private static string PrintKernelMap<TResampler, TKernelMap>(
private static string PrintKernelMap<TKernelMap>(
TKernelMap kernelMap,
Func<TKernelMap, int> getDestinationSize,
Func<TKernelMap, int, ReferenceKernel> getKernel)
where TResampler : unmanaged, IResampler
{
var bld = new StringBuilder();
if (kernelMap is ResizeKernelMap<TResampler> actualMap)
if (kernelMap is ResizeKernelMap actualMap)
{
bld.AppendLine(actualMap.Info);
}

2
tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeTests.cs

@ -121,7 +121,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms
configuration.MemoryAllocator = allocator;
configuration.WorkingBufferSizeHintInBytes = workingBufferSizeHintInBytes;
var verticalKernelMap = ResizeKernelMap<BicubicResampler>.Calculate(
var verticalKernelMap = ResizeKernelMap.Calculate<BicubicResampler>(
default,
destSize.Height,
image0.Height,

Loading…
Cancel
Save