diff --git a/src/ImageSharp/Processing/Processors/Transforms/CompandingResizeProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/CompandingResizeProcessor.cs
deleted file mode 100644
index c8a43b3d9..000000000
--- a/src/ImageSharp/Processing/Processors/Transforms/CompandingResizeProcessor.cs
+++ /dev/null
@@ -1,177 +0,0 @@
-//
-// Copyright (c) James Jackson-South and contributors.
-// Licensed under the Apache License, Version 2.0.
-//
-
-namespace ImageSharp.Processing.Processors
-{
- using System;
- using System.Numerics;
- using System.Threading.Tasks;
-
- ///
- /// Provides methods that allow the resizing of images using various algorithms.
- /// This version will expand and compress the image to and from a linear color space during processing.
- ///
- /// The pixel format.
- internal class CompandingResizeProcessor : ResamplingWeightedProcessor
- where TColor : struct, IPixel
- {
- ///
- /// Initializes a new instance of the class.
- ///
- /// The sampler to perform the resize operation.
- /// The target width.
- /// The target height.
- public CompandingResizeProcessor(IResampler sampler, int width, int height)
- : base(sampler, width, height, new Rectangle(0, 0, width, height))
- {
- }
-
- ///
- /// Initializes a new instance of the class.
- ///
- /// The sampler to perform the resize operation.
- /// The target width.
- /// The target height.
- ///
- /// The structure that specifies the portion of the target image object to draw to.
- ///
- public CompandingResizeProcessor(IResampler sampler, int width, int height, Rectangle resizeRectangle)
- : base(sampler, width, height, resizeRectangle)
- {
- }
-
- ///
- public override bool Compand { get; set; } = true;
-
- ///
- protected override unsafe void OnApply(ImageBase source, Rectangle sourceRectangle)
- {
- // Jump out, we'll deal with that later.
- if (source.Width == this.Width && source.Height == this.Height && sourceRectangle == this.ResizeRectangle)
- {
- return;
- }
-
- int width = this.Width;
- int height = this.Height;
- int sourceX = sourceRectangle.X;
- int sourceY = sourceRectangle.Y;
- int startY = this.ResizeRectangle.Y;
- int endY = this.ResizeRectangle.Bottom;
- int startX = this.ResizeRectangle.X;
- int endX = this.ResizeRectangle.Right;
-
- int minX = Math.Max(0, startX);
- int maxX = Math.Min(width, endX);
- int minY = Math.Max(0, startY);
- int maxY = Math.Min(height, endY);
-
- if (this.Sampler is NearestNeighborResampler)
- {
- // Scaling factors
- float widthFactor = sourceRectangle.Width / (float)this.ResizeRectangle.Width;
- float heightFactor = sourceRectangle.Height / (float)this.ResizeRectangle.Height;
-
- using (PixelAccessor targetPixels = new PixelAccessor(width, height))
- {
- using (PixelAccessor sourcePixels = source.Lock())
- {
- Parallel.For(
- minY,
- maxY,
- this.ParallelOptions,
- y =>
- {
- // Y coordinates of source points
- int originY = (int)(((y - startY) * heightFactor) + sourceY);
-
- for (int x = minX; x < maxX; x++)
- {
- // X coordinates of source points
- targetPixels[x, y] = sourcePixels[(int)(((x - startX) * widthFactor) + sourceX), originY];
- }
- });
- }
-
- // Break out now.
- source.SwapPixelsBuffers(targetPixels);
- return;
- }
- }
-
- // Interpolate the image using the calculated weights.
- // 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
- // are the upper and lower bounds of the source rectangle.
- using (PixelAccessor targetPixels = new PixelAccessor(width, height))
- {
- using (PixelAccessor sourcePixels = source.Lock())
- using (PixelAccessor firstPassPixels = new PixelAccessor(width, source.Height))
- {
- Parallel.For(
- 0,
- sourceRectangle.Bottom,
- this.ParallelOptions,
- y =>
- {
- for (int x = minX; x < maxX; x++)
- {
- // Ensure offsets are normalised for cropping and padding.
- WeightsWindow ws = this.HorizontalWeights.Weights[x - startX];
- float* horizontalValues = ws.Ptr;
- int left = ws.Left;
-
- // Destination color components
- Vector4 destination = Vector4.Zero;
-
- for (int i = 0; i < ws.Length; i++)
- {
- float xw = horizontalValues[i];
- int index = left + i;
- destination += sourcePixels[index, y].ToVector4().Expand() * xw;
- }
-
- TColor d = default(TColor);
- d.PackFromVector4(destination.Compress());
- firstPassPixels[x, y] = d;
- }
- });
-
- // Now process the rows.
- Parallel.For(
- minY,
- maxY,
- this.ParallelOptions,
- y =>
- {
- // Ensure offsets are normalised for cropping and padding.
- WeightsWindow ws = this.VerticalWeights.Weights[y - startY];
- float* verticalValues = ws.Ptr;
- int left = ws.Left;
-
- for (int x = 0; x < width; x++)
- {
- // Destination color components
- Vector4 destination = Vector4.Zero;
-
- for (int i = 0; i < ws.Length; i++)
- {
- float yw = verticalValues[i];
- int index = left + i;
- destination += firstPassPixels[x, index].ToVector4().Expand() * yw;
- }
-
- TColor d = default(TColor);
- d.PackFromVector4(destination.Compress());
- targetPixels[x, y] = d;
- }
- });
- }
-
- source.SwapPixelsBuffers(targetPixels);
- }
- }
- }
-}
\ No newline at end of file
diff --git a/src/ImageSharp/Processing/Processors/Transforms/ResamplingWeightedProcessor.Weights.cs b/src/ImageSharp/Processing/Processors/Transforms/ResamplingWeightedProcessor.Weights.cs
index 00a81100d..c7386487a 100644
--- a/src/ImageSharp/Processing/Processors/Transforms/ResamplingWeightedProcessor.Weights.cs
+++ b/src/ImageSharp/Processing/Processors/Transforms/ResamplingWeightedProcessor.Weights.cs
@@ -69,6 +69,30 @@ namespace ImageSharp.Processing.Processors
return result;
}
+ ///
+ /// Computes the sum of vectors in 'rowSpan' weighted by weight values, pointed by this instance.
+ /// Applies to all input vectors.
+ ///
+ /// The input span of vectors
+ /// The weighted sum
+ public Vector4 ComputeExpandedWeightedRowSum(BufferSpan rowSpan)
+ {
+ float* horizontalValues = this.Ptr;
+ int left = this.Left;
+
+ // Destination color components
+ Vector4 result = Vector4.Zero;
+
+ for (int i = 0; i < this.Length; i++)
+ {
+ float xw = horizontalValues[i];
+ int index = left + i;
+ result += rowSpan[index].Expand() * xw;
+ }
+
+ return result;
+ }
+
///
/// Computes the sum of vectors in 'firstPassPixels' at a column pointed by 'x',
/// weighted by weight values, pointed by this instance.
diff --git a/src/ImageSharp/Processing/Processors/Transforms/ResamplingWeightedProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/ResamplingWeightedProcessor.cs
index f74bf7edd..d1a709384 100644
--- a/src/ImageSharp/Processing/Processors/Transforms/ResamplingWeightedProcessor.cs
+++ b/src/ImageSharp/Processing/Processors/Transforms/ResamplingWeightedProcessor.cs
@@ -156,6 +156,5 @@ namespace ImageSharp.Processing.Processors
return result;
}
-
}
}
\ No newline at end of file
diff --git a/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs
index 77b3f3b6f..944e245ac 100644
--- a/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs
+++ b/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs
@@ -12,9 +12,6 @@ namespace ImageSharp.Processing.Processors
///
/// Provides methods that allow the resizing of images using various algorithms.
///
- ///
- /// This version and the have been separated out to improve performance.
- ///
/// The pixel format.
internal class ResizeProcessor : ResamplingWeightedProcessor
where TColor : struct, IPixel
@@ -123,15 +120,27 @@ namespace ImageSharp.Processing.Processors
using (PinnedBuffer tempRowBuffer = new PinnedBuffer(sourcePixels.Width))
{
BufferSpan sourceRow = sourcePixels.GetRowSpan(y);
+
BulkPixelOperations.Instance.ToVector4(
sourceRow,
tempRowBuffer,
sourceRow.Length);
- for (int x = minX; x < maxX; x++)
+ if (this.Compand)
+ {
+ for (int x = minX; x < maxX; x++)
+ {
+ WeightsWindow window = this.HorizontalWeights.Weights[x - startX];
+ firstPassPixels[x, y] = window.ComputeExpandedWeightedRowSum(tempRowBuffer);
+ }
+ }
+ else
{
- WeightsWindow window = this.HorizontalWeights.Weights[x - startX];
- firstPassPixels[x, y] = window.ComputeWeightedRowSum(tempRowBuffer);
+ for (int x = minX; x < maxX; x++)
+ {
+ WeightsWindow window = this.HorizontalWeights.Weights[x - startX];
+ firstPassPixels[x, y] = window.ComputeWeightedRowSum(tempRowBuffer);
+ }
}
}
});
@@ -146,14 +155,29 @@ namespace ImageSharp.Processing.Processors
// Ensure offsets are normalised for cropping and padding.
WeightsWindow window = this.VerticalWeights.Weights[y - startY];
- for (int x = 0; x < width; x++)
+ if (this.Compand)
{
- // Destination color components
- Vector4 destination = window.ComputeWeightedColumnSum(firstPassPixels, x);
+ for (int x = 0; x < width; x++)
+ {
+ // Destination color components
+ Vector4 destination = window.ComputeWeightedColumnSum(firstPassPixels, x);
+ destination = destination.Compress();
+ TColor d = default(TColor);
+ d.PackFromVector4(destination);
+ targetPixels[x, y] = d;
+ }
+ }
+ else
+ {
+ for (int x = 0; x < width; x++)
+ {
+ // Destination color components
+ Vector4 destination = window.ComputeWeightedColumnSum(firstPassPixels, x);
- TColor d = default(TColor);
- d.PackFromVector4(destination);
- targetPixels[x, y] = d;
+ TColor d = default(TColor);
+ d.PackFromVector4(destination);
+ targetPixels[x, y] = d;
+ }
}
});
}
diff --git a/src/ImageSharp/Processing/Transforms/Resize.cs b/src/ImageSharp/Processing/Transforms/Resize.cs
index ab256c4ae..1952aa1a7 100644
--- a/src/ImageSharp/Processing/Transforms/Resize.cs
+++ b/src/ImageSharp/Processing/Transforms/Resize.cs
@@ -156,16 +156,8 @@ namespace ImageSharp
Guard.MustBeGreaterThan(width, 0, nameof(width));
Guard.MustBeGreaterThan(height, 0, nameof(height));
- ResamplingWeightedProcessor processor;
-
- if (compand)
- {
- processor = new CompandingResizeProcessor(sampler, width, height, targetRectangle);
- }
- else
- {
- processor = new ResizeProcessor(sampler, width, height, targetRectangle);
- }
+ ResizeProcessor processor =
+ new ResizeProcessor(sampler, width, height, targetRectangle) { Compand = compand };
source.ApplyProcessor(processor, sourceRectangle);
return source;
diff --git a/tests/ImageSharp.Tests/Processors/Filters/ResizeTests.cs b/tests/ImageSharp.Tests/Processors/Filters/ResizeTests.cs
index 643033f4c..35994e028 100644
--- a/tests/ImageSharp.Tests/Processors/Filters/ResizeTests.cs
+++ b/tests/ImageSharp.Tests/Processors/Filters/ResizeTests.cs
@@ -8,6 +8,32 @@ namespace ImageSharp.Tests
using System.IO;
using Processing;
using Xunit;
+ using Xunit.Abstractions;
+
+ public class ResizeProfilingBenchmarks : MeasureFixture
+ {
+ public ResizeProfilingBenchmarks(ITestOutputHelper output)
+ : base(output)
+ {
+ }
+
+ public int ExecutionCount { get; set; } = 50;
+
+ [Theory]
+ [InlineData(100, 100)]
+ [InlineData(1000, 1000)]
+ public void ResizeBicubic(int width, int height)
+ {
+ this.Measure(this.ExecutionCount,
+ () =>
+ {
+ using (Image image = new Image(width, height))
+ {
+ image.Resize(width / 4, height / 4);
+ }
+ });
+ }
+ }
public class ResizeTests : FileTestBase
{