diff --git a/src/ImageSharp/Image/PixelAccessor{TColor}.cs b/src/ImageSharp/Image/PixelAccessor{TColor}.cs
index cea058951e..f5393cfb38 100644
--- a/src/ImageSharp/Image/PixelAccessor{TColor}.cs
+++ b/src/ImageSharp/Image/PixelAccessor{TColor}.cs
@@ -241,17 +241,6 @@ namespace ImageSharp
this.CopyTo(area, sourceX, sourceY, width, height);
}
- /////
- ///// Gets a to the row 'y' beginning from the pixel at 'x'.
- /////
- ///// The x coordinate
- ///// The y coordinate
- ///// The
- //internal BufferSpan GetRowSpan(int x, int y)
- //{
- // return this.pixelBuffer.Slice((y * this.Width) + x, this.Width - x);
- //}
-
///
/// Sets the pixel buffer in an unsafe manner. This should not be used unless you know what its doing!!!
///
diff --git a/src/ImageSharp/Processing/Processors/Transforms/CompandingResizeProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/CompandingResizeProcessor.cs
index f5314d448d..14cea480d8 100644
--- a/src/ImageSharp/Processing/Processors/Transforms/CompandingResizeProcessor.cs
+++ b/src/ImageSharp/Processing/Processors/Transforms/CompandingResizeProcessor.cs
@@ -46,7 +46,7 @@ namespace ImageSharp.Processing.Processors
public override bool Compand { get; set; } = true;
///
- protected override void OnApply(ImageBase source, Rectangle sourceRectangle)
+ 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)
@@ -119,15 +119,18 @@ namespace ImageSharp.Processing.Processors
for (int x = minX; x < maxX; x++)
{
// Ensure offsets are normalised for cropping and padding.
- Weight[] horizontalValues = this.HorizontalWeights[x - startX].Values;
+ Weights 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 < horizontalValues.Length; i++)
+ for (int i = 0; i < ws.Length; i++)
{
- Weight xw = horizontalValues[i];
- destination += sourcePixels[xw.Index + sourceX, y].ToVector4().Expand() * xw.Value;
+ float xw = horizontalValues[i];
+ int index = left + i;
+ destination += sourcePixels[index, y].ToVector4().Expand() * xw;
}
TColor d = default(TColor);
@@ -144,17 +147,20 @@ namespace ImageSharp.Processing.Processors
y =>
{
// Ensure offsets are normalised for cropping and padding.
- Weight[] verticalValues = this.VerticalWeights[y - startY].Values;
+ Weights 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 < verticalValues.Length; i++)
+ for (int i = 0; i < ws.Length; i++)
{
- Weight yw = verticalValues[i];
- destination += firstPassPixels[x, yw.Index + sourceY].ToVector4().Expand() * yw.Value;
+ float yw = verticalValues[i];
+ int index = left + i;
+ destination += firstPassPixels[x, index].ToVector4().Expand() * yw;
}
TColor d = default(TColor);
diff --git a/src/ImageSharp/Processing/Processors/Transforms/ResamplingWeightedProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/ResamplingWeightedProcessor.cs
index 2d6de41545..51f382df2a 100644
--- a/src/ImageSharp/Processing/Processors/Transforms/ResamplingWeightedProcessor.cs
+++ b/src/ImageSharp/Processing/Processors/Transforms/ResamplingWeightedProcessor.cs
@@ -6,6 +6,9 @@
namespace ImageSharp.Processing.Processors
{
using System;
+ using System.Buffers;
+ using System.Runtime.CompilerServices;
+ using System.Runtime.InteropServices;
///
/// Provides methods that allow the resizing of images using various algorithms.
@@ -59,32 +62,41 @@ namespace ImageSharp.Processing.Processors
///
/// Gets or sets the horizontal weights.
///
- protected Weights[] HorizontalWeights { get; set; }
+ protected Weights.Buffer HorizontalWeights { get; set; }
///
/// Gets or sets the vertical weights.
///
- protected Weights[] VerticalWeights { get; set; }
+ protected Weights.Buffer VerticalWeights { get; set; }
///
protected override void BeforeApply(ImageBase source, Rectangle sourceRectangle)
{
if (!(this.Sampler is NearestNeighborResampler))
{
- this.HorizontalWeights = this.PrecomputeWeights(this.ResizeRectangle.Width, sourceRectangle.Width);
- this.VerticalWeights = this.PrecomputeWeights(this.ResizeRectangle.Height, sourceRectangle.Height);
+ this.HorizontalWeights = this.PrecomputeWeights(
+ this.ResizeRectangle.Width,
+ sourceRectangle.Width);
+
+ this.VerticalWeights = this.PrecomputeWeights(
+ this.ResizeRectangle.Height,
+ sourceRectangle.Height);
}
}
+ protected override void AfterApply(ImageBase source, Rectangle sourceRectangle)
+ {
+ base.AfterApply(source, sourceRectangle);
+ this.HorizontalWeights?.Dispose();
+ this.HorizontalWeights = null;
+ this.VerticalWeights?.Dispose();
+ this.VerticalWeights = null;
+ }
+
///
/// Computes the weights to apply at each pixel when resizing.
///
- /// The destination section size.
- /// The source section size.
- ///
- /// The .
- ///
- protected Weights[] PrecomputeWeights(int destinationSize, int sourceSize)
+ protected unsafe Weights.Buffer PrecomputeWeights(int destinationSize, int sourceSize)
{
float ratio = (float)sourceSize / destinationSize;
float scale = ratio;
@@ -96,8 +108,8 @@ namespace ImageSharp.Processing.Processors
IResampler sampler = this.Sampler;
float radius = (float)Math.Ceiling(scale * sampler.Radius);
- Weights[] result = new Weights[destinationSize];
-
+ Weights.Buffer result = new Weights.Buffer(sourceSize, destinationSize);
+
for (int i = 0; i < destinationSize; i++)
{
float center = ((i + .5F) * ratio) - .5F;
@@ -116,67 +128,82 @@ namespace ImageSharp.Processing.Processors
}
float sum = 0;
- result[i] = new Weights();
- Weight[] weights = new Weight[right - left + 1];
+
+ result.Weights[i] = result.Slice(i, left, right);
+ Weights ws = result.Weights[i];
+
+ float* weights = ws.Ptr;
for (int j = left; j <= right; j++)
{
float weight = sampler.GetValue((j - center) / scale);
sum += weight;
- weights[j - left] = new Weight(j, weight);
+ weights[j - left] = weight;
}
// Normalise, best to do it here rather than in the pixel loop later on.
if (sum > 0)
{
- for (int w = 0; w < weights.Length; w++)
+ for (int w = 0; w < ws.Length; w++)
{
- weights[w].Value = weights[w].Value / sum;
+ weights[w] = weights[w] / sum;
}
}
-
- result[i].Values = weights;
}
return result;
}
///
- /// Represents the weight to be added to a scaled pixel.
+ /// Represents a collection of weights and their sum.
///
- protected struct Weight
+ protected unsafe struct Weights
{
///
- /// Initializes a new instance of the struct.
+ /// The local left index position
///
- /// The index.
- /// The value.
- public Weight(int index, float value)
+ public int Left;
+
+ public BufferSpan Span;
+
+ public float* Ptr => (float*)Span.PointerAtOffset;
+
+ public int Length => Span.Length;
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private Weights(int left, BufferSpan span)
{
- this.Index = index;
- this.Value = value;
+ this.Left = left;
+ this.Span = span;
}
- ///
- /// Gets the pixel index.
- ///
- public int Index { get; }
+ internal unsafe class Buffer : IDisposable
+ {
+ private PinnedImageBuffer dataBuffer;
- ///
- /// Gets or sets the result of the interpolation algorithm.
- ///
- public float Value { get; set; }
- }
+ public Weights[] Weights { get; }
- ///
- /// Represents a collection of weights and their sum.
- ///
- protected class Weights
- {
- ///
- /// Gets or sets the values.
- ///
- public Weight[] Values { get; set; }
+ public float* DataPtr { get; }
+
+ internal Weights Slice(int i, int leftIdx, int rightIdx)
+ {
+ var span = dataBuffer.GetRowSpan(i).Slice(leftIdx, rightIdx - leftIdx);
+ return new Weights(leftIdx, span);
+ }
+
+ public Buffer(int sourceSize, int destinationSize)
+ {
+ this.dataBuffer = new PinnedImageBuffer(sourceSize, destinationSize);
+ this.dataBuffer.Clear();
+ this.DataPtr = (float*)this.dataBuffer.Pointer;
+ this.Weights = new Weights[destinationSize];
+ }
+
+ public void Dispose()
+ {
+ this.dataBuffer.Dispose();
+ }
+ }
}
}
}
\ 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 a43745a057..39b739134d 100644
--- a/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs
+++ b/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs
@@ -45,7 +45,7 @@ namespace ImageSharp.Processing.Processors
}
///
- protected override void OnApply(ImageBase source, Rectangle sourceRectangle)
+ 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)
@@ -107,33 +107,47 @@ namespace ImageSharp.Processing.Processors
using (PixelAccessor targetPixels = new PixelAccessor(width, height))
{
using (PixelAccessor sourcePixels = source.Lock())
- using (PixelAccessor firstPassPixels = new PixelAccessor(width, source.Height))
+ using (PinnedImageBuffer firstPassPixels = new PinnedImageBuffer(width, source.Height))
{
+ firstPassPixels.Clear();
+
Parallel.For(
0,
sourceRectangle.Bottom,
this.ParallelOptions,
y =>
- {
- for (int x = minX; x < maxX; x++)
{
- // Ensure offsets are normalised for cropping and padding.
- Weight[] horizontalValues = this.HorizontalWeights[x - startX].Values;
-
- // Destination color components
- Vector4 destination = Vector4.Zero;
-
- for (int i = 0; i < horizontalValues.Length; i++)
+ // TODO: Without Parallel.For() this buffer object could be reused:
+ using (PinnedBuffer tempRowBuffer = new PinnedBuffer(sourcePixels.Width))
{
- Weight xw = horizontalValues[i];
- destination += sourcePixels[xw.Index + sourceX, y].ToVector4() * xw.Value;
+ BufferSpan sourceRow = sourcePixels.GetRowSpan(y);
+ BulkPixelOperations.Instance.ToVector4(
+ sourceRow,
+ tempRowBuffer,
+ sourceRow.Length);
+
+ for (int x = minX; x < maxX; x++)
+ {
+ // Ensure offsets are normalised for cropping and padding.
+
+ Weights 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 += tempRowBuffer[index] * xw;
+ }
+
+ firstPassPixels[x, y] = destination;
+ }
}
-
- TColor d = default(TColor);
- d.PackFromVector4(destination);
- firstPassPixels[x, y] = d;
- }
- });
+ });
// Now process the rows.
Parallel.For(
@@ -143,17 +157,20 @@ namespace ImageSharp.Processing.Processors
y =>
{
// Ensure offsets are normalised for cropping and padding.
- Weight[] verticalValues = this.VerticalWeights[y - startY].Values;
+ Weights 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 < verticalValues.Length; i++)
+ for (int i = 0; i < ws.Length; i++)
{
- Weight yw = verticalValues[i];
- destination += firstPassPixels[x, yw.Index + sourceY].ToVector4() * yw.Value;
+ float yw = verticalValues[i];
+ int index = left + i;
+ destination += firstPassPixels[x, index] * yw;
}
TColor d = default(TColor);