Browse Source

Replace Fast2DArray with DenseMatrix

Much better and faster (comprable to 1D array)
af/merge-core
James Jackson-South 8 years ago
parent
commit
22ee2bb1a4
  1. 28
      src/ImageSharp.Drawing/Brushes/PatternBrush{TPixel}.cs
  2. 3
      src/ImageSharp/Dithering/ErrorDiffusion/AtkinsonDiffuser.cs
  3. 4
      src/ImageSharp/Dithering/ErrorDiffusion/BurksDiffuser.cs
  4. 10
      src/ImageSharp/Dithering/ErrorDiffusion/ErrorDiffuserBase.cs
  5. 4
      src/ImageSharp/Dithering/ErrorDiffusion/FloydSteinbergDiffuser.cs
  6. 4
      src/ImageSharp/Dithering/ErrorDiffusion/JarvisJudiceNinkeDiffuser.cs
  7. 4
      src/ImageSharp/Dithering/ErrorDiffusion/Sierra2Diffuser.cs
  8. 4
      src/ImageSharp/Dithering/ErrorDiffusion/Sierra3Diffuser.cs
  9. 4
      src/ImageSharp/Dithering/ErrorDiffusion/SierraLiteDiffuser.cs
  10. 4
      src/ImageSharp/Dithering/ErrorDiffusion/StevensonArceDiffuser.cs
  11. 4
      src/ImageSharp/Dithering/ErrorDiffusion/StuckiDiffuser.cs
  12. 14
      src/ImageSharp/Dithering/Ordered/OrderedDither.cs
  13. 12
      src/ImageSharp/Dithering/Ordered/OrderedDitherFactory.cs
  14. 173
      src/ImageSharp/Memory/Fast2DArray{T}.cs
  15. 8
      src/ImageSharp/MetaData/Profiles/ICC/DataWriter/IccDataWriter.Matrix.cs
  16. 18
      src/ImageSharp/MetaData/Profiles/ICC/MultiProcessElements/IccMatrixProcessElement.cs
  17. 215
      src/ImageSharp/Primitives/DenseMatrix{T}.cs
  18. 16
      src/ImageSharp/Primitives/ValueSize.cs
  19. 17
      src/ImageSharp/Processing/Convolution/Processors/BoxBlurProcessor.cs
  20. 17
      src/ImageSharp/Processing/Convolution/Processors/Convolution2DProcessor.cs
  21. 16
      src/ImageSharp/Processing/Convolution/Processors/Convolution2PassProcessor.cs
  22. 9
      src/ImageSharp/Processing/Convolution/Processors/ConvolutionProcessor.cs
  23. 9
      src/ImageSharp/Processing/Convolution/Processors/EdgeDetector2DProcessor.cs
  24. 21
      src/ImageSharp/Processing/Convolution/Processors/EdgeDetectorCompassProcessor.cs
  25. 7
      src/ImageSharp/Processing/Convolution/Processors/EdgeDetectorProcessor.cs
  26. 17
      src/ImageSharp/Processing/Convolution/Processors/GaussianBlurProcessor.cs
  27. 17
      src/ImageSharp/Processing/Convolution/Processors/GaussianSharpenProcessor.cs
  28. 6
      src/ImageSharp/Processing/Convolution/Processors/KayyaliKernels.cs
  29. 18
      src/ImageSharp/Processing/Convolution/Processors/KirschProcessor.cs
  30. 18
      src/ImageSharp/Processing/Convolution/Processors/KirshKernels.cs
  31. 17
      src/ImageSharp/Processing/Convolution/Processors/LaplacianKernelFactory.cs
  32. 8
      src/ImageSharp/Processing/Convolution/Processors/LaplacianKernels.cs
  33. 6
      src/ImageSharp/Processing/Convolution/Processors/PrewittKernels.cs
  34. 6
      src/ImageSharp/Processing/Convolution/Processors/RobertsCrossKernels.cs
  35. 18
      src/ImageSharp/Processing/Convolution/Processors/RobinsonKernels.cs
  36. 18
      src/ImageSharp/Processing/Convolution/Processors/RobinsonProcessor.cs
  37. 6
      src/ImageSharp/Processing/Convolution/Processors/ScharrKernels.cs
  38. 6
      src/ImageSharp/Processing/Convolution/Processors/SobelKernels.cs
  39. 1
      src/ImageSharp/Processing/Overlays/Glow.cs
  40. 1
      src/ImageSharp/Processing/Overlays/Vignette.cs
  41. 1
      src/ImageSharp/Processing/Processors/Overlays/GlowProcessor.cs
  42. 1
      src/ImageSharp/Processing/Processors/Overlays/VignetteProcessor.cs
  43. 47
      tests/ImageSharp.Benchmarks/General/Array2D.cs
  44. 4
      tests/ImageSharp.Tests/Drawing/SolidBezierTests.cs
  45. 108
      tests/ImageSharp.Tests/Primitives/DenseMatrixTests.cs
  46. 1
      tests/ImageSharp.Tests/Processing/Overlays/GlowTest.cs
  47. 1
      tests/ImageSharp.Tests/Processing/Overlays/VignetteTest.cs

28
src/ImageSharp.Drawing/Brushes/PatternBrush{TPixel}.cs

@ -5,9 +5,9 @@ using System;
using System.Numerics;
using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Drawing.Brushes.Processors;
using SixLabors.ImageSharp.Drawing.Processors;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Primitives;
using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Drawing.Brushes
@ -40,8 +40,8 @@ namespace SixLabors.ImageSharp.Drawing.Brushes
/// <summary>
/// The pattern.
/// </summary>
private readonly Fast2DArray<TPixel> pattern;
private readonly Fast2DArray<Vector4> patternVector;
private readonly DenseMatrix<TPixel> pattern;
private readonly DenseMatrix<Vector4> patternVector;
/// <summary>
/// Initializes a new instance of the <see cref="PatternBrush{TPixel}"/> class.
@ -50,7 +50,7 @@ namespace SixLabors.ImageSharp.Drawing.Brushes
/// <param name="backColor">Color of the back.</param>
/// <param name="pattern">The pattern.</param>
public PatternBrush(TPixel foreColor, TPixel backColor, bool[,] pattern)
: this(foreColor, backColor, new Fast2DArray<bool>(pattern))
: this(foreColor, backColor, new DenseMatrix<bool>(pattern))
{
}
@ -60,12 +60,12 @@ namespace SixLabors.ImageSharp.Drawing.Brushes
/// <param name="foreColor">Color of the fore.</param>
/// <param name="backColor">Color of the back.</param>
/// <param name="pattern">The pattern.</param>
internal PatternBrush(TPixel foreColor, TPixel backColor, Fast2DArray<bool> pattern)
internal PatternBrush(TPixel foreColor, TPixel backColor, DenseMatrix<bool> pattern)
{
var foreColorVector = foreColor.ToVector4();
var backColorVector = backColor.ToVector4();
this.pattern = new Fast2DArray<TPixel>(pattern.Width, pattern.Height);
this.patternVector = new Fast2DArray<Vector4>(pattern.Width, pattern.Height);
this.pattern = new DenseMatrix<TPixel>(pattern.Columns, pattern.Rows);
this.patternVector = new DenseMatrix<Vector4>(pattern.Columns, pattern.Rows);
for (int i = 0; i < pattern.Data.Length; i++)
{
if (pattern.Data[i])
@ -105,8 +105,8 @@ namespace SixLabors.ImageSharp.Drawing.Brushes
/// <summary>
/// The pattern.
/// </summary>
private readonly Fast2DArray<TPixel> pattern;
private readonly Fast2DArray<Vector4> patternVector;
private readonly DenseMatrix<TPixel> pattern;
private readonly DenseMatrix<Vector4> patternVector;
/// <summary>
/// Initializes a new instance of the <see cref="PatternBrushApplicator" /> class.
@ -115,7 +115,7 @@ namespace SixLabors.ImageSharp.Drawing.Brushes
/// <param name="pattern">The pattern.</param>
/// <param name="patternVector">The patternVector.</param>
/// <param name="options">The options</param>
public PatternBrushApplicator(ImageFrame<TPixel> source, Fast2DArray<TPixel> pattern, Fast2DArray<Vector4> patternVector, GraphicsOptions options)
public PatternBrushApplicator(ImageFrame<TPixel> source, DenseMatrix<TPixel> pattern, DenseMatrix<Vector4> patternVector, GraphicsOptions options)
: base(source, options)
{
this.pattern = pattern;
@ -134,8 +134,8 @@ namespace SixLabors.ImageSharp.Drawing.Brushes
{
get
{
x = x % this.pattern.Width;
y = y % this.pattern.Height;
x = x % this.pattern.Columns;
y = y % this.pattern.Rows;
// 2d array index at row/column
return this.pattern[y, x];
@ -151,7 +151,7 @@ namespace SixLabors.ImageSharp.Drawing.Brushes
/// <inheritdoc />
internal override void Apply(Span<float> scanline, int x, int y)
{
int patternY = y % this.pattern.Height;
int patternY = y % this.pattern.Rows;
MemoryManager memoryManager = this.Target.MemoryManager;
using (IBuffer<float> amountBuffer = memoryManager.Allocate<float>(scanline.Length))
@ -164,7 +164,7 @@ namespace SixLabors.ImageSharp.Drawing.Brushes
{
amountSpan[i] = (scanline[i] * this.Options.BlendPercentage).Clamp(0, 1);
int patternX = (x + i) % this.pattern.Width;
int patternX = (x + i) % this.pattern.Columns;
overlaySpan[i] = this.pattern[patternY, patternX];
}

3
src/ImageSharp/Dithering/ErrorDiffusion/AtkinsonDiffuser.cs

@ -3,6 +3,7 @@
using SixLabors.ImageSharp.Dithering.Base;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.Primitives;
namespace SixLabors.ImageSharp.Dithering
{
@ -15,7 +16,7 @@ namespace SixLabors.ImageSharp.Dithering
/// <summary>
/// The diffusion matrix
/// </summary>
private static readonly Fast2DArray<float> AtkinsonMatrix =
private static readonly DenseMatrix<float> AtkinsonMatrix =
new float[,]
{
{ 0, 0, 1, 1 },

4
src/ImageSharp/Dithering/ErrorDiffusion/BurksDiffuser.cs

@ -2,7 +2,7 @@
// Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.Dithering.Base;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.Primitives;
namespace SixLabors.ImageSharp.Dithering
{
@ -15,7 +15,7 @@ namespace SixLabors.ImageSharp.Dithering
/// <summary>
/// The diffusion matrix
/// </summary>
private static readonly Fast2DArray<float> BurksMatrix =
private static readonly DenseMatrix<float> BurksMatrix =
new float[,]
{
{ 0, 0, 0, 8, 4 },

10
src/ImageSharp/Dithering/ErrorDiffusion/ErrorDiffuserBase.cs

@ -5,8 +5,8 @@ using System;
using System.Numerics;
using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Primitives;
namespace SixLabors.ImageSharp.Dithering.Base
{
@ -38,21 +38,21 @@ namespace SixLabors.ImageSharp.Dithering.Base
/// <summary>
/// The diffusion matrix
/// </summary>
private readonly Fast2DArray<float> matrix;
private readonly DenseMatrix<float> matrix;
/// <summary>
/// Initializes a new instance of the <see cref="ErrorDiffuserBase"/> class.
/// </summary>
/// <param name="matrix">The dithering matrix.</param>
/// <param name="divisor">The divisor.</param>
internal ErrorDiffuserBase(Fast2DArray<float> matrix, byte divisor)
internal ErrorDiffuserBase(DenseMatrix<float> matrix, byte divisor)
{
Guard.NotNull(matrix, nameof(matrix));
Guard.MustBeGreaterThan(divisor, 0, nameof(divisor));
this.matrix = matrix;
this.matrixWidth = this.matrix.Width;
this.matrixHeight = this.matrix.Height;
this.matrixWidth = this.matrix.Columns;
this.matrixHeight = this.matrix.Rows;
this.divisorVector = new Vector4(divisor);
this.startingOffset = 0;

4
src/ImageSharp/Dithering/ErrorDiffusion/FloydSteinbergDiffuser.cs

@ -2,7 +2,7 @@
// Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.Dithering.Base;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.Primitives;
namespace SixLabors.ImageSharp.Dithering
{
@ -15,7 +15,7 @@ namespace SixLabors.ImageSharp.Dithering
/// <summary>
/// The diffusion matrix
/// </summary>
private static readonly Fast2DArray<float> FloydSteinbergMatrix =
private static readonly DenseMatrix<float> FloydSteinbergMatrix =
new float[,]
{
{ 0, 0, 7 },

4
src/ImageSharp/Dithering/ErrorDiffusion/JarvisJudiceNinkeDiffuser.cs

@ -2,7 +2,7 @@
// Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.Dithering.Base;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.Primitives;
namespace SixLabors.ImageSharp.Dithering
{
@ -15,7 +15,7 @@ namespace SixLabors.ImageSharp.Dithering
/// <summary>
/// The diffusion matrix
/// </summary>
private static readonly Fast2DArray<float> JarvisJudiceNinkeMatrix =
private static readonly DenseMatrix<float> JarvisJudiceNinkeMatrix =
new float[,]
{
{ 0, 0, 0, 7, 5 },

4
src/ImageSharp/Dithering/ErrorDiffusion/Sierra2Diffuser.cs

@ -2,7 +2,7 @@
// Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.Dithering.Base;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.Primitives;
namespace SixLabors.ImageSharp.Dithering
{
@ -15,7 +15,7 @@ namespace SixLabors.ImageSharp.Dithering
/// <summary>
/// The diffusion matrix
/// </summary>
private static readonly Fast2DArray<float> Sierra2Matrix =
private static readonly DenseMatrix<float> Sierra2Matrix =
new float[,]
{
{ 0, 0, 0, 4, 3 },

4
src/ImageSharp/Dithering/ErrorDiffusion/Sierra3Diffuser.cs

@ -2,7 +2,7 @@
// Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.Dithering.Base;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.Primitives;
namespace SixLabors.ImageSharp.Dithering
{
@ -15,7 +15,7 @@ namespace SixLabors.ImageSharp.Dithering
/// <summary>
/// The diffusion matrix
/// </summary>
private static readonly Fast2DArray<float> Sierra3Matrix =
private static readonly DenseMatrix<float> Sierra3Matrix =
new float[,]
{
{ 0, 0, 0, 5, 3 },

4
src/ImageSharp/Dithering/ErrorDiffusion/SierraLiteDiffuser.cs

@ -2,7 +2,7 @@
// Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.Dithering.Base;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.Primitives;
namespace SixLabors.ImageSharp.Dithering
{
@ -15,7 +15,7 @@ namespace SixLabors.ImageSharp.Dithering
/// <summary>
/// The diffusion matrix
/// </summary>
private static readonly Fast2DArray<float> SierraLiteMatrix =
private static readonly DenseMatrix<float> SierraLiteMatrix =
new float[,]
{
{ 0, 0, 2 },

4
src/ImageSharp/Dithering/ErrorDiffusion/StevensonArceDiffuser.cs

@ -2,7 +2,7 @@
// Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.Dithering.Base;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.Primitives;
namespace SixLabors.ImageSharp.Dithering
{
@ -14,7 +14,7 @@ namespace SixLabors.ImageSharp.Dithering
/// <summary>
/// The diffusion matrix
/// </summary>
private static readonly Fast2DArray<float> StevensonArceMatrix =
private static readonly DenseMatrix<float> StevensonArceMatrix =
new float[,]
{
{ 0, 0, 0, 0, 0, 32, 0 },

4
src/ImageSharp/Dithering/ErrorDiffusion/StuckiDiffuser.cs

@ -2,7 +2,7 @@
// Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.Dithering.Base;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.Primitives;
namespace SixLabors.ImageSharp.Dithering
{
@ -15,7 +15,7 @@ namespace SixLabors.ImageSharp.Dithering
/// <summary>
/// The diffusion matrix
/// </summary>
private static readonly Fast2DArray<float> StuckiMatrix =
private static readonly DenseMatrix<float> StuckiMatrix =
new float[,]
{
{ 0, 0, 0, 8, 4 },

14
src/ImageSharp/Dithering/Ordered/OrderedDither.cs

@ -1,8 +1,8 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Primitives;
namespace SixLabors.ImageSharp.Dithering
{
@ -11,7 +11,7 @@ namespace SixLabors.ImageSharp.Dithering
/// </summary>
public class OrderedDither : IOrderedDither
{
private readonly Fast2DArray<uint> thresholdMatrix;
private readonly DenseMatrix<uint> thresholdMatrix;
private readonly int modulusX;
private readonly int modulusY;
@ -21,17 +21,17 @@ namespace SixLabors.ImageSharp.Dithering
/// <param name="length">The length of the matrix sides</param>
public OrderedDither(uint length)
{
Fast2DArray<uint> ditherMatrix = OrderedDitherFactory.CreateDitherMatrix(length);
this.modulusX = ditherMatrix.Width;
this.modulusY = ditherMatrix.Height;
DenseMatrix<uint> ditherMatrix = OrderedDitherFactory.CreateDitherMatrix(length);
this.modulusX = ditherMatrix.Columns;
this.modulusY = ditherMatrix.Rows;
// Adjust the matrix range for 0-255
// It looks like it's actually possible to dither an image using it's own colors. We should investigate for V2
// https://stackoverflow.com/questions/12422407/monochrome-dithering-in-javascript-bayer-atkinson-floyd-steinberg
int multiplier = 256 / ditherMatrix.Count;
for (int y = 0; y < ditherMatrix.Height; y++)
for (int y = 0; y < ditherMatrix.Rows; y++)
{
for (int x = 0; x < ditherMatrix.Width; x++)
for (int x = 0; x < ditherMatrix.Columns; x++)
{
ditherMatrix[y, x] = (uint)((ditherMatrix[y, x] + 1) * multiplier) - 1;
}

12
src/ImageSharp/Dithering/Ordered/OrderedDitherFactory.cs

@ -2,7 +2,7 @@
// Licensed under the Apache License, Version 2.0.
using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.Primitives;
namespace SixLabors.ImageSharp.Dithering
{
@ -16,8 +16,8 @@ namespace SixLabors.ImageSharp.Dithering
/// <see href="https://en.wikipedia.org/wiki/Ordered_dithering"/>
/// </summary>
/// <param name="length">The length of the matrix sides</param>
/// <returns>The <see cref="Fast2DArray{T}"/></returns>
public static Fast2DArray<uint> CreateDitherMatrix(uint length)
/// <returns>The <see cref="DenseMatrix{T}"/></returns>
public static DenseMatrix<uint> CreateDitherMatrix(uint length)
{
// Calculate the the logarithm of length to the base 2
uint exponent = 0;
@ -30,7 +30,7 @@ namespace SixLabors.ImageSharp.Dithering
while (length > bayerLength);
// Create our Bayer matrix that matches the given exponent and dimensions
var matrix = new Fast2DArray<uint>((int)length);
var matrix = new DenseMatrix<uint>((int)length);
uint i = 0;
for (int y = 0; y < length; y++)
{
@ -81,9 +81,9 @@ namespace SixLabors.ImageSharp.Dithering
uint result = 0;
for (uint i = 0; i < order; ++i)
{
uint xOdd_XOR_yOdd = (x & 1) ^ (y & 1);
uint xOddXorYOdd = (x & 1) ^ (y & 1);
uint xOdd = x & 1;
result = ((result << 1 | xOdd_XOR_yOdd) << 1) | xOdd;
result = ((result << 1 | xOddXorYOdd) << 1) | xOdd;
x >>= 1;
y >>= 1;
}

173
src/ImageSharp/Memory/Fast2DArray{T}.cs

@ -1,173 +0,0 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
using System.Diagnostics;
using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.Memory
{
/// <summary>
/// Provides fast access to 2D arrays.
/// </summary>
/// <typeparam name="T">The type of elements in the array.</typeparam>
internal struct Fast2DArray<T>
{
/// <summary>
/// The 1D representation of the 2D array.
/// </summary>
public T[] Data;
/// <summary>
/// Gets the width of the 2D array.
/// </summary>
public int Width;
/// <summary>
/// Gets the height of the 2D array.
/// </summary>
public int Height;
/// <summary>
/// Gets the number of items in the 2D array
/// </summary>
public int Count;
/// <summary>
/// Initializes a new instance of the <see cref="Fast2DArray{T}" /> struct.
/// </summary>
/// <param name="length">The length of each dimension.</param>
public Fast2DArray(int length)
: this(length, length)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="Fast2DArray{T}" /> struct.
/// </summary>
/// <param name="width">The width.</param>
/// <param name="height">The height.</param>
public Fast2DArray(int width, int height)
{
this.Height = height;
this.Width = width;
Guard.MustBeGreaterThan(width, 0, nameof(width));
Guard.MustBeGreaterThan(height, 0, nameof(height));
this.Count = width * height;
this.Data = new T[this.Count];
}
/// <summary>
/// Initializes a new instance of the <see cref="Fast2DArray{T}"/> struct.
/// </summary>
/// <param name="data">The 2D array to provide access to.</param>
public Fast2DArray(T[,] data)
{
Guard.NotNull(data, nameof(data));
this.Height = data.GetLength(0);
this.Width = data.GetLength(1);
Guard.MustBeGreaterThan(this.Width, 0, nameof(this.Width));
Guard.MustBeGreaterThan(this.Height, 0, nameof(this.Height));
this.Count = this.Width * this.Height;
this.Data = new T[this.Count];
for (int y = 0; y < this.Height; y++)
{
for (int x = 0; x < this.Width; x++)
{
this.Data[(y * this.Width) + x] = data[y, x];
}
}
}
/// <summary>
/// Gets or sets the item at the specified position.
/// </summary>
/// <param name="row">The row-coordinate of the item. Must be greater than or equal to zero and less than the height of the array.</param>
/// <param name="column">The column-coordinate of the item. Must be greater than or equal to zero and less than the width of the array.</param>
/// <returns>The <see typeparam="T"/> at the specified position.</returns>
public T this[int row, int column]
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
this.CheckCoordinates(row, column);
return this.Data[(row * this.Width) + column];
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
set
{
this.CheckCoordinates(row, column);
this.Data[(row * this.Width) + column] = value;
}
}
/// <summary>
/// Performs an implicit conversion from a 2D array to a <see cref="Fast2DArray{T}" />.
/// </summary>
/// <param name="data">The source array.</param>
/// <returns>
/// The <see cref="Fast2DArray{T}"/> representation on the source data.
/// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static implicit operator Fast2DArray<T>(T[,] data)
{
return new Fast2DArray<T>(data);
}
/// <summary>
/// Gets a <see cref="Span{T}"/> representing the row beginning from the the first item on that row.
/// </summary>
/// <param name="row">The y-coordinate of the row. Must be greater than or equal to zero and less than the height of the 2D array.</param>
/// <returns>The <see cref="Span{T}"/></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Span<T> GetRowSpan(int row)
{
this.CheckCoordinates(row);
return new Span<T>(this.Data, row * this.Width, this.Width);
}
/// <summary>
/// Checks the coordinates to ensure they are within bounds.
/// </summary>
/// <param name="row">The y-coordinate of the item. Must be greater than zero and smaller than the height of the array.</param>
/// <param name="column">The x-coordinate of the item. Must be greater than zero and smaller than the width of the array.</param>
/// <exception cref="ArgumentOutOfRangeException">
/// Thrown if the coordinates are not within the bounds of the array.
/// </exception>
[Conditional("DEBUG")]
private void CheckCoordinates(int row, int column)
{
if (row < 0 || row >= this.Height)
{
throw new ArgumentOutOfRangeException(nameof(row), row, $"{row} is outwith the array bounds.");
}
if (column < 0 || column >= this.Width)
{
throw new ArgumentOutOfRangeException(nameof(column), column, $"{column} is outwith the array bounds.");
}
}
/// <summary>
/// Checks the coordinates to ensure they are within bounds.
/// </summary>
/// <param name="row">The y-coordinate of the item. Must be greater than zero and smaller than the height of the array.</param>
/// <exception cref="ArgumentOutOfRangeException">
/// Thrown if the coordinates are not within the bounds of the image.
/// </exception>
[Conditional("DEBUG")]
private void CheckCoordinates(int row)
{
if (row < 0 || row >= this.Height)
{
throw new ArgumentOutOfRangeException(nameof(row), row, $"{row} is outwith the array bounds.");
}
}
}
}

8
src/ImageSharp/MetaData/Profiles/ICC/DataWriter/IccDataWriter.Matrix.cs

@ -2,7 +2,7 @@
// Licensed under the Apache License, Version 2.0.
using System.Numerics;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.Primitives;
namespace SixLabors.ImageSharp.MetaData.Profiles.Icc
{
@ -59,12 +59,12 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc
/// <param name="value">The matrix to write</param>
/// <param name="isSingle">True if the values are encoded as Single; false if encoded as Fix16</param>
/// <returns>The number of bytes written</returns>
public int WriteMatrix(Fast2DArray<float> value, bool isSingle)
public int WriteMatrix(DenseMatrix<float> value, bool isSingle)
{
int count = 0;
for (int y = 0; y < value.Height; y++)
for (int y = 0; y < value.Rows; y++)
{
for (int x = 0; x < value.Width; x++)
for (int x = 0; x < value.Columns; x++)
{
if (isSingle)
{

18
src/ImageSharp/MetaData/Profiles/ICC/MultiProcessElements/IccMatrixProcessElement.cs

@ -3,7 +3,8 @@
using System;
using System.Linq;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.Primitives;
namespace SixLabors.ImageSharp.MetaData.Profiles.Icc
{
@ -33,7 +34,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc
/// <summary>
/// Gets the two dimensional matrix with size of Input-Channels x Output-Channels
/// </summary>
public Fast2DArray<float> MatrixIxO { get; }
public DenseMatrix<float> MatrixIxO { get; }
/// <summary>
/// Gets the one dimensional matrix with size of Output-Channels x 1
@ -60,18 +61,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc
private bool EqualsMatrix(IccMatrixProcessElement element)
{
for (int x = 0; x < this.MatrixIxO.Width; x++)
{
for (int y = 0; y < this.MatrixIxO.Height; y++)
{
if (this.MatrixIxO[x, y] != element.MatrixIxO[x, y])
{
return false;
}
}
}
return true;
return this.MatrixIxO.Equals(element.MatrixIxO);
}
}
}

215
src/ImageSharp/Primitives/DenseMatrix{T}.cs

@ -0,0 +1,215 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
using System.Diagnostics;
using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.Primitives
{
/// <summary>
/// Represents a dense matrix with arbitrary elements.
/// Components that are adjacent in a column of the matrix are adjacent in the storage array.
/// The components are said to be stored in column major order.
/// </summary>
/// <typeparam name="T">The type of elements in the matrix.</typeparam>
public readonly struct DenseMatrix<T> : IEquatable<DenseMatrix<T>>
where T : struct, IEquatable<T>
{
/// <summary>
/// The 1D representation of the dense matrix.
/// </summary>
public readonly T[] Data;
/// <summary>
/// Gets the number of columns in the dense matrix.
/// </summary>
public readonly int Columns;
/// <summary>
/// Gets the number of rows in the dense matrix.
/// </summary>
public readonly int Rows;
/// <summary>
/// Gets the number of items in the array.
/// </summary>
public readonly int Count;
/// <summary>
/// Initializes a new instance of the <see cref=" DenseMatrix{T}" /> struct.
/// </summary>
/// <param name="length">The length of each side in the matrix.</param>
public DenseMatrix(int length)
: this(length, length)
{
}
/// <summary>
/// Initializes a new instance of the <see cref=" DenseMatrix{T}" /> struct.
/// </summary>
/// <param name="columns">The number of columns.</param>
/// <param name="rows">The number of rows.</param>
public DenseMatrix(int columns, int rows)
{
Guard.MustBeGreaterThan(columns, 0, nameof(columns));
Guard.MustBeGreaterThan(rows, 0, nameof(rows));
this.Rows = rows;
this.Columns = columns;
this.Count = columns * rows;
this.Data = new T[this.Columns * this.Rows];
}
/// <summary>
/// Initializes a new instance of the <see cref=" DenseMatrix{T}"/> struct.
/// </summary>
/// <param name="data">The 2D array to provide access to.</param>
public DenseMatrix(T[,] data)
{
Guard.NotNull(data, nameof(data));
int rows = data.GetLength(0);
int columns = data.GetLength(1);
Guard.MustBeGreaterThan(rows, 0, nameof(this.Rows));
Guard.MustBeGreaterThan(columns, 0, nameof(this.Columns));
this.Rows = rows;
this.Columns = columns;
this.Count = this.Columns * this.Rows;
this.Data = new T[this.Columns * this.Rows];
for (int y = 0; y < this.Rows; y++)
{
for (int x = 0; x < this.Columns; x++)
{
ref T value = ref this[y, x];
value = data[y, x];
}
}
}
/// <summary>
/// Gets or sets the item at the specified position.
/// </summary>
/// <param name="row">The row-coordinate of the item. Must be greater than or equal to zero and less than the height of the array.</param>
/// <param name="column">The column-coordinate of the item. Must be greater than or equal to zero and less than the width of the array.</param>
/// <returns>The <see typeparam="T"/> at the specified position.</returns>
public ref T this[int row, int column]
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
this.CheckCoordinates(row, column);
return ref this.Data[(row * this.Columns) + column];
}
}
/// <summary>
/// Performs an implicit conversion from a <see cref="T:T[,]" /> to a <see cref=" DenseMatrix{T}" />.
/// </summary>
/// <param name="data">The source array.</param>
/// <returns>
/// The <see cref="DenseMatrix{T}"/> representation on the source data.
/// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static implicit operator DenseMatrix<T>(T[,] data) => new DenseMatrix<T>(data);
/// <summary>
/// Performs an implicit conversion from a <see cref="DenseMatrix{T}"/> to a <see cref="T:T[,]" />.
/// </summary>
/// <param name="data">The source array.</param>
/// <returns>
/// The <see cref="T:T[,]"/> representation on the source data.
/// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#pragma warning disable SA1008 // Opening parenthesis should be spaced correctly
public static implicit operator T[,] (DenseMatrix<T> data)
#pragma warning restore SA1008 // Opening parenthesis should be spaced correctly
{
var result = new T[data.Rows, data.Columns];
for (int y = 0; y < data.Rows; y++)
{
for (int x = 0; x < data.Columns; x++)
{
ref T value = ref result[y, x];
value = data[y, x];
}
}
return result;
}
/// <summary>
/// Fills the matrix with the given value
/// </summary>
/// <param name="value">The value to fill each item with</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Fill(T value)
{
for (int i = 0; i < this.Data.Length; i++)
{
this.Data[i] = value;
}
}
/// <summary>
/// Clears the matrix setting each value to the default value for the element type
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Clear() => Array.Clear(this.Data, 0, this.Data.Length);
/// <summary>
/// Checks the coordinates to ensure they are within bounds.
/// </summary>
/// <param name="row">The y-coordinate of the item. Must be greater than zero and smaller than the height of the matrix.</param>
/// <param name="column">The x-coordinate of the item. Must be greater than zero and smaller than the width of the matrix.</param>
/// <exception cref="ArgumentOutOfRangeException">
/// Thrown if the coordinates are not within the bounds of the array.
/// </exception>
[Conditional("DEBUG")]
private void CheckCoordinates(int row, int column)
{
if (row < 0 || row >= this.Rows)
{
throw new ArgumentOutOfRangeException(nameof(row), row, $"{row} is outwith the matrix bounds.");
}
if (column < 0 || column >= this.Columns)
{
throw new ArgumentOutOfRangeException(nameof(column), column, $"{column} is outwith the matrix bounds.");
}
}
/// <inheritdoc/>
public bool Equals(DenseMatrix<T> other)
{
if (this.Columns != other.Columns)
{
return false;
}
if (this.Rows != other.Rows)
{
return false;
}
for (int i = 0; i < this.Data.Length; i++)
{
if (!this.Data[i].Equals(other.Data[i]))
{
return false;
}
}
return true;
}
/// <inheritdoc/>
public override bool Equals(object obj) => obj is DenseMatrix<T> matrix && this.Equals(matrix);
/// <inheritdoc/>
public override int GetHashCode() => this.Data.GetHashCode();
}
}

16
src/ImageSharp/Numerics/ValueSize.cs → src/ImageSharp/Primitives/ValueSize.cs

@ -4,7 +4,7 @@
using System;
using SixLabors.Primitives;
namespace SixLabors.ImageSharp
namespace SixLabors.ImageSharp.Primitives
{
/// <summary>
/// Represents a value in relation to a value on the image
@ -28,7 +28,7 @@ namespace SixLabors.ImageSharp
}
/// <summary>
/// The different vlaue types
/// Enumerates the different value types
/// </summary>
public enum ValueSizeType
{
@ -120,10 +120,22 @@ namespace SixLabors.ImageSharp
return $"{this.Value} - {this.Type}";
}
/// <inheritdoc/>
public override bool Equals(object obj)
{
return obj is ValueSize size && this.Equals(size);
}
/// <inheritdoc/>
public bool Equals(ValueSize other)
{
return this.Type == other.Type && this.Value.Equals(other.Value);
}
/// <inheritdoc/>
public override int GetHashCode()
{
return HashHelpers.Combine(this.Value.GetHashCode(), this.Type.GetHashCode());
}
}
}

17
src/ImageSharp/Processing/Convolution/Processors/BoxBlurProcessor.cs

@ -1,9 +1,8 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing.Processors;
using SixLabors.ImageSharp.Primitives;
using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing.Convolution.Processors
@ -42,12 +41,12 @@ namespace SixLabors.ImageSharp.Processing.Convolution.Processors
/// <summary>
/// Gets the horizontal gradient operator.
/// </summary>
public Fast2DArray<float> KernelX { get; }
public DenseMatrix<float> KernelX { get; }
/// <summary>
/// Gets the vertical gradient operator.
/// </summary>
public Fast2DArray<float> KernelY { get; }
public DenseMatrix<float> KernelY { get; }
/// <inheritdoc/>
protected override void OnFrameApply(ImageFrame<TPixel> source, Rectangle sourceRectangle, Configuration configuration)
@ -59,13 +58,13 @@ namespace SixLabors.ImageSharp.Processing.Convolution.Processors
/// Create a 1 dimensional Box kernel.
/// </summary>
/// <param name="horizontal">Whether to calculate a horizontal kernel.</param>
/// <returns>The <see cref="Fast2DArray{T}"/></returns>
private Fast2DArray<float> CreateBoxKernel(bool horizontal)
/// <returns>The <see cref="DenseMatrix{T}"/></returns>
private DenseMatrix<float> CreateBoxKernel(bool horizontal)
{
int size = this.kernelSize;
Fast2DArray<float> kernel = horizontal
? new Fast2DArray<float>(size, 1)
: new Fast2DArray<float>(1, size);
DenseMatrix<float> kernel = horizontal
? new DenseMatrix<float>(size, 1)
: new DenseMatrix<float>(1, size);
float sum = 0F;
for (int i = 0; i < size; i++)

17
src/ImageSharp/Processing/Convolution/Processors/Convolution2DProcessor.cs

@ -7,9 +7,10 @@ using System.Threading.Tasks;
using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Primitives;
using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing.Processors
namespace SixLabors.ImageSharp.Processing.Convolution.Processors
{
/// <summary>
/// Defines a processor that uses two one-dimensional matrices to perform convolution against an image.
@ -23,7 +24,7 @@ namespace SixLabors.ImageSharp.Processing.Processors
/// </summary>
/// <param name="kernelX">The horizontal gradient operator.</param>
/// <param name="kernelY">The vertical gradient operator.</param>
public Convolution2DProcessor(Fast2DArray<float> kernelX, Fast2DArray<float> kernelY)
public Convolution2DProcessor(DenseMatrix<float> kernelX, DenseMatrix<float> kernelY)
{
this.KernelX = kernelX;
this.KernelY = kernelY;
@ -32,20 +33,20 @@ namespace SixLabors.ImageSharp.Processing.Processors
/// <summary>
/// Gets the horizontal gradient operator.
/// </summary>
public Fast2DArray<float> KernelX { get; }
public DenseMatrix<float> KernelX { get; }
/// <summary>
/// Gets the vertical gradient operator.
/// </summary>
public Fast2DArray<float> KernelY { get; }
public DenseMatrix<float> KernelY { get; }
/// <inheritdoc/>
protected override void OnFrameApply(ImageFrame<TPixel> source, Rectangle sourceRectangle, Configuration configuration)
{
int kernelYHeight = this.KernelY.Height;
int kernelYWidth = this.KernelY.Width;
int kernelXHeight = this.KernelX.Height;
int kernelXWidth = this.KernelX.Width;
int kernelYHeight = this.KernelY.Rows;
int kernelYWidth = this.KernelY.Columns;
int kernelXHeight = this.KernelX.Rows;
int kernelXWidth = this.KernelX.Columns;
int radiusY = kernelYHeight >> 1;
int radiusX = kernelXWidth >> 1;

16
src/ImageSharp/Processing/Convolution/Processors/Convolution2PassProcessor.cs

@ -4,13 +4,13 @@
using System;
using System.Numerics;
using System.Threading.Tasks;
using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Helpers;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Primitives;
using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing.Processors
namespace SixLabors.ImageSharp.Processing.Convolution.Processors
{
/// <summary>
/// Defines a processor that uses two one-dimensional matrices to perform two-pass convolution against an image.
@ -24,7 +24,7 @@ namespace SixLabors.ImageSharp.Processing.Processors
/// </summary>
/// <param name="kernelX">The horizontal gradient operator.</param>
/// <param name="kernelY">The vertical gradient operator.</param>
public Convolution2PassProcessor(Fast2DArray<float> kernelX, Fast2DArray<float> kernelY)
public Convolution2PassProcessor(DenseMatrix<float> kernelX, DenseMatrix<float> kernelY)
{
this.KernelX = kernelX;
this.KernelY = kernelY;
@ -33,12 +33,12 @@ namespace SixLabors.ImageSharp.Processing.Processors
/// <summary>
/// Gets the horizontal gradient operator.
/// </summary>
public Fast2DArray<float> KernelX { get; }
public DenseMatrix<float> KernelX { get; }
/// <summary>
/// Gets the vertical gradient operator.
/// </summary>
public Fast2DArray<float> KernelY { get; }
public DenseMatrix<float> KernelY { get; }
/// <inheritdoc/>
protected override void OnFrameApply(ImageFrame<TPixel> source, Rectangle sourceRectangle, Configuration configuration)
@ -67,11 +67,11 @@ namespace SixLabors.ImageSharp.Processing.Processors
Buffer2D<TPixel> targetPixels,
Buffer2D<TPixel> sourcePixels,
Rectangle sourceRectangle,
Fast2DArray<float> kernel,
DenseMatrix<float> kernel,
ParallelOptions parallelOptions)
{
int kernelHeight = kernel.Height;
int kernelWidth = kernel.Width;
int kernelHeight = kernel.Rows;
int kernelWidth = kernel.Columns;
int radiusY = kernelHeight >> 1;
int radiusX = kernelWidth >> 1;

9
src/ImageSharp/Processing/Convolution/Processors/ConvolutionProcessor.cs

@ -8,9 +8,10 @@ using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Helpers;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Primitives;
using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing.Processors
namespace SixLabors.ImageSharp.Processing.Convolution.Processors
{
/// <summary>
/// Defines a processor that uses a 2 dimensional matrix to perform convolution against an image.
@ -23,7 +24,7 @@ namespace SixLabors.ImageSharp.Processing.Processors
/// Initializes a new instance of the <see cref="ConvolutionProcessor{TPixel}"/> class.
/// </summary>
/// <param name="kernelXY">The 2d gradient operator.</param>
public ConvolutionProcessor(Fast2DArray<float> kernelXY)
public ConvolutionProcessor(DenseMatrix<float> kernelXY)
{
this.KernelXY = kernelXY;
}
@ -31,12 +32,12 @@ namespace SixLabors.ImageSharp.Processing.Processors
/// <summary>
/// Gets the 2d gradient operator.
/// </summary>
public Fast2DArray<float> KernelXY { get; }
public DenseMatrix<float> KernelXY { get; }
/// <inheritdoc/>
protected override void OnFrameApply(ImageFrame<TPixel> source, Rectangle sourceRectangle, Configuration configuration)
{
int kernelLength = this.KernelXY.Height;
int kernelLength = this.KernelXY.Rows;
int radius = kernelLength >> 1;
int startY = sourceRectangle.Y;

9
src/ImageSharp/Processing/Convolution/Processors/EdgeDetector2DProcessor.cs

@ -1,10 +1,9 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Primitives;
using SixLabors.ImageSharp.Processing.Filters.Processors;
using SixLabors.ImageSharp.Processing.Processors;
using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing.Convolution.Processors
@ -22,7 +21,7 @@ namespace SixLabors.ImageSharp.Processing.Convolution.Processors
/// <param name="kernelX">The horizontal gradient operator.</param>
/// <param name="kernelY">The vertical gradient operator.</param>
/// <param name="grayscale">Whether to convert the image to grayscale before performing edge detection.</param>
protected EdgeDetector2DProcessor(Fast2DArray<float> kernelX, Fast2DArray<float> kernelY, bool grayscale)
protected EdgeDetector2DProcessor(DenseMatrix<float> kernelX, DenseMatrix<float> kernelY, bool grayscale)
{
this.KernelX = kernelX;
this.KernelY = kernelY;
@ -32,12 +31,12 @@ namespace SixLabors.ImageSharp.Processing.Convolution.Processors
/// <summary>
/// Gets the horizontal gradient operator.
/// </summary>
public Fast2DArray<float> KernelX { get; }
public DenseMatrix<float> KernelX { get; }
/// <summary>
/// Gets the vertical gradient operator.
/// </summary>
public Fast2DArray<float> KernelY { get; }
public DenseMatrix<float> KernelY { get; }
/// <inheritdoc/>
public bool Grayscale { get; set; }

21
src/ImageSharp/Processing/Convolution/Processors/EdgeDetectorCompassProcessor.cs

@ -4,10 +4,9 @@
using System;
using System.Numerics;
using System.Threading.Tasks;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Primitives;
using SixLabors.ImageSharp.Processing.Filters.Processors;
using SixLabors.ImageSharp.Processing.Processors;
using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing.Convolution.Processors
@ -31,42 +30,42 @@ namespace SixLabors.ImageSharp.Processing.Convolution.Processors
/// <summary>
/// Gets the North gradient operator
/// </summary>
public abstract Fast2DArray<float> North { get; }
public abstract DenseMatrix<float> North { get; }
/// <summary>
/// Gets the NorthWest gradient operator
/// </summary>
public abstract Fast2DArray<float> NorthWest { get; }
public abstract DenseMatrix<float> NorthWest { get; }
/// <summary>
/// Gets the West gradient operator
/// </summary>
public abstract Fast2DArray<float> West { get; }
public abstract DenseMatrix<float> West { get; }
/// <summary>
/// Gets the SouthWest gradient operator
/// </summary>
public abstract Fast2DArray<float> SouthWest { get; }
public abstract DenseMatrix<float> SouthWest { get; }
/// <summary>
/// Gets the South gradient operator
/// </summary>
public abstract Fast2DArray<float> South { get; }
public abstract DenseMatrix<float> South { get; }
/// <summary>
/// Gets the SouthEast gradient operator
/// </summary>
public abstract Fast2DArray<float> SouthEast { get; }
public abstract DenseMatrix<float> SouthEast { get; }
/// <summary>
/// Gets the East gradient operator
/// </summary>
public abstract Fast2DArray<float> East { get; }
public abstract DenseMatrix<float> East { get; }
/// <summary>
/// Gets the NorthEast gradient operator
/// </summary>
public abstract Fast2DArray<float> NorthEast { get; }
public abstract DenseMatrix<float> NorthEast { get; }
/// <inheritdoc/>
public bool Grayscale { get; }
@ -83,7 +82,7 @@ namespace SixLabors.ImageSharp.Processing.Convolution.Processors
/// <inheritdoc />
protected override void OnFrameApply(ImageFrame<TPixel> source, Rectangle sourceRectangle, Configuration configuration)
{
Fast2DArray<float>[] kernels = { this.North, this.NorthWest, this.West, this.SouthWest, this.South, this.SouthEast, this.East, this.NorthEast };
DenseMatrix<float>[] kernels = { this.North, this.NorthWest, this.West, this.SouthWest, this.South, this.SouthEast, this.East, this.NorthEast };
int startY = sourceRectangle.Y;
int endY = sourceRectangle.Bottom;

7
src/ImageSharp/Processing/Convolution/Processors/EdgeDetectorProcessor.cs

@ -1,10 +1,9 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Primitives;
using SixLabors.ImageSharp.Processing.Filters.Processors;
using SixLabors.ImageSharp.Processing.Processors;
using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing.Convolution.Processors
@ -21,7 +20,7 @@ namespace SixLabors.ImageSharp.Processing.Convolution.Processors
/// </summary>
/// <param name="kernelXY">The 2d gradient operator.</param>
/// <param name="grayscale">Whether to convert the image to grayscale before performing edge detection.</param>
protected EdgeDetectorProcessor(Fast2DArray<float> kernelXY, bool grayscale)
protected EdgeDetectorProcessor(DenseMatrix<float> kernelXY, bool grayscale)
{
this.KernelXY = kernelXY;
this.Grayscale = grayscale;
@ -33,7 +32,7 @@ namespace SixLabors.ImageSharp.Processing.Convolution.Processors
/// <summary>
/// Gets the 2d gradient operator.
/// </summary>
public Fast2DArray<float> KernelXY { get; }
public DenseMatrix<float> KernelXY { get; }
/// <inheritdoc/>
protected override void BeforeFrameApply(ImageFrame<TPixel> source, Rectangle sourceRectangle, Configuration configuration)

17
src/ImageSharp/Processing/Convolution/Processors/GaussianBlurProcessor.cs

@ -2,9 +2,8 @@
// Licensed under the Apache License, Version 2.0.
using System;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing.Processors;
using SixLabors.ImageSharp.Primitives;
using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing.Convolution.Processors
@ -73,12 +72,12 @@ namespace SixLabors.ImageSharp.Processing.Convolution.Processors
/// <summary>
/// Gets the horizontal gradient operator.
/// </summary>
public Fast2DArray<float> KernelX { get; }
public DenseMatrix<float> KernelX { get; }
/// <summary>
/// Gets the vertical gradient operator.
/// </summary>
public Fast2DArray<float> KernelY { get; }
public DenseMatrix<float> KernelY { get; }
/// <inheritdoc/>
protected override void OnFrameApply(ImageFrame<TPixel> source, Rectangle sourceRectangle, Configuration configuration)
@ -90,14 +89,14 @@ namespace SixLabors.ImageSharp.Processing.Convolution.Processors
/// Create a 1 dimensional Gaussian kernel using the Gaussian G(x) function
/// </summary>
/// <param name="horizontal">Whether to calculate a horizontal kernel.</param>
/// <returns>The <see cref="Fast2DArray{T}"/></returns>
private Fast2DArray<float> CreateGaussianKernel(bool horizontal)
/// <returns>The <see cref="DenseMatrix{T}"/></returns>
private DenseMatrix<float> CreateGaussianKernel(bool horizontal)
{
int size = this.kernelSize;
float weight = this.Sigma;
Fast2DArray<float> kernel = horizontal
? new Fast2DArray<float>(size, 1)
: new Fast2DArray<float>(1, size);
DenseMatrix<float> kernel = horizontal
? new DenseMatrix<float>(size, 1)
: new DenseMatrix<float>(1, size);
float sum = 0F;
float midpoint = (size - 1) / 2F;

17
src/ImageSharp/Processing/Convolution/Processors/GaussianSharpenProcessor.cs

@ -2,9 +2,8 @@
// Licensed under the Apache License, Version 2.0.
using System;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing.Processors;
using SixLabors.ImageSharp.Primitives;
using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing.Convolution.Processors
@ -75,12 +74,12 @@ namespace SixLabors.ImageSharp.Processing.Convolution.Processors
/// <summary>
/// Gets the horizontal gradient operator.
/// </summary>
public Fast2DArray<float> KernelX { get; }
public DenseMatrix<float> KernelX { get; }
/// <summary>
/// Gets the vertical gradient operator.
/// </summary>
public Fast2DArray<float> KernelY { get; }
public DenseMatrix<float> KernelY { get; }
/// <inheritdoc/>
protected override void OnFrameApply(ImageFrame<TPixel> source, Rectangle sourceRectangle, Configuration configuration)
@ -92,14 +91,14 @@ namespace SixLabors.ImageSharp.Processing.Convolution.Processors
/// Create a 1 dimensional Gaussian kernel using the Gaussian G(x) function
/// </summary>
/// <param name="horizontal">Whether to calculate a horizontal kernel.</param>
/// <returns>The <see cref="Fast2DArray{T}"/></returns>
private Fast2DArray<float> CreateGaussianKernel(bool horizontal)
/// <returns>The <see cref="DenseMatrix{T}"/></returns>
private DenseMatrix<float> CreateGaussianKernel(bool horizontal)
{
int size = this.kernelSize;
float weight = this.Sigma;
Fast2DArray<float> kernel = horizontal
? new Fast2DArray<float>(size, 1)
: new Fast2DArray<float>(1, size);
DenseMatrix<float> kernel = horizontal
? new DenseMatrix<float>(size, 1)
: new DenseMatrix<float>(1, size);
float sum = 0;

6
src/ImageSharp/Processing/Convolution/Processors/KayyaliKernels.cs

@ -1,7 +1,7 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.Primitives;
namespace SixLabors.ImageSharp.Processing.Convolution.Processors
{
@ -13,7 +13,7 @@ namespace SixLabors.ImageSharp.Processing.Convolution.Processors
/// <summary>
/// Gets the horizontal gradient operator.
/// </summary>
public static Fast2DArray<float> KayyaliX =>
public static DenseMatrix<float> KayyaliX =>
new float[,]
{
{ 6, 0, -6 },
@ -24,7 +24,7 @@ namespace SixLabors.ImageSharp.Processing.Convolution.Processors
/// <summary>
/// Gets the vertical gradient operator.
/// </summary>
public static Fast2DArray<float> KayyaliY =>
public static DenseMatrix<float> KayyaliY =>
new float[,]
{
{ -6, 0, 6 },

18
src/ImageSharp/Processing/Convolution/Processors/KirschProcessor.cs

@ -1,8 +1,8 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Primitives;
namespace SixLabors.ImageSharp.Processing.Convolution.Processors
{
@ -23,27 +23,27 @@ namespace SixLabors.ImageSharp.Processing.Convolution.Processors
}
/// <inheritdoc/>
public override Fast2DArray<float> North => KirshKernels.KirschNorth;
public override DenseMatrix<float> North => KirshKernels.KirschNorth;
/// <inheritdoc/>
public override Fast2DArray<float> NorthWest => KirshKernels.KirschNorthWest;
public override DenseMatrix<float> NorthWest => KirshKernels.KirschNorthWest;
/// <inheritdoc/>
public override Fast2DArray<float> West => KirshKernels.KirschWest;
public override DenseMatrix<float> West => KirshKernels.KirschWest;
/// <inheritdoc/>
public override Fast2DArray<float> SouthWest => KirshKernels.KirschSouthWest;
public override DenseMatrix<float> SouthWest => KirshKernels.KirschSouthWest;
/// <inheritdoc/>
public override Fast2DArray<float> South => KirshKernels.KirschSouth;
public override DenseMatrix<float> South => KirshKernels.KirschSouth;
/// <inheritdoc/>
public override Fast2DArray<float> SouthEast => KirshKernels.KirschSouthEast;
public override DenseMatrix<float> SouthEast => KirshKernels.KirschSouthEast;
/// <inheritdoc/>
public override Fast2DArray<float> East => KirshKernels.KirschEast;
public override DenseMatrix<float> East => KirshKernels.KirschEast;
/// <inheritdoc/>
public override Fast2DArray<float> NorthEast => KirshKernels.KirschNorthEast;
public override DenseMatrix<float> NorthEast => KirshKernels.KirschNorthEast;
}
}

18
src/ImageSharp/Processing/Convolution/Processors/KirshKernels.cs

@ -1,7 +1,7 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.Primitives;
namespace SixLabors.ImageSharp.Processing.Convolution.Processors
{
@ -13,7 +13,7 @@ namespace SixLabors.ImageSharp.Processing.Convolution.Processors
/// <summary>
/// Gets the North gradient operator
/// </summary>
public static Fast2DArray<float> KirschNorth =>
public static DenseMatrix<float> KirschNorth =>
new float[,]
{
{ 5, 5, 5 },
@ -24,7 +24,7 @@ namespace SixLabors.ImageSharp.Processing.Convolution.Processors
/// <summary>
/// Gets the NorthWest gradient operator
/// </summary>
public static Fast2DArray<float> KirschNorthWest =>
public static DenseMatrix<float> KirschNorthWest =>
new float[,]
{
{ 5, 5, -3 },
@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Processing.Convolution.Processors
/// <summary>
/// Gets the West gradient operator
/// </summary>
public static Fast2DArray<float> KirschWest =>
public static DenseMatrix<float> KirschWest =>
new float[,]
{
{ 5, -3, -3 },
@ -46,7 +46,7 @@ namespace SixLabors.ImageSharp.Processing.Convolution.Processors
/// <summary>
/// Gets the SouthWest gradient operator
/// </summary>
public static Fast2DArray<float> KirschSouthWest =>
public static DenseMatrix<float> KirschSouthWest =>
new float[,]
{
{ -3, -3, -3 },
@ -57,7 +57,7 @@ namespace SixLabors.ImageSharp.Processing.Convolution.Processors
/// <summary>
/// Gets the South gradient operator
/// </summary>
public static Fast2DArray<float> KirschSouth =>
public static DenseMatrix<float> KirschSouth =>
new float[,]
{
{ -3, -3, -3 },
@ -68,7 +68,7 @@ namespace SixLabors.ImageSharp.Processing.Convolution.Processors
/// <summary>
/// Gets the SouthEast gradient operator
/// </summary>
public static Fast2DArray<float> KirschSouthEast =>
public static DenseMatrix<float> KirschSouthEast =>
new float[,]
{
{ -3, -3, -3 },
@ -79,7 +79,7 @@ namespace SixLabors.ImageSharp.Processing.Convolution.Processors
/// <summary>
/// Gets the East gradient operator
/// </summary>
public static Fast2DArray<float> KirschEast =>
public static DenseMatrix<float> KirschEast =>
new float[,]
{
{ -3, -3, 5 },
@ -90,7 +90,7 @@ namespace SixLabors.ImageSharp.Processing.Convolution.Processors
/// <summary>
/// Gets the NorthEast gradient operator
/// </summary>
public static Fast2DArray<float> KirschNorthEast =>
public static DenseMatrix<float> KirschNorthEast =>
new float[,]
{
{ -3, 5, 5 },

17
src/ImageSharp/Processing/Convolution/Processors/LaplacianKernelFactory.cs

@ -1,7 +1,7 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.Primitives;
namespace SixLabors.ImageSharp.Processing.Convolution.Processors
{
@ -15,21 +15,14 @@ namespace SixLabors.ImageSharp.Processing.Convolution.Processors
/// <see href="https://stackoverflow.com/questions/19422029/how-to-calculate-a-laplacian-mask-or-any-size"/>
/// </summary>
/// <param name="length">The length of the matrix sides</param>
/// <returns>The <see cref="Fast2DArray{T}"/></returns>
public static Fast2DArray<float> CreateKernel(uint length)
/// <returns>The <see cref="DenseMatrix{T}"/></returns>
public static DenseMatrix<float> CreateKernel(uint length)
{
Guard.MustBeGreaterThanOrEqualTo(length, 3u, nameof(length));
Guard.IsFalse(length % 2 == 0, nameof(length), "The kernel length must be an odd number.");
var kernel = new Fast2DArray<float>((int)length);
for (int y = 0; y < kernel.Height; y++)
{
for (int x = 0; x < kernel.Width; x++)
{
kernel[x, y] = -1;
}
}
var kernel = new DenseMatrix<float>((int)length);
kernel.Fill(-1);
int mid = (int)(length / 2);
kernel[mid, mid] = (length * length) - 1;

8
src/ImageSharp/Processing/Convolution/Processors/LaplacianKernels.cs

@ -1,7 +1,7 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.Primitives;
namespace SixLabors.ImageSharp.Processing.Convolution.Processors
{
@ -13,17 +13,17 @@ namespace SixLabors.ImageSharp.Processing.Convolution.Processors
/// <summary>
/// Gets the 3x3 Laplacian kernel
/// </summary>
public static Fast2DArray<float> Laplacian3x3 => LaplacianKernelFactory.CreateKernel(3);
public static DenseMatrix<float> Laplacian3x3 => LaplacianKernelFactory.CreateKernel(3);
/// <summary>
/// Gets the 5x5 Laplacian kernel
/// </summary>
public static Fast2DArray<float> Laplacian5x5 => LaplacianKernelFactory.CreateKernel(5);
public static DenseMatrix<float> Laplacian5x5 => LaplacianKernelFactory.CreateKernel(5);
/// <summary>
/// Gets the Laplacian of Gaussian kernel.
/// </summary>
public static Fast2DArray<float> LaplacianOfGaussianXY =>
public static DenseMatrix<float> LaplacianOfGaussianXY =>
new float[,]
{
{ 0, 0, -1, 0, 0 },

6
src/ImageSharp/Processing/Convolution/Processors/PrewittKernels.cs

@ -1,7 +1,7 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.Primitives;
namespace SixLabors.ImageSharp.Processing.Convolution.Processors
{
@ -13,7 +13,7 @@ namespace SixLabors.ImageSharp.Processing.Convolution.Processors
/// <summary>
/// Gets the horizontal gradient operator.
/// </summary>
public static Fast2DArray<float> PrewittX =>
public static DenseMatrix<float> PrewittX =>
new float[,]
{
{ -1, 0, 1 },
@ -24,7 +24,7 @@ namespace SixLabors.ImageSharp.Processing.Convolution.Processors
/// <summary>
/// Gets the vertical gradient operator.
/// </summary>
public static Fast2DArray<float> PrewittY =>
public static DenseMatrix<float> PrewittY =>
new float[,]
{
{ 1, 1, 1 },

6
src/ImageSharp/Processing/Convolution/Processors/RobertsCrossKernels.cs

@ -1,7 +1,7 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.Primitives;
namespace SixLabors.ImageSharp.Processing.Convolution.Processors
{
@ -13,7 +13,7 @@ namespace SixLabors.ImageSharp.Processing.Convolution.Processors
/// <summary>
/// Gets the horizontal gradient operator.
/// </summary>
public static Fast2DArray<float> RobertsCrossX =>
public static DenseMatrix<float> RobertsCrossX =>
new float[,]
{
{ 1, 0 },
@ -23,7 +23,7 @@ namespace SixLabors.ImageSharp.Processing.Convolution.Processors
/// <summary>
/// Gets the vertical gradient operator.
/// </summary>
public static Fast2DArray<float> RobertsCrossY =>
public static DenseMatrix<float> RobertsCrossY =>
new float[,]
{
{ 0, 1 },

18
src/ImageSharp/Processing/Convolution/Processors/RobinsonKernels.cs

@ -1,7 +1,7 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.Primitives;
namespace SixLabors.ImageSharp.Processing.Convolution.Processors
{
@ -13,7 +13,7 @@ namespace SixLabors.ImageSharp.Processing.Convolution.Processors
/// <summary>
/// Gets the North gradient operator
/// </summary>
public static Fast2DArray<float> RobinsonNorth =>
public static DenseMatrix<float> RobinsonNorth =>
new float[,]
{
{ 1, 2, 1 },
@ -24,7 +24,7 @@ namespace SixLabors.ImageSharp.Processing.Convolution.Processors
/// <summary>
/// Gets the NorthWest gradient operator
/// </summary>
public static Fast2DArray<float> RobinsonNorthWest =>
public static DenseMatrix<float> RobinsonNorthWest =>
new float[,]
{
{ 2, 1, 0 },
@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Processing.Convolution.Processors
/// <summary>
/// Gets the West gradient operator
/// </summary>
public static Fast2DArray<float> RobinsonWest =>
public static DenseMatrix<float> RobinsonWest =>
new float[,]
{
{ 1, 0, -1 },
@ -46,7 +46,7 @@ namespace SixLabors.ImageSharp.Processing.Convolution.Processors
/// <summary>
/// Gets the SouthWest gradient operator
/// </summary>
public static Fast2DArray<float> RobinsonSouthWest =>
public static DenseMatrix<float> RobinsonSouthWest =>
new float[,]
{
{ 0, -1, -2 },
@ -57,7 +57,7 @@ namespace SixLabors.ImageSharp.Processing.Convolution.Processors
/// <summary>
/// Gets the South gradient operator
/// </summary>
public static Fast2DArray<float> RobinsonSouth =>
public static DenseMatrix<float> RobinsonSouth =>
new float[,]
{
{ -1, -2, -1 },
@ -68,7 +68,7 @@ namespace SixLabors.ImageSharp.Processing.Convolution.Processors
/// <summary>
/// Gets the SouthEast gradient operator
/// </summary>
public static Fast2DArray<float> RobinsonSouthEast =>
public static DenseMatrix<float> RobinsonSouthEast =>
new float[,]
{
{ -2, -1, 0 },
@ -79,7 +79,7 @@ namespace SixLabors.ImageSharp.Processing.Convolution.Processors
/// <summary>
/// Gets the East gradient operator
/// </summary>
public static Fast2DArray<float> RobinsonEast =>
public static DenseMatrix<float> RobinsonEast =>
new float[,]
{
{ -1, 0, 1 },
@ -90,7 +90,7 @@ namespace SixLabors.ImageSharp.Processing.Convolution.Processors
/// <summary>
/// Gets the NorthEast gradient operator
/// </summary>
public static Fast2DArray<float> RobinsonNorthEast =>
public static DenseMatrix<float> RobinsonNorthEast =>
new float[,]
{
{ 0, 1, 2 },

18
src/ImageSharp/Processing/Convolution/Processors/RobinsonProcessor.cs

@ -1,8 +1,8 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Primitives;
namespace SixLabors.ImageSharp.Processing.Convolution.Processors
{
@ -24,27 +24,27 @@ namespace SixLabors.ImageSharp.Processing.Convolution.Processors
}
/// <inheritdoc/>
public override Fast2DArray<float> North => RobinsonKernels.RobinsonNorth;
public override DenseMatrix<float> North => RobinsonKernels.RobinsonNorth;
/// <inheritdoc/>
public override Fast2DArray<float> NorthWest => RobinsonKernels.RobinsonNorthWest;
public override DenseMatrix<float> NorthWest => RobinsonKernels.RobinsonNorthWest;
/// <inheritdoc/>
public override Fast2DArray<float> West => RobinsonKernels.RobinsonWest;
public override DenseMatrix<float> West => RobinsonKernels.RobinsonWest;
/// <inheritdoc/>
public override Fast2DArray<float> SouthWest => RobinsonKernels.RobinsonSouthWest;
public override DenseMatrix<float> SouthWest => RobinsonKernels.RobinsonSouthWest;
/// <inheritdoc/>
public override Fast2DArray<float> South => RobinsonKernels.RobinsonSouth;
public override DenseMatrix<float> South => RobinsonKernels.RobinsonSouth;
/// <inheritdoc/>
public override Fast2DArray<float> SouthEast => RobinsonKernels.RobinsonSouthEast;
public override DenseMatrix<float> SouthEast => RobinsonKernels.RobinsonSouthEast;
/// <inheritdoc/>
public override Fast2DArray<float> East => RobinsonKernels.RobinsonEast;
public override DenseMatrix<float> East => RobinsonKernels.RobinsonEast;
/// <inheritdoc/>
public override Fast2DArray<float> NorthEast => RobinsonKernels.RobinsonNorthEast;
public override DenseMatrix<float> NorthEast => RobinsonKernels.RobinsonNorthEast;
}
}

6
src/ImageSharp/Processing/Convolution/Processors/ScharrKernels.cs

@ -1,7 +1,7 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.Primitives;
namespace SixLabors.ImageSharp.Processing.Convolution.Processors
{
@ -13,7 +13,7 @@ namespace SixLabors.ImageSharp.Processing.Convolution.Processors
/// <summary>
/// Gets the horizontal gradient operator.
/// </summary>
public static Fast2DArray<float> ScharrX =>
public static DenseMatrix<float> ScharrX =>
new float[,]
{
{ -3, 0, 3 },
@ -24,7 +24,7 @@ namespace SixLabors.ImageSharp.Processing.Convolution.Processors
/// <summary>
/// Gets the vertical gradient operator.
/// </summary>
public static Fast2DArray<float> ScharrY =>
public static DenseMatrix<float> ScharrY =>
new float[,]
{
{ 3, 10, 3 },

6
src/ImageSharp/Processing/Convolution/Processors/SobelKernels.cs

@ -1,7 +1,7 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.Primitives;
namespace SixLabors.ImageSharp.Processing.Convolution.Processors
{
@ -13,7 +13,7 @@ namespace SixLabors.ImageSharp.Processing.Convolution.Processors
/// <summary>
/// Gets the horizontal gradient operator.
/// </summary>
public static Fast2DArray<float> SobelX =>
public static DenseMatrix<float> SobelX =>
new float[,]
{
{ -1, 0, 1 },
@ -24,7 +24,7 @@ namespace SixLabors.ImageSharp.Processing.Convolution.Processors
/// <summary>
/// Gets the vertical gradient operator.
/// </summary>
public static Fast2DArray<float> SobelY =>
public static DenseMatrix<float> SobelY =>
new float[,]
{
{ -1, -2, -1 },

1
src/ImageSharp/Processing/Overlays/Glow.cs

@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Primitives;
using SixLabors.ImageSharp.Processing.Processors;
using SixLabors.ImageSharp.Processing.Processors.Overlays;
using SixLabors.Primitives;

1
src/ImageSharp/Processing/Overlays/Vignette.cs

@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Primitives;
using SixLabors.ImageSharp.Processing.Processors;
using SixLabors.ImageSharp.Processing.Processors.Overlays;
using SixLabors.Primitives;

1
src/ImageSharp/Processing/Processors/Overlays/GlowProcessor.cs

@ -8,6 +8,7 @@ using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Helpers;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Primitives;
using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing.Processors.Overlays

1
src/ImageSharp/Processing/Processors/Overlays/VignetteProcessor.cs

@ -8,6 +8,7 @@ using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Helpers;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Primitives;
using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing.Processors.Overlays

47
tests/ImageSharp.Benchmarks/General/Array2D.cs

@ -9,7 +9,18 @@ namespace SixLabors.ImageSharp.Benchmarks.General
using BenchmarkDotNet.Attributes;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.Primitives;
/**
* Method | Count | Mean | Error | StdDev | Scaled | ScaledSD |
-------------------------------------------- |------ |---------:|---------:|---------:|-------:|---------:|
'Emulated 2D array access using flat array' | 32 | 224.2 ns | 4.739 ns | 13.75 ns | 0.65 | 0.07 |
'Array access using 2D array' | 32 | 346.6 ns | 9.225 ns | 26.91 ns | 1.00 | 0.00 |
'Array access using a jagged array' | 32 | 229.3 ns | 6.028 ns | 17.58 ns | 0.67 | 0.07 |
'Array access using DenseMatrix' | 32 | 223.2 ns | 5.248 ns | 15.22 ns | 0.65 | 0.07 |
*
*/
public class Array2D
{
@ -19,9 +30,9 @@ namespace SixLabors.ImageSharp.Benchmarks.General
private float[][] jaggedData;
private Fast2DArray<float> fastData;
[Params(4, 16, 128)]
private DenseMatrix<float> matrix;
[Params(4, 16, 32)]
public int Count { get; set; }
public int Min { get; private set; }
@ -39,9 +50,9 @@ namespace SixLabors.ImageSharp.Benchmarks.General
this.jaggedData[i] = new float[this.Count];
}
this.fastData = new Fast2DArray<float>(this.array2D);
this.matrix = new DenseMatrix<float>(this.array2D);
this.Min = this.Count / 2 - 10;
this.Min = (this.Count / 2) - 10;
this.Min = Math.Max(0, this.Min);
this.Max = this.Min + Math.Min(10, this.Count);
}
@ -56,7 +67,9 @@ namespace SixLabors.ImageSharp.Benchmarks.General
{
for (int j = this.Min; j < this.Max; j++)
{
s += a[count * i + j];
ref float v = ref a[count * i + j];
v = i * j;
s += v;
}
}
return s;
@ -71,7 +84,9 @@ namespace SixLabors.ImageSharp.Benchmarks.General
{
for (int j = this.Min; j < this.Max; j++)
{
s += a[i, j];
ref float v = ref a[i, j];
v = i * j;
s += v;
}
}
return s;
@ -86,25 +101,29 @@ namespace SixLabors.ImageSharp.Benchmarks.General
{
for (int j = this.Min; j < this.Max; j++)
{
s += a[i][j];
ref float v = ref a[i][j];
v = i * j;
s += v;
}
}
return s;
}
[Benchmark(Description = "Array access using Fast2DArray")]
public float ArrayFastIndex()
[Benchmark(Description = "Array access using DenseMatrix")]
public float ArrayMatrixIndex()
{
float s = 0;
Fast2DArray<float> a = this.fastData;
DenseMatrix<float> a = this.matrix;
for (int i = this.Min; i < this.Max; i++)
{
for (int j = this.Min; j < this.Max; j++)
{
s += a[i, j];
ref float v = ref a[i, j];
v = i * j;
s += v;
}
}
return s;
}
}
}
}

4
tests/ImageSharp.Tests/Drawing/SolidBezierTests.cs

@ -17,7 +17,7 @@ namespace SixLabors.ImageSharp.Tests.Drawing
public void FilledBezier<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : struct, IPixel<TPixel>
{
Primitives.PointF[] simplePath = {
SixLabors.Primitives.PointF[] simplePath = {
new Vector2(10, 400),
new Vector2(30, 10),
new Vector2(240, 30),
@ -43,7 +43,7 @@ namespace SixLabors.ImageSharp.Tests.Drawing
public void OverlayByFilledPolygonOpacity<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : struct, IPixel<TPixel>
{
Primitives.PointF[] simplePath = {
SixLabors.Primitives.PointF[] simplePath = {
new Vector2(10, 400),
new Vector2(30, 10),
new Vector2(240, 30),

108
tests/ImageSharp.Tests/Primitives/DenseMatrixTests.cs

@ -0,0 +1,108 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
using SixLabors.ImageSharp.Primitives;
using Xunit;
namespace SixLabors.ImageSharp.Tests.Primitives
{
public class DenseMatrixTests
{
private static readonly float[,] FloydSteinbergMatrix =
{
{ 0, 0, 7 },
{ 3, 5, 1 }
};
[Fact]
public void DenseMatrixThrowsOnNullInitializer()
{
Assert.Throws<ArgumentNullException>(() =>
{
var dense = new DenseMatrix<float>(null);
});
}
[Fact]
public void DenseMatrixThrowsOnEmptyZeroWidth()
{
Assert.Throws<ArgumentOutOfRangeException>(() =>
{
var dense = new DenseMatrix<float>(0, 10);
});
}
[Fact]
public void DenseMatrixThrowsOnEmptyZeroHeight()
{
Assert.Throws<ArgumentOutOfRangeException>(() =>
{
var dense = new DenseMatrix<float>(10, 0);
});
}
[Fact]
public void DenseMatrixThrowsOnEmptyInitializer()
{
Assert.Throws<ArgumentOutOfRangeException>(() =>
{
var dense = new DenseMatrix<float>(new float[0, 0]);
});
}
[Fact]
public void DenseMatrixReturnsCorrectDimensions()
{
var dense = new DenseMatrix<float>(FloydSteinbergMatrix);
Assert.True(dense.Columns == FloydSteinbergMatrix.GetLength(1));
Assert.True(dense.Rows == FloydSteinbergMatrix.GetLength(0));
Assert.Equal(3, dense.Columns);
Assert.Equal(2, dense.Rows);
}
[Fact]
public void DenseMatrixGetReturnsCorrectResults()
{
DenseMatrix<float> dense = FloydSteinbergMatrix;
for (int row = 0; row < dense.Rows; row++)
{
for (int column = 0; column < dense.Columns; column++)
{
Assert.True(Math.Abs(dense[row, column] - FloydSteinbergMatrix[row, column]) < Constants.Epsilon);
}
}
}
[Fact]
public void DenseMatrixGetSetReturnsCorrectResults()
{
var dense = new DenseMatrix<int>(4, 4);
const int Val = 5;
dense[3, 3] = Val;
Assert.Equal(Val, dense[3, 3]);
}
[Fact]
public void DenseMatrixCanFillAndClear()
{
var dense = new DenseMatrix<int>(9);
dense.Fill(4);
for (int i = 0; i < dense.Data.Length; i++)
{
Assert.Equal(4, dense.Data[i]);
}
dense.Clear();
for (int i = 0; i < dense.Data.Length; i++)
{
Assert.Equal(0, dense.Data[i]);
}
}
}
}

1
tests/ImageSharp.Tests/Processing/Overlays/GlowTest.cs

@ -9,6 +9,7 @@ using Xunit;
namespace SixLabors.ImageSharp.Tests.Processing.Overlays
{
using SixLabors.ImageSharp.Primitives;
using SixLabors.ImageSharp.Processing.Processors.Overlays;
public class GlowTest : BaseImageOperationsExtensionTest

1
tests/ImageSharp.Tests/Processing/Overlays/VignetteTest.cs

@ -10,6 +10,7 @@ using Xunit;
namespace SixLabors.ImageSharp.Tests.Processing.Overlays
{
using SixLabors.ImageSharp.Primitives;
using SixLabors.ImageSharp.Processing.Processors.Overlays;
public class VignetteTest : BaseImageOperationsExtensionTest

Loading…
Cancel
Save