Browse Source

pass configuation into processors

pull/326/head
Scott Williams 9 years ago
parent
commit
09a667d3a5
  1. 4
      src/ImageSharp.Drawing/Processors/DrawImageProcessor.cs
  2. 4
      src/ImageSharp.Drawing/Processors/FillProcessor.cs
  3. 2
      src/ImageSharp.Drawing/Processors/FillRegionProcessor.cs
  4. 22
      src/ImageSharp/Advanced/IConfigurable.cs
  5. 10
      src/ImageSharp/Advanced/ImageExtensions.cs
  6. 7
      src/ImageSharp/Image/ImageFrame{TPixel}.cs
  7. 17
      src/ImageSharp/Image/Image{TPixel}.cs
  8. 8
      src/ImageSharp/Processing/Processors/Binarization/BinaryThresholdProcessor.cs
  9. 6
      src/ImageSharp/Processing/Processors/Binarization/ErrorDiffusionDitherProcessor.cs
  10. 6
      src/ImageSharp/Processing/Processors/Binarization/OrderedDitherProcessor.cs
  11. 33
      src/ImageSharp/Processing/Processors/CloningImageProcessor.cs
  12. 4
      src/ImageSharp/Processing/Processors/ColorMatrix/ColorMatrixProcessor.cs
  13. 4
      src/ImageSharp/Processing/Processors/ColorMatrix/LomographProcessor.cs
  14. 6
      src/ImageSharp/Processing/Processors/ColorMatrix/PolaroidProcessor.cs
  15. 4
      src/ImageSharp/Processing/Processors/Convolution/BoxBlurProcessor.cs
  16. 4
      src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor.cs
  17. 4
      src/ImageSharp/Processing/Processors/Convolution/Convolution2PassProcessor.cs
  18. 4
      src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessor.cs
  19. 8
      src/ImageSharp/Processing/Processors/Convolution/EdgeDetection/EdgeDetector2DProcessor.cs
  20. 12
      src/ImageSharp/Processing/Processors/Convolution/EdgeDetection/EdgeDetectorCompassProcessor.cs
  21. 8
      src/ImageSharp/Processing/Processors/Convolution/EdgeDetection/EdgeDetectorProcessor.cs
  22. 4
      src/ImageSharp/Processing/Processors/Convolution/GaussianBlurProcessor.cs
  23. 4
      src/ImageSharp/Processing/Processors/Convolution/GaussianSharpenProcessor.cs
  24. 2
      src/ImageSharp/Processing/Processors/DelegateProcessor.cs
  25. 4
      src/ImageSharp/Processing/Processors/Effects/AlphaProcessor.cs
  26. 4
      src/ImageSharp/Processing/Processors/Effects/BackgroundColorProcessor.cs
  27. 4
      src/ImageSharp/Processing/Processors/Effects/BrightnessProcessor.cs
  28. 4
      src/ImageSharp/Processing/Processors/Effects/ContrastProcessor.cs
  29. 4
      src/ImageSharp/Processing/Processors/Effects/InvertProcessor.cs
  30. 4
      src/ImageSharp/Processing/Processors/Effects/OilPaintingProcessor.cs
  31. 4
      src/ImageSharp/Processing/Processors/Effects/PixelateProcessor.cs
  32. 47
      src/ImageSharp/Processing/Processors/ImageProcessor.cs
  33. 4
      src/ImageSharp/Processing/Processors/Overlays/GlowProcessor.cs
  34. 4
      src/ImageSharp/Processing/Processors/Overlays/VignetteProcessor.cs
  35. 2
      src/ImageSharp/Processing/Processors/Transforms/AutoOrientProcessor.cs
  36. 4
      src/ImageSharp/Processing/Processors/Transforms/CropProcessor.cs
  37. 8
      src/ImageSharp/Processing/Processors/Transforms/EntropyCropProcessor.cs
  38. 16
      src/ImageSharp/Processing/Processors/Transforms/FlipProcessor.cs
  39. 6
      src/ImageSharp/Processing/Processors/Transforms/ResamplingWeightedProcessor.cs
  40. 8
      src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs
  41. 36
      src/ImageSharp/Processing/Processors/Transforms/RotateProcessor.cs
  42. 6
      src/ImageSharp/Processing/Processors/Transforms/SkewProcessor.cs
  43. 4
      tests/ImageSharp.Benchmarks/Samplers/Glow.cs
  44. 4
      tests/ImageSharp.Tests/TestUtilities/ImageComparison/ExactImageComparer.cs
  45. 16
      tests/ImageSharp.Tests/TestUtilities/ImageComparison/ImageComparer.cs
  46. 38
      tests/ImageSharp.Tests/TestUtilities/ImageComparison/ImageSimilarityReport.cs
  47. 6
      tests/ImageSharp.Tests/TestUtilities/ImageComparison/TolerantImageComparer.cs

4
src/ImageSharp.Drawing/Processors/DrawImageProcessor.cs

@ -60,7 +60,7 @@ namespace SixLabors.ImageSharp.Drawing.Processors
public Point Location { get; } public Point Location { get; }
/// <inheritdoc/> /// <inheritdoc/>
protected override void OnApply(ImageFrame<TPixel> source, Rectangle sourceRectangle) protected override void OnApply(ImageFrame<TPixel> source, Rectangle sourceRectangle, Configuration configuration)
{ {
Image<TPixel> disposableImage = null; Image<TPixel> disposableImage = null;
Image<TPixel> targetImage = this.Image; Image<TPixel> targetImage = this.Image;
@ -96,7 +96,7 @@ namespace SixLabors.ImageSharp.Drawing.Processors
Parallel.For( Parallel.For(
minY, minY,
maxY, maxY,
source.Configuration().ParallelOptions, configuration.ParallelOptions,
y => y =>
{ {
Span<TPixel> background = sourcePixels.GetRowSpan(y).Slice(minX, width); Span<TPixel> background = sourcePixels.GetRowSpan(y).Slice(minX, width);

4
src/ImageSharp.Drawing/Processors/FillProcessor.cs

@ -40,7 +40,7 @@ namespace SixLabors.ImageSharp.Drawing.Processors
} }
/// <inheritdoc/> /// <inheritdoc/>
protected override void OnApply(ImageFrame<TPixel> source, Rectangle sourceRectangle) protected override void OnApply(ImageFrame<TPixel> source, Rectangle sourceRectangle, Configuration configuration)
{ {
int startX = sourceRectangle.X; int startX = sourceRectangle.X;
int endX = sourceRectangle.Right; int endX = sourceRectangle.Right;
@ -77,7 +77,7 @@ namespace SixLabors.ImageSharp.Drawing.Processors
Parallel.For( Parallel.For(
minY, minY,
maxY, maxY,
source.Configuration().ParallelOptions, configuration.ParallelOptions,
y => y =>
{ {
int offsetY = y - startY; int offsetY = y - startY;

2
src/ImageSharp.Drawing/Processors/FillRegionProcessor.cs

@ -57,7 +57,7 @@ namespace SixLabors.ImageSharp.Drawing.Processors
public GraphicsOptions Options { get; } public GraphicsOptions Options { get; }
/// <inheritdoc/> /// <inheritdoc/>
protected override void OnApply(ImageFrame<TPixel> source, Rectangle sourceRectangle) protected override void OnApply(ImageFrame<TPixel> source, Rectangle sourceRectangle, Configuration configuration)
{ {
Region region = this.Region; Region region = this.Region;
Rectangle rect = region.Bounds; Rectangle rect = region.Bounds;

22
src/ImageSharp/Advanced/IConfigurable.cs

@ -0,0 +1,22 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.MetaData;
using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Advanced
{
/// <summary>
/// Encapsulates the properties for configuration
/// </summary>
internal interface IConfigurable
{
/// <summary>
/// Gets the pixel buffer.
/// </summary>
Configuration Configuration { get; }
}
}

10
src/ImageSharp/Advanced/ImageExtensions.cs

@ -80,18 +80,16 @@ namespace SixLabors.ImageSharp.Advanced
/// <typeparam name="TPixel">The Pixel format.</typeparam> /// <typeparam name="TPixel">The Pixel format.</typeparam>
/// <param name="source">The source image</param> /// <param name="source">The source image</param>
/// <returns>Returns the bounds of the image</returns> /// <returns>Returns the bounds of the image</returns>
public static Configuration Configuration<TPixel>(this ImageFrame<TPixel> source) public static Configuration Configuration<TPixel>(this Image<TPixel> source)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
=> source?.Parent?.ImageConfiguration ?? SixLabors.ImageSharp.Configuration.Default; => GetConfiguration(source);
/// <summary> /// <summary>
/// Gets the bounds of the image. /// Gets the bounds of the image.
/// </summary> /// </summary>
/// <typeparam name="TPixel">The Pixel format.</typeparam>
/// <param name="source">The source image</param> /// <param name="source">The source image</param>
/// <returns>Returns the bounds of the image</returns> /// <returns>Returns the bounds of the image</returns>
public static Configuration Configuration<TPixel>(this Image<TPixel> source) private static Configuration GetConfiguration(IConfigurable source)
where TPixel : struct, IPixel<TPixel> => source?.Configuration ?? SixLabors.ImageSharp.Configuration.Default;
=> source?.ImageConfiguration ?? SixLabors.ImageSharp.Configuration.Default;
} }
} }

7
src/ImageSharp/Image/ImageFrame{TPixel}.cs

@ -73,11 +73,6 @@ namespace SixLabors.ImageSharp
/// <inheritdoc/> /// <inheritdoc/>
public int Height => this.pixelBuffer.Height; public int Height => this.pixelBuffer.Height;
/// <summary>
/// Gets the configuration providing initialization code which allows extending the library.
/// </summary>
public Image<TPixel> Parent { get; private set; }
/// <summary> /// <summary>
/// Gets the meta data of the frame. /// Gets the meta data of the frame.
/// </summary> /// </summary>
@ -222,7 +217,7 @@ namespace SixLabors.ImageSharp
Parallel.For( Parallel.For(
0, 0,
target.Height, target.Height,
this.Configuration().ParallelOptions, Configuration.Default.ParallelOptions,
y => y =>
{ {
for (int x = 0; x < target.Width; x++) for (int x = 0; x < target.Width; x++)

17
src/ImageSharp/Image/Image{TPixel}.cs

@ -17,9 +17,11 @@ namespace SixLabors.ImageSharp
/// Encapsulates an image, which consists of the pixel data for a graphics image and its attributes. /// Encapsulates an image, which consists of the pixel data for a graphics image and its attributes.
/// </summary> /// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam> /// <typeparam name="TPixel">The pixel format.</typeparam>
public sealed partial class Image<TPixel> : IDisposable public sealed partial class Image<TPixel> : IDisposable, IConfigurable
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
private Configuration configuration;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="Image{TPixel}"/> class /// Initializes a new instance of the <see cref="Image{TPixel}"/> class
/// with the height and the width of the image. /// with the height and the width of the image.
@ -71,7 +73,7 @@ namespace SixLabors.ImageSharp
/// <param name="frames">The frames that will be owned by this image instance.</param> /// <param name="frames">The frames that will be owned by this image instance.</param>
internal Image(Configuration configuration, int width, int height, ImageMetaData metadata, IEnumerable<ImageFrame<TPixel>> frames) internal Image(Configuration configuration, int width, int height, ImageMetaData metadata, IEnumerable<ImageFrame<TPixel>> frames)
{ {
this.ImageConfiguration = configuration ?? Configuration.Default; this.configuration = configuration ?? Configuration.Default;
this.MetaData = metadata ?? new ImageMetaData(); this.MetaData = metadata ?? new ImageMetaData();
this.Frames = new ImageFrameCollection<TPixel>(); this.Frames = new ImageFrameCollection<TPixel>();
@ -91,12 +93,9 @@ namespace SixLabors.ImageSharp
} }
/// <summary> /// <summary>
/// Gets the configuration. /// Gets the pixel buffer.
/// </summary> /// </summary>
/// <value> Configuration IConfigurable.Configuration => this.configuration;
/// The configuration.
/// </value>
internal Configuration ImageConfiguration { get; }
/// <summary> /// <summary>
/// Gets the width. /// Gets the width.
@ -158,7 +157,7 @@ namespace SixLabors.ImageSharp
{ {
IEnumerable<ImageFrame<TPixel>> frames = this.Frames.Select(x => x.Clone()).ToArray(); IEnumerable<ImageFrame<TPixel>> frames = this.Frames.Select(x => x.Clone()).ToArray();
return new Image<TPixel>(this.ImageConfiguration, this.Width, this.Height, this.MetaData.Clone(), frames); return new Image<TPixel>(this.configuration, this.Width, this.Height, this.MetaData.Clone(), frames);
} }
/// <inheritdoc/> /// <inheritdoc/>
@ -176,7 +175,7 @@ namespace SixLabors.ImageSharp
where TPixel2 : struct, IPixel<TPixel2> where TPixel2 : struct, IPixel<TPixel2>
{ {
IEnumerable<ImageFrame<TPixel2>> frames = this.Frames.Select(x => x.CloneAs<TPixel2>()).ToArray(); IEnumerable<ImageFrame<TPixel2>> frames = this.Frames.Select(x => x.CloneAs<TPixel2>()).ToArray();
var target = new Image<TPixel2>(this.ImageConfiguration, this.Width, this.Height, this.MetaData, frames); var target = new Image<TPixel2>(this.configuration, this.Width, this.Height, this.MetaData, frames);
return target; return target;
} }

8
src/ImageSharp/Processing/Processors/Binarization/BinaryThresholdProcessor.cs

@ -48,13 +48,13 @@ namespace SixLabors.ImageSharp.Processing.Processors
public TPixel LowerColor { get; set; } public TPixel LowerColor { get; set; }
/// <inheritdoc/> /// <inheritdoc/>
protected override void BeforeApply(ImageFrame<TPixel> source, Rectangle sourceRectangle) protected override void BeforeApply(ImageFrame<TPixel> source, Rectangle sourceRectangle, Configuration configuration)
{ {
new GrayscaleBt709Processor<TPixel>().Apply(source, sourceRectangle); new GrayscaleBt709Processor<TPixel>().Apply(source, sourceRectangle, configuration);
} }
/// <inheritdoc/> /// <inheritdoc/>
protected override void OnApply(ImageFrame<TPixel> source, Rectangle sourceRectangle) protected override void OnApply(ImageFrame<TPixel> source, Rectangle sourceRectangle, Configuration configuration)
{ {
float threshold = this.Threshold; float threshold = this.Threshold;
TPixel upper = this.UpperColor; TPixel upper = this.UpperColor;
@ -85,7 +85,7 @@ namespace SixLabors.ImageSharp.Processing.Processors
Parallel.For( Parallel.For(
minY, minY,
maxY, maxY,
source.Configuration().ParallelOptions, configuration.ParallelOptions,
y => y =>
{ {
Span<TPixel> row = source.GetPixelRowSpan(y - startY); Span<TPixel> row = source.GetPixelRowSpan(y - startY);

6
src/ImageSharp/Processing/Processors/Binarization/ErrorDiffusionDitherProcessor.cs

@ -55,13 +55,13 @@ namespace SixLabors.ImageSharp.Processing.Processors
public TPixel LowerColor { get; set; } public TPixel LowerColor { get; set; }
/// <inheritdoc/> /// <inheritdoc/>
protected override void BeforeApply(ImageFrame<TPixel> source, Rectangle sourceRectangle) protected override void BeforeApply(ImageFrame<TPixel> source, Rectangle sourceRectangle, Configuration configuration)
{ {
new GrayscaleBt709Processor<TPixel>().Apply(source, sourceRectangle); new GrayscaleBt709Processor<TPixel>().Apply(source, sourceRectangle, configuration);
} }
/// <inheritdoc/> /// <inheritdoc/>
protected override void OnApply(ImageFrame<TPixel> source, Rectangle sourceRectangle) protected override void OnApply(ImageFrame<TPixel> source, Rectangle sourceRectangle, Configuration configuration)
{ {
var interest = Rectangle.Intersect(sourceRectangle, source.Bounds()); var interest = Rectangle.Intersect(sourceRectangle, source.Bounds());
int startY = interest.Y; int startY = interest.Y;

6
src/ImageSharp/Processing/Processors/Binarization/OrderedDitherProcessor.cs

@ -63,13 +63,13 @@ namespace SixLabors.ImageSharp.Processing.Processors
public TPixel LowerColor { get; set; } public TPixel LowerColor { get; set; }
/// <inheritdoc/> /// <inheritdoc/>
protected override void BeforeApply(ImageFrame<TPixel> source, Rectangle sourceRectangle) protected override void BeforeApply(ImageFrame<TPixel> source, Rectangle sourceRectangle, Configuration configuration)
{ {
new GrayscaleBt709Processor<TPixel>().Apply(source, sourceRectangle); new GrayscaleBt709Processor<TPixel>().Apply(source, sourceRectangle, configuration);
} }
/// <inheritdoc/> /// <inheritdoc/>
protected override void OnApply(ImageFrame<TPixel> source, Rectangle sourceRectangle) protected override void OnApply(ImageFrame<TPixel> source, Rectangle sourceRectangle, Configuration configuration)
{ {
var interest = Rectangle.Intersect(sourceRectangle, source.Bounds()); var interest = Rectangle.Intersect(sourceRectangle, source.Bounds());
int startY = interest.Y; int startY = interest.Y;

33
src/ImageSharp/Processing/Processors/CloningImageProcessor.cs

@ -2,7 +2,7 @@
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using System; using System;
using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
using SixLabors.Primitives; using SixLabors.Primitives;
@ -27,6 +27,7 @@ namespace SixLabors.ImageSharp.Processing
throw new ImageProcessingException($"An error occured when processing the image using {this.GetType().Name}. The processor changed the number of frames."); throw new ImageProcessingException($"An error occured when processing the image using {this.GetType().Name}. The processor changed the number of frames.");
} }
var configuration = source.Configuration();
this.BeforeImageApply(source, clone, sourceRectangle); this.BeforeImageApply(source, clone, sourceRectangle);
for (int i = 0; i < source.Frames.Count; i++) for (int i = 0; i < source.Frames.Count; i++)
@ -34,10 +35,9 @@ namespace SixLabors.ImageSharp.Processing
ImageFrame<TPixel> sourceFrame = source.Frames[i]; ImageFrame<TPixel> sourceFrame = source.Frames[i];
ImageFrame<TPixel> clonedFrame = clone.Frames[i]; ImageFrame<TPixel> clonedFrame = clone.Frames[i];
this.BeforeApply(sourceFrame, clonedFrame, sourceRectangle); this.BeforeApply(sourceFrame, clonedFrame, sourceRectangle, configuration);
this.OnApply(sourceFrame, clonedFrame, sourceRectangle, configuration);
this.OnApply(sourceFrame, clonedFrame, sourceRectangle); this.AfterApply(sourceFrame, clonedFrame, sourceRectangle, configuration);
this.AfterApply(sourceFrame, clonedFrame, sourceRectangle);
} }
this.AfterImageApply(source, clone, sourceRectangle); this.AfterImageApply(source, clone, sourceRectangle);
@ -99,33 +99,30 @@ namespace SixLabors.ImageSharp.Processing
/// </summary> /// </summary>
/// <param name="source">The source image. Cannot be null.</param> /// <param name="source">The source image. Cannot be null.</param>
/// <param name="destination">The cloned/destination image. Cannot be null.</param> /// <param name="destination">The cloned/destination image. Cannot be null.</param>
/// <param name="sourceRectangle"> /// <param name="sourceRectangle">The <see cref="Rectangle" /> structure that specifies the portion of the image object to draw.</param>
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to draw. /// <param name="configuration">The configuration.</param>
/// </param> protected virtual void BeforeApply(ImageFrame<TPixel> source, ImageFrame<TPixel> destination, Rectangle sourceRectangle, Configuration configuration)
protected virtual void BeforeApply(ImageFrame<TPixel> source, ImageFrame<TPixel> destination, Rectangle sourceRectangle)
{ {
} }
/// <summary> /// <summary>
/// Applies the process to the specified portion of the specified <see cref="ImageFrame{TPixel}"/> at the specified location /// Applies the process to the specified portion of the specified <see cref="ImageFrame{TPixel}" /> at the specified location
/// and with the specified size. /// and with the specified size.
/// </summary> /// </summary>
/// <param name="source">The source image. Cannot be null.</param> /// <param name="source">The source image. Cannot be null.</param>
/// <param name="destination">The cloned/destination image. Cannot be null.</param> /// <param name="destination">The cloned/destination image. Cannot be null.</param>
/// <param name="sourceRectangle"> /// <param name="sourceRectangle">The <see cref="Rectangle" /> structure that specifies the portion of the image object to draw.</param>
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to draw. /// <param name="configuration">The configuration.</param>
/// </param> protected abstract void OnApply(ImageFrame<TPixel> source, ImageFrame<TPixel> destination, Rectangle sourceRectangle, Configuration configuration);
protected abstract void OnApply(ImageFrame<TPixel> source, ImageFrame<TPixel> destination, Rectangle sourceRectangle);
/// <summary> /// <summary>
/// This method is called after the process is applied to prepare the processor. /// This method is called after the process is applied to prepare the processor.
/// </summary> /// </summary>
/// <param name="source">The source image. Cannot be null.</param> /// <param name="source">The source image. Cannot be null.</param>
/// <param name="destination">The cloned/destination image. Cannot be null.</param> /// <param name="destination">The cloned/destination image. Cannot be null.</param>
/// <param name="sourceRectangle"> /// <param name="sourceRectangle">The <see cref="Rectangle" /> structure that specifies the portion of the image object to draw.</param>
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to draw. /// <param name="configuration">The configuration.</param>
/// </param> protected virtual void AfterApply(ImageFrame<TPixel> source, ImageFrame<TPixel> destination, Rectangle sourceRectangle, Configuration configuration)
protected virtual void AfterApply(ImageFrame<TPixel> source, ImageFrame<TPixel> destination, Rectangle sourceRectangle)
{ {
} }

4
src/ImageSharp/Processing/Processors/ColorMatrix/ColorMatrixProcessor.cs

@ -24,7 +24,7 @@ namespace SixLabors.ImageSharp.Processing.Processors
public virtual bool Compand { get; set; } = true; public virtual bool Compand { get; set; } = true;
/// <inheritdoc/> /// <inheritdoc/>
protected override void OnApply(ImageFrame<TPixel> source, Rectangle sourceRectangle) protected override void OnApply(ImageFrame<TPixel> source, Rectangle sourceRectangle, Configuration configuration)
{ {
int startY = sourceRectangle.Y; int startY = sourceRectangle.Y;
int endY = sourceRectangle.Bottom; int endY = sourceRectangle.Bottom;
@ -54,7 +54,7 @@ namespace SixLabors.ImageSharp.Processing.Processors
Parallel.For( Parallel.For(
minY, minY,
maxY, maxY,
source.Configuration().ParallelOptions, configuration.ParallelOptions,
y => y =>
{ {
Span<TPixel> row = source.GetPixelRowSpan(y - startY); Span<TPixel> row = source.GetPixelRowSpan(y - startY);

4
src/ImageSharp/Processing/Processors/ColorMatrix/LomographProcessor.cs

@ -39,9 +39,9 @@ namespace SixLabors.ImageSharp.Processing.Processors
}; };
/// <inheritdoc/> /// <inheritdoc/>
protected override void AfterApply(ImageFrame<TPixel> source, Rectangle sourceRectangle) protected override void AfterApply(ImageFrame<TPixel> source, Rectangle sourceRectangle, Configuration configuration)
{ {
new VignetteProcessor<TPixel>(VeryDarkGreen, this.options).Apply(source, sourceRectangle); new VignetteProcessor<TPixel>(VeryDarkGreen, this.options).Apply(source, sourceRectangle, configuration);
} }
} }
} }

6
src/ImageSharp/Processing/Processors/ColorMatrix/PolaroidProcessor.cs

@ -46,10 +46,10 @@ namespace SixLabors.ImageSharp.Processing.Processors
}; };
/// <inheritdoc/> /// <inheritdoc/>
protected override void AfterApply(ImageFrame<TPixel> source, Rectangle sourceRectangle) protected override void AfterApply(ImageFrame<TPixel> source, Rectangle sourceRectangle, Configuration configuration)
{ {
new VignetteProcessor<TPixel>(VeryDarkOrange, this.options).Apply(source, sourceRectangle); new VignetteProcessor<TPixel>(VeryDarkOrange, this.options).Apply(source, sourceRectangle, configuration);
new GlowProcessor<TPixel>(LightOrange, source.Width / 4F, this.options).Apply(source, sourceRectangle); new GlowProcessor<TPixel>(LightOrange, source.Width / 4F, this.options).Apply(source, sourceRectangle, configuration);
} }
} }
} }

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

@ -50,9 +50,9 @@ namespace SixLabors.ImageSharp.Processing.Processors
public Fast2DArray<float> KernelY { get; } public Fast2DArray<float> KernelY { get; }
/// <inheritdoc/> /// <inheritdoc/>
protected override void OnApply(ImageFrame<TPixel> source, Rectangle sourceRectangle) protected override void OnApply(ImageFrame<TPixel> source, Rectangle sourceRectangle, Configuration configuration)
{ {
new Convolution2PassProcessor<TPixel>(this.KernelX, this.KernelY).Apply(source, sourceRectangle); new Convolution2PassProcessor<TPixel>(this.KernelX, this.KernelY).Apply(source, sourceRectangle, configuration);
} }
/// <summary> /// <summary>

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

@ -40,7 +40,7 @@ namespace SixLabors.ImageSharp.Processing.Processors
public Fast2DArray<float> KernelY { get; } public Fast2DArray<float> KernelY { get; }
/// <inheritdoc/> /// <inheritdoc/>
protected override void OnApply(ImageFrame<TPixel> source, Rectangle sourceRectangle) protected override void OnApply(ImageFrame<TPixel> source, Rectangle sourceRectangle, Configuration configuration)
{ {
int kernelYHeight = this.KernelY.Height; int kernelYHeight = this.KernelY.Height;
int kernelYWidth = this.KernelY.Width; int kernelYWidth = this.KernelY.Width;
@ -63,7 +63,7 @@ namespace SixLabors.ImageSharp.Processing.Processors
Parallel.For( Parallel.For(
startY, startY,
endY, endY,
source.Configuration().ParallelOptions, configuration.ParallelOptions,
y => y =>
{ {
Span<TPixel> sourceRow = source.GetPixelRowSpan(y); Span<TPixel> sourceRow = source.GetPixelRowSpan(y);

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

@ -41,11 +41,11 @@ namespace SixLabors.ImageSharp.Processing.Processors
public Fast2DArray<float> KernelY { get; } public Fast2DArray<float> KernelY { get; }
/// <inheritdoc/> /// <inheritdoc/>
protected override void OnApply(ImageFrame<TPixel> source, Rectangle sourceRectangle) protected override void OnApply(ImageFrame<TPixel> source, Rectangle sourceRectangle, Configuration configuration)
{ {
int width = source.Width; int width = source.Width;
int height = source.Height; int height = source.Height;
ParallelOptions parallelOptions = source.Configuration().ParallelOptions; ParallelOptions parallelOptions = configuration.ParallelOptions;
using (var firstPassPixels = new PixelAccessor<TPixel>(width, height)) using (var firstPassPixels = new PixelAccessor<TPixel>(width, height))
using (PixelAccessor<TPixel> sourcePixels = source.Lock()) using (PixelAccessor<TPixel> sourcePixels = source.Lock())

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

@ -33,7 +33,7 @@ namespace SixLabors.ImageSharp.Processing.Processors
public Fast2DArray<float> KernelXY { get; } public Fast2DArray<float> KernelXY { get; }
/// <inheritdoc/> /// <inheritdoc/>
protected override void OnApply(ImageFrame<TPixel> source, Rectangle sourceRectangle) protected override void OnApply(ImageFrame<TPixel> source, Rectangle sourceRectangle, Configuration configuration)
{ {
int kernelLength = this.KernelXY.Height; int kernelLength = this.KernelXY.Height;
int radius = kernelLength >> 1; int radius = kernelLength >> 1;
@ -52,7 +52,7 @@ namespace SixLabors.ImageSharp.Processing.Processors
Parallel.For( Parallel.For(
startY, startY,
endY, endY,
source.Configuration().ParallelOptions, configuration.ParallelOptions,
y => y =>
{ {
Span<TPixel> sourceRow = source.GetPixelRowSpan(y); Span<TPixel> sourceRow = source.GetPixelRowSpan(y);

8
src/ImageSharp/Processing/Processors/Convolution/EdgeDetection/EdgeDetector2DProcessor.cs

@ -40,17 +40,17 @@ namespace SixLabors.ImageSharp.Processing.Processors
public bool Grayscale { get; set; } public bool Grayscale { get; set; }
/// <inheritdoc /> /// <inheritdoc />
protected override void OnApply(ImageFrame<TPixel> source, Rectangle sourceRectangle) protected override void OnApply(ImageFrame<TPixel> source, Rectangle sourceRectangle, Configuration configuration)
{ {
new Convolution2DProcessor<TPixel>(this.KernelX, this.KernelY).Apply(source, sourceRectangle); new Convolution2DProcessor<TPixel>(this.KernelX, this.KernelY).Apply(source, sourceRectangle, configuration);
} }
/// <inheritdoc/> /// <inheritdoc/>
protected override void BeforeApply(ImageFrame<TPixel> source, Rectangle sourceRectangle) protected override void BeforeApply(ImageFrame<TPixel> source, Rectangle sourceRectangle, Configuration configuration)
{ {
if (this.Grayscale) if (this.Grayscale)
{ {
new GrayscaleBt709Processor<TPixel>().Apply(source, sourceRectangle); new GrayscaleBt709Processor<TPixel>().Apply(source, sourceRectangle, configuration);
} }
} }
} }

12
src/ImageSharp/Processing/Processors/Convolution/EdgeDetection/EdgeDetectorCompassProcessor.cs

@ -62,16 +62,16 @@ namespace SixLabors.ImageSharp.Processing.Processors
public bool Grayscale { get; set; } public bool Grayscale { get; set; }
/// <inheritdoc/> /// <inheritdoc/>
protected override void BeforeApply(ImageFrame<TPixel> source, Rectangle sourceRectangle) protected override void BeforeApply(ImageFrame<TPixel> source, Rectangle sourceRectangle, Configuration configuration)
{ {
if (this.Grayscale) if (this.Grayscale)
{ {
new GrayscaleBt709Processor<TPixel>().Apply(source, sourceRectangle); new GrayscaleBt709Processor<TPixel>().Apply(source, sourceRectangle, configuration);
} }
} }
/// <inheritdoc /> /// <inheritdoc />
protected override void OnApply(ImageFrame<TPixel> source, Rectangle sourceRectangle) protected override void OnApply(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 }; Fast2DArray<float>[] kernels = { this.North, this.NorthWest, this.West, this.SouthWest, this.South, this.SouthEast, this.East, this.NorthEast };
@ -89,7 +89,7 @@ namespace SixLabors.ImageSharp.Processing.Processors
// we need a clean copy for each pass to start from // we need a clean copy for each pass to start from
using (ImageFrame<TPixel> cleanCopy = source.Clone()) using (ImageFrame<TPixel> cleanCopy = source.Clone())
{ {
new ConvolutionProcessor<TPixel>(kernels[0]).Apply(source, sourceRectangle); new ConvolutionProcessor<TPixel>(kernels[0]).Apply(source, sourceRectangle, configuration);
if (kernels.Length == 1) if (kernels.Length == 1)
{ {
@ -116,7 +116,7 @@ namespace SixLabors.ImageSharp.Processing.Processors
{ {
using (ImageFrame<TPixel> pass = cleanCopy.Clone()) using (ImageFrame<TPixel> pass = cleanCopy.Clone())
{ {
new ConvolutionProcessor<TPixel>(kernels[i]).Apply(pass, sourceRectangle); new ConvolutionProcessor<TPixel>(kernels[i]).Apply(pass, sourceRectangle, configuration);
using (PixelAccessor<TPixel> passPixels = pass.Lock()) using (PixelAccessor<TPixel> passPixels = pass.Lock())
using (PixelAccessor<TPixel> targetPixels = source.Lock()) using (PixelAccessor<TPixel> targetPixels = source.Lock())
@ -124,7 +124,7 @@ namespace SixLabors.ImageSharp.Processing.Processors
Parallel.For( Parallel.For(
minY, minY,
maxY, maxY,
source.Configuration().ParallelOptions, configuration.ParallelOptions,
y => y =>
{ {
int offsetY = y - shiftY; int offsetY = y - shiftY;

8
src/ImageSharp/Processing/Processors/Convolution/EdgeDetection/EdgeDetectorProcessor.cs

@ -33,18 +33,18 @@ namespace SixLabors.ImageSharp.Processing.Processors
public Fast2DArray<float> KernelXY { get; } public Fast2DArray<float> KernelXY { get; }
/// <inheritdoc/> /// <inheritdoc/>
protected override void BeforeApply(ImageFrame<TPixel> source, Rectangle sourceRectangle) protected override void BeforeApply(ImageFrame<TPixel> source, Rectangle sourceRectangle, Configuration configuration)
{ {
if (this.Grayscale) if (this.Grayscale)
{ {
new GrayscaleBt709Processor<TPixel>().Apply(source, sourceRectangle); new GrayscaleBt709Processor<TPixel>().Apply(source, sourceRectangle, configuration);
} }
} }
/// <inheritdoc/> /// <inheritdoc/>
protected override void OnApply(ImageFrame<TPixel> source, Rectangle sourceRectangle) protected override void OnApply(ImageFrame<TPixel> source, Rectangle sourceRectangle, Configuration configuration)
{ {
new ConvolutionProcessor<TPixel>(this.KernelXY).Apply(source, sourceRectangle); new ConvolutionProcessor<TPixel>(this.KernelXY).Apply(source, sourceRectangle, configuration);
} }
} }
} }

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

@ -85,9 +85,9 @@ namespace SixLabors.ImageSharp.Processing.Processors
public Fast2DArray<float> KernelY { get; } public Fast2DArray<float> KernelY { get; }
/// <inheritdoc/> /// <inheritdoc/>
protected override void OnApply(ImageFrame<TPixel> source, Rectangle sourceRectangle) protected override void OnApply(ImageFrame<TPixel> source, Rectangle sourceRectangle, Configuration configuration)
{ {
new Convolution2PassProcessor<TPixel>(this.KernelX, this.KernelY).Apply(source, sourceRectangle); new Convolution2PassProcessor<TPixel>(this.KernelX, this.KernelY).Apply(source, sourceRectangle, configuration);
} }
/// <summary> /// <summary>

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

@ -87,9 +87,9 @@ namespace SixLabors.ImageSharp.Processing.Processors
public Fast2DArray<float> KernelY { get; } public Fast2DArray<float> KernelY { get; }
/// <inheritdoc/> /// <inheritdoc/>
protected override void OnApply(ImageFrame<TPixel> source, Rectangle sourceRectangle) protected override void OnApply(ImageFrame<TPixel> source, Rectangle sourceRectangle, Configuration configuration)
{ {
new Convolution2PassProcessor<TPixel>(this.KernelX, this.KernelY).Apply(source, sourceRectangle); new Convolution2PassProcessor<TPixel>(this.KernelX, this.KernelY).Apply(source, sourceRectangle, configuration);
} }
/// <summary> /// <summary>

2
src/ImageSharp/Processing/Processors/DelegateProcessor.cs

@ -37,7 +37,7 @@ namespace SixLabors.ImageSharp.Processing
} }
/// <inheritdoc/> /// <inheritdoc/>
protected override void OnApply(ImageFrame<TPixel> source, Rectangle sourceRectangle) protected override void OnApply(ImageFrame<TPixel> source, Rectangle sourceRectangle, Configuration configuration)
{ {
// NOP, we did all we wanted to do inside BeforeImageApply // NOP, we did all we wanted to do inside BeforeImageApply
} }

4
src/ImageSharp/Processing/Processors/Effects/AlphaProcessor.cs

@ -36,7 +36,7 @@ namespace SixLabors.ImageSharp.Processing.Processors
public float Value { get; } public float Value { get; }
/// <inheritdoc/> /// <inheritdoc/>
protected override void OnApply(ImageFrame<TPixel> source, Rectangle sourceRectangle) protected override void OnApply(ImageFrame<TPixel> source, Rectangle sourceRectangle, Configuration configuration)
{ {
int startY = sourceRectangle.Y; int startY = sourceRectangle.Y;
int endY = sourceRectangle.Bottom; int endY = sourceRectangle.Bottom;
@ -65,7 +65,7 @@ namespace SixLabors.ImageSharp.Processing.Processors
Parallel.For( Parallel.For(
minY, minY,
maxY, maxY,
source.Configuration().ParallelOptions, configuration.ParallelOptions,
y => y =>
{ {
Span<TPixel> row = source.GetPixelRowSpan(y - startY); Span<TPixel> row = source.GetPixelRowSpan(y - startY);

4
src/ImageSharp/Processing/Processors/Effects/BackgroundColorProcessor.cs

@ -41,7 +41,7 @@ namespace SixLabors.ImageSharp.Processing.Processors
public TPixel Value { get; } public TPixel Value { get; }
/// <inheritdoc/> /// <inheritdoc/>
protected override void OnApply(ImageFrame<TPixel> source, Rectangle sourceRectangle) protected override void OnApply(ImageFrame<TPixel> source, Rectangle sourceRectangle, Configuration configuration)
{ {
int startY = sourceRectangle.Y; int startY = sourceRectangle.Y;
int endY = sourceRectangle.Bottom; int endY = sourceRectangle.Bottom;
@ -80,7 +80,7 @@ namespace SixLabors.ImageSharp.Processing.Processors
Parallel.For( Parallel.For(
minY, minY,
maxY, maxY,
source.Configuration().ParallelOptions, configuration.ParallelOptions,
y => y =>
{ {
Span<TPixel> destination = source.GetPixelRowSpan(y - startY).Slice(minX - startX, width); Span<TPixel> destination = source.GetPixelRowSpan(y - startY).Slice(minX - startX, width);

4
src/ImageSharp/Processing/Processors/Effects/BrightnessProcessor.cs

@ -36,7 +36,7 @@ namespace SixLabors.ImageSharp.Processing.Processors
public int Value { get; } public int Value { get; }
/// <inheritdoc/> /// <inheritdoc/>
protected override void OnApply(ImageFrame<TPixel> source, Rectangle sourceRectangle) protected override void OnApply(ImageFrame<TPixel> source, Rectangle sourceRectangle, Configuration configuration)
{ {
float brightness = this.Value / 100F; float brightness = this.Value / 100F;
@ -65,7 +65,7 @@ namespace SixLabors.ImageSharp.Processing.Processors
Parallel.For( Parallel.For(
minY, minY,
maxY, maxY,
source.Configuration().ParallelOptions, configuration.ParallelOptions,
y => y =>
{ {
Span<TPixel> row = source.GetPixelRowSpan(y - startY); Span<TPixel> row = source.GetPixelRowSpan(y - startY);

4
src/ImageSharp/Processing/Processors/Effects/ContrastProcessor.cs

@ -36,7 +36,7 @@ namespace SixLabors.ImageSharp.Processing.Processors
public int Value { get; } public int Value { get; }
/// <inheritdoc/> /// <inheritdoc/>
protected override void OnApply(ImageFrame<TPixel> source, Rectangle sourceRectangle) protected override void OnApply(ImageFrame<TPixel> source, Rectangle sourceRectangle, Configuration configuration)
{ {
float contrast = (100F + this.Value) / 100F; float contrast = (100F + this.Value) / 100F;
@ -67,7 +67,7 @@ namespace SixLabors.ImageSharp.Processing.Processors
Parallel.For( Parallel.For(
minY, minY,
maxY, maxY,
source.Configuration().ParallelOptions, configuration.ParallelOptions,
y => y =>
{ {
Span<TPixel> row = source.GetPixelRowSpan(y - startY); Span<TPixel> row = source.GetPixelRowSpan(y - startY);

4
src/ImageSharp/Processing/Processors/Effects/InvertProcessor.cs

@ -18,7 +18,7 @@ namespace SixLabors.ImageSharp.Processing.Processors
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
/// <inheritdoc/> /// <inheritdoc/>
protected override void OnApply(ImageFrame<TPixel> source, Rectangle sourceRectangle) protected override void OnApply(ImageFrame<TPixel> source, Rectangle sourceRectangle, Configuration configuration)
{ {
int startY = sourceRectangle.Y; int startY = sourceRectangle.Y;
int endY = sourceRectangle.Bottom; int endY = sourceRectangle.Bottom;
@ -46,7 +46,7 @@ namespace SixLabors.ImageSharp.Processing.Processors
Parallel.For( Parallel.For(
minY, minY,
maxY, maxY,
source.Configuration().ParallelOptions, configuration.ParallelOptions,
y => y =>
{ {
Span<TPixel> row = source.GetPixelRowSpan(y - startY); Span<TPixel> row = source.GetPixelRowSpan(y - startY);

4
src/ImageSharp/Processing/Processors/Effects/OilPaintingProcessor.cs

@ -48,7 +48,7 @@ namespace SixLabors.ImageSharp.Processing.Processors
public int BrushSize { get; } public int BrushSize { get; }
/// <inheritdoc/> /// <inheritdoc/>
protected override void OnApply(ImageFrame<TPixel> source, Rectangle sourceRectangle) protected override void OnApply(ImageFrame<TPixel> source, Rectangle sourceRectangle, Configuration configuration)
{ {
if (this.BrushSize <= 0 || this.BrushSize > source.Height || this.BrushSize > source.Width) if (this.BrushSize <= 0 || this.BrushSize > source.Height || this.BrushSize > source.Width)
{ {
@ -72,7 +72,7 @@ namespace SixLabors.ImageSharp.Processing.Processors
Parallel.For( Parallel.For(
startY, startY,
maxY, maxY,
source.Configuration().ParallelOptions, configuration.ParallelOptions,
y => y =>
{ {
Span<TPixel> sourceRow = source.GetPixelRowSpan(y); Span<TPixel> sourceRow = source.GetPixelRowSpan(y);

4
src/ImageSharp/Processing/Processors/Effects/PixelateProcessor.cs

@ -37,7 +37,7 @@ namespace SixLabors.ImageSharp.Processing.Processors
public int Size { get; } public int Size { get; }
/// <inheritdoc/> /// <inheritdoc/>
protected override void OnApply(ImageFrame<TPixel> source, Rectangle sourceRectangle) protected override void OnApply(ImageFrame<TPixel> source, Rectangle sourceRectangle, Configuration configuration)
{ {
if (this.Size <= 0 || this.Size > source.Height || this.Size > source.Width) if (this.Size <= 0 || this.Size > source.Height || this.Size > source.Width)
{ {
@ -73,7 +73,7 @@ namespace SixLabors.ImageSharp.Processing.Processors
Parallel.ForEach( Parallel.ForEach(
range, range,
source.Configuration().ParallelOptions, configuration.ParallelOptions,
y => y =>
{ {
int offsetY = y - startY; int offsetY = y - startY;

47
src/ImageSharp/Processing/Processors/ImageProcessor.cs

@ -2,7 +2,7 @@
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using System; using System;
using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
using SixLabors.Primitives; using SixLabors.Primitives;
@ -20,13 +20,12 @@ namespace SixLabors.ImageSharp.Processing
{ {
try try
{ {
var config = source.Configuration();
this.BeforeImageApply(source, sourceRectangle); this.BeforeImageApply(source, sourceRectangle);
foreach (ImageFrame<TPixel> sourceFrame in source.Frames) foreach (ImageFrame<TPixel> sourceFrame in source.Frames)
{ {
this.BeforeApply(sourceFrame, sourceRectangle); this.Apply(sourceFrame, sourceRectangle, config);
this.OnApply(sourceFrame, sourceRectangle);
this.AfterApply(sourceFrame, sourceRectangle);
} }
this.AfterImageApply(source, sourceRectangle); this.AfterImageApply(source, sourceRectangle);
@ -48,13 +47,14 @@ namespace SixLabors.ImageSharp.Processing
/// </summary> /// </summary>
/// <param name="source">the source image</param> /// <param name="source">the source image</param>
/// <param name="sourceRectangle">the target</param> /// <param name="sourceRectangle">the target</param>
public void Apply(ImageFrame<TPixel> source, Rectangle sourceRectangle) /// <param name="configuration">The configuration.</param>
public void Apply(ImageFrame<TPixel> source, Rectangle sourceRectangle, Configuration configuration)
{ {
try try
{ {
this.BeforeApply(source, sourceRectangle); this.BeforeApply(source, sourceRectangle, configuration);
this.OnApply(source, sourceRectangle); this.OnApply(source, sourceRectangle, configuration);
this.AfterApply(source, sourceRectangle); this.AfterApply(source, sourceRectangle, configuration);
} }
#if DEBUG #if DEBUG
catch (Exception) catch (Exception)
@ -72,9 +72,7 @@ namespace SixLabors.ImageSharp.Processing
/// This method is called before the process is applied to prepare the processor. /// This method is called before the process is applied to prepare the processor.
/// </summary> /// </summary>
/// <param name="source">The source image. Cannot be null.</param> /// <param name="source">The source image. Cannot be null.</param>
/// <param name="sourceRectangle"> /// <param name="sourceRectangle">The <see cref="Rectangle" /> structure that specifies the portion of the image object to draw.</param>
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to draw.
/// </param>
protected virtual void BeforeImageApply(Image<TPixel> source, Rectangle sourceRectangle) protected virtual void BeforeImageApply(Image<TPixel> source, Rectangle sourceRectangle)
{ {
} }
@ -83,31 +81,28 @@ namespace SixLabors.ImageSharp.Processing
/// This method is called before the process is applied to prepare the processor. /// This method is called before the process is applied to prepare the processor.
/// </summary> /// </summary>
/// <param name="source">The source image. Cannot be null.</param> /// <param name="source">The source image. Cannot be null.</param>
/// <param name="sourceRectangle"> /// <param name="sourceRectangle">The <see cref="Rectangle" /> structure that specifies the portion of the image object to draw.</param>
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to draw. /// <param name="configuration">The configuration.</param>
/// </param> protected virtual void BeforeApply(ImageFrame<TPixel> source, Rectangle sourceRectangle, Configuration configuration)
protected virtual void BeforeApply(ImageFrame<TPixel> source, Rectangle sourceRectangle)
{ {
} }
/// <summary> /// <summary>
/// Applies the process to the specified portion of the specified <see cref="ImageFrame{TPixel}"/> at the specified location /// Applies the process to the specified portion of the specified <see cref="ImageFrame{TPixel}" /> at the specified location
/// and with the specified size. /// and with the specified size.
/// </summary> /// </summary>
/// <param name="source">The source image. Cannot be null.</param> /// <param name="source">The source image. Cannot be null.</param>
/// <param name="sourceRectangle"> /// <param name="sourceRectangle">The <see cref="Rectangle" /> structure that specifies the portion of the image object to draw.</param>
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to draw. /// <param name="configuration">The configuration.</param>
/// </param> protected abstract void OnApply(ImageFrame<TPixel> source, Rectangle sourceRectangle, Configuration configuration);
protected abstract void OnApply(ImageFrame<TPixel> source, Rectangle sourceRectangle);
/// <summary> /// <summary>
/// This method is called after the process is applied to prepare the processor. /// This method is called after the process is applied to prepare the processor.
/// </summary> /// </summary>
/// <param name="source">The source image. Cannot be null.</param> /// <param name="source">The source image. Cannot be null.</param>
/// <param name="sourceRectangle"> /// <param name="sourceRectangle">The <see cref="Rectangle" /> structure that specifies the portion of the image object to draw.</param>
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to draw. /// <param name="configuration">The configuration.</param>
/// </param> protected virtual void AfterApply(ImageFrame<TPixel> source, Rectangle sourceRectangle, Configuration configuration)
protected virtual void AfterApply(ImageFrame<TPixel> source, Rectangle sourceRectangle)
{ {
} }
@ -115,9 +110,7 @@ namespace SixLabors.ImageSharp.Processing
/// This method is called after the process is applied to prepare the processor. /// This method is called after the process is applied to prepare the processor.
/// </summary> /// </summary>
/// <param name="source">The source image. Cannot be null.</param> /// <param name="source">The source image. Cannot be null.</param>
/// <param name="sourceRectangle"> /// <param name="sourceRectangle">The <see cref="Rectangle" /> structure that specifies the portion of the image object to draw.</param>
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to draw.
/// </param>
protected virtual void AfterImageApply(Image<TPixel> source, Rectangle sourceRectangle) protected virtual void AfterImageApply(Image<TPixel> source, Rectangle sourceRectangle)
{ {
} }

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

@ -52,7 +52,7 @@ namespace SixLabors.ImageSharp.Processing.Processors
public ValueSize Radius { get; set; } public ValueSize Radius { get; set; }
/// <inheritdoc/> /// <inheritdoc/>
protected override void OnApply(ImageFrame<TPixel> source, Rectangle sourceRectangle) protected override void OnApply(ImageFrame<TPixel> source, Rectangle sourceRectangle, Configuration configuration)
{ {
int startY = sourceRectangle.Y; int startY = sourceRectangle.Y;
int endY = sourceRectangle.Bottom; int endY = sourceRectangle.Bottom;
@ -93,7 +93,7 @@ namespace SixLabors.ImageSharp.Processing.Processors
Parallel.For( Parallel.For(
minY, minY,
maxY, maxY,
source.Configuration().ParallelOptions, configuration.ParallelOptions,
y => y =>
{ {
using (var amounts = new Buffer<float>(width)) using (var amounts = new Buffer<float>(width))

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

@ -71,7 +71,7 @@ namespace SixLabors.ImageSharp.Processing.Processors
public ValueSize RadiusY { get; set; } public ValueSize RadiusY { get; set; }
/// <inheritdoc/> /// <inheritdoc/>
protected override void OnApply(ImageFrame<TPixel> source, Rectangle sourceRectangle) protected override void OnApply(ImageFrame<TPixel> source, Rectangle sourceRectangle, Configuration configuration)
{ {
int startY = sourceRectangle.Y; int startY = sourceRectangle.Y;
int endY = sourceRectangle.Bottom; int endY = sourceRectangle.Bottom;
@ -114,7 +114,7 @@ namespace SixLabors.ImageSharp.Processing.Processors
Parallel.For( Parallel.For(
minY, minY,
maxY, maxY,
source.Configuration().ParallelOptions, configuration.ParallelOptions,
y => y =>
{ {
using (var amounts = new Buffer<float>(width)) using (var amounts = new Buffer<float>(width))

2
src/ImageSharp/Processing/Processors/Transforms/AutoOrientProcessor.cs

@ -61,7 +61,7 @@ namespace SixLabors.ImageSharp.Processing.Processors
} }
/// <inheritdoc /> /// <inheritdoc />
protected override void OnApply(ImageFrame<TPixel> source, Rectangle sourceRectangle) protected override void OnApply(ImageFrame<TPixel> source, Rectangle sourceRectangle, Configuration configuration)
{ {
// Nothing required here // Nothing required here
} }

4
src/ImageSharp/Processing/Processors/Transforms/CropProcessor.cs

@ -32,7 +32,7 @@ namespace SixLabors.ImageSharp.Processing.Processors
public Rectangle CropRectangle { get; } public Rectangle CropRectangle { get; }
/// <inheritdoc/> /// <inheritdoc/>
protected override void OnApply(ImageFrame<TPixel> source, Rectangle sourceRectangle) protected override void OnApply(ImageFrame<TPixel> source, Rectangle sourceRectangle, Configuration configuration)
{ {
if (this.CropRectangle == sourceRectangle) if (this.CropRectangle == sourceRectangle)
{ {
@ -49,7 +49,7 @@ namespace SixLabors.ImageSharp.Processing.Processors
Parallel.For( Parallel.For(
minY, minY,
maxY, maxY,
source.Configuration().ParallelOptions, configuration.ParallelOptions,
y => y =>
{ {
Span<TPixel> sourceRow = source.GetPixelRowSpan(y).Slice(minX); Span<TPixel> sourceRow = source.GetPixelRowSpan(y).Slice(minX);

8
src/ImageSharp/Processing/Processors/Transforms/EntropyCropProcessor.cs

@ -34,15 +34,15 @@ namespace SixLabors.ImageSharp.Processing.Processors
public float Threshold { get; } public float Threshold { get; }
/// <inheritdoc/> /// <inheritdoc/>
protected override void OnApply(ImageFrame<TPixel> source, Rectangle sourceRectangle) protected override void OnApply(ImageFrame<TPixel> source, Rectangle sourceRectangle, Configuration configuration)
{ {
using (ImageFrame<TPixel> temp = source.Clone()) using (ImageFrame<TPixel> temp = source.Clone())
{ {
// Detect the edges. // Detect the edges.
new SobelProcessor<TPixel>().Apply(temp, sourceRectangle); new SobelProcessor<TPixel>().Apply(temp, sourceRectangle, configuration);
// Apply threshold binarization filter. // Apply threshold binarization filter.
new BinaryThresholdProcessor<TPixel>(this.Threshold).Apply(temp, sourceRectangle); new BinaryThresholdProcessor<TPixel>(this.Threshold).Apply(temp, sourceRectangle, configuration);
// Search for the first white pixels // Search for the first white pixels
Rectangle rectangle = ImageMaths.GetFilteredBoundingRectangle(temp, 0); Rectangle rectangle = ImageMaths.GetFilteredBoundingRectangle(temp, 0);
@ -52,7 +52,7 @@ namespace SixLabors.ImageSharp.Processing.Processors
return; return;
} }
new CropProcessor<TPixel>(rectangle).Apply(source, sourceRectangle); new CropProcessor<TPixel>(rectangle).Apply(source, sourceRectangle, configuration);
} }
} }
} }

16
src/ImageSharp/Processing/Processors/Transforms/FlipProcessor.cs

@ -32,16 +32,16 @@ namespace SixLabors.ImageSharp.Processing.Processors
public FlipType FlipType { get; } public FlipType FlipType { get; }
/// <inheritdoc/> /// <inheritdoc/>
protected override void OnApply(ImageFrame<TPixel> source, Rectangle sourceRectangle) protected override void OnApply(ImageFrame<TPixel> source, Rectangle sourceRectangle, Configuration configuration)
{ {
switch (this.FlipType) switch (this.FlipType)
{ {
// No default needed as we have already set the pixels. // No default needed as we have already set the pixels.
case FlipType.Vertical: case FlipType.Vertical:
this.FlipX(source); this.FlipX(source, configuration);
break; break;
case FlipType.Horizontal: case FlipType.Horizontal:
this.FlipY(source); this.FlipY(source, configuration);
break; break;
} }
} }
@ -51,7 +51,8 @@ namespace SixLabors.ImageSharp.Processing.Processors
/// at half the height of the image. /// at half the height of the image.
/// </summary> /// </summary>
/// <param name="source">The source image to apply the process to.</param> /// <param name="source">The source image to apply the process to.</param>
private void FlipX(ImageFrame<TPixel> source) /// <param name="configuration">The configuration.</param>
private void FlipX(ImageFrame<TPixel> source, Configuration configuration)
{ {
int width = source.Width; int width = source.Width;
int height = source.Height; int height = source.Height;
@ -62,7 +63,7 @@ namespace SixLabors.ImageSharp.Processing.Processors
Parallel.For( Parallel.For(
0, 0,
halfHeight, halfHeight,
source.Configuration().ParallelOptions, configuration.ParallelOptions,
y => y =>
{ {
int newY = height - y - 1; int newY = height - y - 1;
@ -84,7 +85,8 @@ namespace SixLabors.ImageSharp.Processing.Processors
/// at half of the width of the image. /// at half of the width of the image.
/// </summary> /// </summary>
/// <param name="source">The source image to apply the process to.</param> /// <param name="source">The source image to apply the process to.</param>
private void FlipY(ImageFrame<TPixel> source) /// <param name="configuration">The configuration.</param>
private void FlipY(ImageFrame<TPixel> source, Configuration configuration)
{ {
int width = source.Width; int width = source.Width;
int height = source.Height; int height = source.Height;
@ -95,7 +97,7 @@ namespace SixLabors.ImageSharp.Processing.Processors
Parallel.For( Parallel.For(
0, 0,
height, height,
source.Configuration().ParallelOptions, configuration.ParallelOptions,
y => y =>
{ {
Span<TPixel> sourceRow = source.GetPixelRowSpan(y); Span<TPixel> sourceRow = source.GetPixelRowSpan(y);

6
src/ImageSharp/Processing/Processors/Transforms/ResamplingWeightedProcessor.cs

@ -137,7 +137,7 @@ namespace SixLabors.ImageSharp.Processing.Processors
} }
/// <inheritdoc/> /// <inheritdoc/>
protected override void BeforeApply(ImageFrame<TPixel> source, ImageFrame<TPixel> destination, Rectangle sourceRectangle) protected override void BeforeApply(ImageFrame<TPixel> source, ImageFrame<TPixel> destination, Rectangle sourceRectangle, Configuration configuration)
{ {
if (!(this.Sampler is NearestNeighborResampler)) if (!(this.Sampler is NearestNeighborResampler))
{ {
@ -152,9 +152,9 @@ namespace SixLabors.ImageSharp.Processing.Processors
} }
/// <inheritdoc /> /// <inheritdoc />
protected override void AfterApply(ImageFrame<TPixel> source, ImageFrame<TPixel> destination, Rectangle sourceRectangle) protected override void AfterApply(ImageFrame<TPixel> source, ImageFrame<TPixel> destination, Rectangle sourceRectangle, Configuration configuration)
{ {
base.AfterApply(source, destination, sourceRectangle); base.AfterApply(source, destination, sourceRectangle, configuration);
this.HorizontalWeights?.Dispose(); this.HorizontalWeights?.Dispose();
this.HorizontalWeights = null; this.HorizontalWeights = null;
this.VerticalWeights?.Dispose(); this.VerticalWeights?.Dispose();

8
src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs

@ -66,7 +66,7 @@ namespace SixLabors.ImageSharp.Processing.Processors
} }
/// <inheritdoc/> /// <inheritdoc/>
protected override unsafe void OnApply(ImageFrame<TPixel> source, ImageFrame<TPixel> cloned, Rectangle sourceRectangle) protected override unsafe void OnApply(ImageFrame<TPixel> source, ImageFrame<TPixel> cloned, Rectangle sourceRectangle, Configuration configuration)
{ {
// Jump out, we'll deal with that later. // Jump out, we'll deal with that later.
if (source.Width == cloned.Width && source.Height == cloned.Height && sourceRectangle == this.ResizeRectangle) if (source.Width == cloned.Width && source.Height == cloned.Height && sourceRectangle == this.ResizeRectangle)
@ -99,7 +99,7 @@ namespace SixLabors.ImageSharp.Processing.Processors
Parallel.For( Parallel.For(
minY, minY,
maxY, maxY,
source.Configuration().ParallelOptions, configuration.ParallelOptions,
y => y =>
{ {
// Y coordinates of source points // Y coordinates of source points
@ -128,7 +128,7 @@ namespace SixLabors.ImageSharp.Processing.Processors
Parallel.For( Parallel.For(
0, 0,
sourceRectangle.Bottom, sourceRectangle.Bottom,
source.Configuration().ParallelOptions, configuration.ParallelOptions,
y => y =>
{ {
// TODO: Without Parallel.For() this buffer object could be reused: // TODO: Without Parallel.For() this buffer object could be reused:
@ -161,7 +161,7 @@ namespace SixLabors.ImageSharp.Processing.Processors
Parallel.For( Parallel.For(
minY, minY,
maxY, maxY,
source.Configuration().ParallelOptions, configuration.ParallelOptions,
y => y =>
{ {
// Ensure offsets are normalised for cropping and padding. // Ensure offsets are normalised for cropping and padding.

36
src/ImageSharp/Processing/Processors/Transforms/RotateProcessor.cs

@ -35,9 +35,9 @@ namespace SixLabors.ImageSharp.Processing.Processors
public bool Expand { get; set; } = true; public bool Expand { get; set; } = true;
/// <inheritdoc/> /// <inheritdoc/>
protected override void OnApply(ImageFrame<TPixel> source, Rectangle sourceRectangle) protected override void OnApply(ImageFrame<TPixel> source, Rectangle sourceRectangle, Configuration configuration)
{ {
if (this.OptimizedApply(source)) if (this.OptimizedApply(source, configuration))
{ {
return; return;
} }
@ -52,7 +52,7 @@ namespace SixLabors.ImageSharp.Processing.Processors
Parallel.For( Parallel.For(
0, 0,
height, height,
source.Configuration().ParallelOptions, configuration.ParallelOptions,
y => y =>
{ {
Span<TPixel> targetRow = targetPixels.GetRowSpan(y); Span<TPixel> targetRow = targetPixels.GetRowSpan(y);
@ -73,7 +73,7 @@ namespace SixLabors.ImageSharp.Processing.Processors
} }
/// <inheritdoc/> /// <inheritdoc/>
protected override void BeforeApply(ImageFrame<TPixel> source, Rectangle sourceRectangle) protected override void BeforeApply(ImageFrame<TPixel> source, Rectangle sourceRectangle, Configuration configuration)
{ {
if (MathF.Abs(this.Angle) < Constants.Epsilon || MathF.Abs(this.Angle - 90) < Constants.Epsilon || MathF.Abs(this.Angle - 180) < Constants.Epsilon || MathF.Abs(this.Angle - 270) < Constants.Epsilon) if (MathF.Abs(this.Angle) < Constants.Epsilon || MathF.Abs(this.Angle - 90) < Constants.Epsilon || MathF.Abs(this.Angle - 180) < Constants.Epsilon || MathF.Abs(this.Angle - 270) < Constants.Epsilon)
{ {
@ -91,8 +91,11 @@ namespace SixLabors.ImageSharp.Processing.Processors
/// Rotates the images with an optimized method when the angle is 90, 180 or 270 degrees. /// Rotates the images with an optimized method when the angle is 90, 180 or 270 degrees.
/// </summary> /// </summary>
/// <param name="source">The source image.</param> /// <param name="source">The source image.</param>
/// <returns>The <see cref="bool"/></returns> /// <param name="configuration">The configuration.</param>
private bool OptimizedApply(ImageFrame<TPixel> source) /// <returns>
/// The <see cref="bool" />
/// </returns>
private bool OptimizedApply(ImageFrame<TPixel> source, Configuration configuration)
{ {
if (MathF.Abs(this.Angle) < Constants.Epsilon) if (MathF.Abs(this.Angle) < Constants.Epsilon)
{ {
@ -102,19 +105,19 @@ namespace SixLabors.ImageSharp.Processing.Processors
if (MathF.Abs(this.Angle - 90) < Constants.Epsilon) if (MathF.Abs(this.Angle - 90) < Constants.Epsilon)
{ {
this.Rotate90(source); this.Rotate90(source, configuration);
return true; return true;
} }
if (MathF.Abs(this.Angle - 180) < Constants.Epsilon) if (MathF.Abs(this.Angle - 180) < Constants.Epsilon)
{ {
this.Rotate180(source); this.Rotate180(source, configuration);
return true; return true;
} }
if (MathF.Abs(this.Angle - 270) < Constants.Epsilon) if (MathF.Abs(this.Angle - 270) < Constants.Epsilon)
{ {
this.Rotate270(source); this.Rotate270(source, configuration);
return true; return true;
} }
@ -125,7 +128,8 @@ namespace SixLabors.ImageSharp.Processing.Processors
/// Rotates the image 270 degrees clockwise at the centre point. /// Rotates the image 270 degrees clockwise at the centre point.
/// </summary> /// </summary>
/// <param name="source">The source image.</param> /// <param name="source">The source image.</param>
private void Rotate270(ImageFrame<TPixel> source) /// <param name="configuration">The configuration.</param>
private void Rotate270(ImageFrame<TPixel> source, Configuration configuration)
{ {
int width = source.Width; int width = source.Width;
int height = source.Height; int height = source.Height;
@ -137,7 +141,7 @@ namespace SixLabors.ImageSharp.Processing.Processors
Parallel.For( Parallel.For(
0, 0,
height, height,
source.Configuration().ParallelOptions, configuration.ParallelOptions,
y => y =>
{ {
for (int x = 0; x < width; x++) for (int x = 0; x < width; x++)
@ -158,7 +162,8 @@ namespace SixLabors.ImageSharp.Processing.Processors
/// Rotates the image 180 degrees clockwise at the centre point. /// Rotates the image 180 degrees clockwise at the centre point.
/// </summary> /// </summary>
/// <param name="source">The source image.</param> /// <param name="source">The source image.</param>
private void Rotate180(ImageFrame<TPixel> source) /// <param name="configuration">The configuration.</param>
private void Rotate180(ImageFrame<TPixel> source, Configuration configuration)
{ {
int width = source.Width; int width = source.Width;
int height = source.Height; int height = source.Height;
@ -168,7 +173,7 @@ namespace SixLabors.ImageSharp.Processing.Processors
Parallel.For( Parallel.For(
0, 0,
height, height,
source.Configuration().ParallelOptions, configuration.ParallelOptions,
y => y =>
{ {
Span<TPixel> sourceRow = source.GetPixelRowSpan(y); Span<TPixel> sourceRow = source.GetPixelRowSpan(y);
@ -188,7 +193,8 @@ namespace SixLabors.ImageSharp.Processing.Processors
/// Rotates the image 90 degrees clockwise at the centre point. /// Rotates the image 90 degrees clockwise at the centre point.
/// </summary> /// </summary>
/// <param name="source">The source image.</param> /// <param name="source">The source image.</param>
private void Rotate90(ImageFrame<TPixel> source) /// <param name="configuration">The configuration.</param>
private void Rotate90(ImageFrame<TPixel> source, Configuration configuration)
{ {
int width = source.Width; int width = source.Width;
int height = source.Height; int height = source.Height;
@ -198,7 +204,7 @@ namespace SixLabors.ImageSharp.Processing.Processors
Parallel.For( Parallel.For(
0, 0,
height, height,
source.Configuration().ParallelOptions, configuration.ParallelOptions,
y => y =>
{ {
Span<TPixel> sourceRow = source.GetPixelRowSpan(y); Span<TPixel> sourceRow = source.GetPixelRowSpan(y);

6
src/ImageSharp/Processing/Processors/Transforms/SkewProcessor.cs

@ -40,7 +40,7 @@ namespace SixLabors.ImageSharp.Processing.Processors
public bool Expand { get; set; } = true; public bool Expand { get; set; } = true;
/// <inheritdoc/> /// <inheritdoc/>
protected override void OnApply(ImageFrame<TPixel> source, Rectangle sourceRectangle) protected override void OnApply(ImageFrame<TPixel> source, Rectangle sourceRectangle, Configuration configuration)
{ {
int height = this.CanvasRectangle.Height; int height = this.CanvasRectangle.Height;
int width = this.CanvasRectangle.Width; int width = this.CanvasRectangle.Width;
@ -52,7 +52,7 @@ namespace SixLabors.ImageSharp.Processing.Processors
Parallel.For( Parallel.For(
0, 0,
height, height,
source.Configuration().ParallelOptions, configuration.ParallelOptions,
y => y =>
{ {
Span<TPixel> targetRow = targetPixels.GetRowSpan(y); Span<TPixel> targetRow = targetPixels.GetRowSpan(y);
@ -73,7 +73,7 @@ namespace SixLabors.ImageSharp.Processing.Processors
} }
/// <inheritdoc/> /// <inheritdoc/>
protected override void BeforeApply(ImageFrame<TPixel> source, Rectangle sourceRectangle) protected override void BeforeApply(ImageFrame<TPixel> source, Rectangle sourceRectangle, Configuration configuration)
{ {
this.processMatrix = Matrix3x2Extensions.CreateSkewDegrees(-this.AngleX, -this.AngleY, new Point(0, 0)); this.processMatrix = Matrix3x2Extensions.CreateSkewDegrees(-this.AngleX, -this.AngleY, new Point(0, 0));
if (this.Expand) if (this.Expand)

4
tests/ImageSharp.Benchmarks/Samplers/Glow.cs

@ -75,7 +75,7 @@ namespace SixLabors.ImageSharp.Benchmarks
public float Radius { get; set; } public float Radius { get; set; }
/// <inheritdoc/> /// <inheritdoc/>
protected override void OnApply(ImageFrame<TPixel> source, Rectangle sourceRectangle) protected override void OnApply(ImageFrame<TPixel> source, Rectangle sourceRectangle, Configuration configuration)
{ {
int startY = sourceRectangle.Y; int startY = sourceRectangle.Y;
int endY = sourceRectangle.Bottom; int endY = sourceRectangle.Bottom;
@ -114,7 +114,7 @@ namespace SixLabors.ImageSharp.Benchmarks
Parallel.For( Parallel.For(
minY, minY,
maxY, maxY,
source.Configuration().ParallelOptions, configuration.ParallelOptions,
y => y =>
{ {
int offsetY = y - startY; int offsetY = y - startY;

4
tests/ImageSharp.Tests/TestUtilities/ImageComparison/ExactImageComparer.cs

@ -12,7 +12,7 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison
{ {
public static ExactImageComparer Instance { get; } = new ExactImageComparer(); public static ExactImageComparer Instance { get; } = new ExactImageComparer();
public override ImageSimilarityReport CompareImagesOrFrames<TPixelA, TPixelB>( public override ImageSimilarityReport<TPixelA, TPixelB> CompareImagesOrFrames<TPixelA, TPixelB>(
ImageFrame<TPixelA> expected, ImageFrame<TPixelA> expected,
ImageFrame<TPixelB> actual) ImageFrame<TPixelB> actual)
{ {
@ -51,7 +51,7 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison
} }
} }
return new ImageSimilarityReport(expected, actual, differences); return new ImageSimilarityReport<TPixelA, TPixelB>(expected, actual, differences);
} }
} }
} }

16
tests/ImageSharp.Tests/TestUtilities/ImageComparison/ImageComparer.cs

@ -22,7 +22,7 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison
return new TolerantImageComparer(imageThreshold, perPixelManhattanThreshold); return new TolerantImageComparer(imageThreshold, perPixelManhattanThreshold);
} }
public abstract ImageSimilarityReport CompareImagesOrFrames<TPixelA, TPixelB>( public abstract ImageSimilarityReport<TPixelA, TPixelB> CompareImagesOrFrames<TPixelA, TPixelB>(
ImageFrame<TPixelA> expected, ImageFrame<TPixelA> expected,
ImageFrame<TPixelB> actual) ImageFrame<TPixelB> actual)
where TPixelA : struct, IPixel<TPixelA> where TPixelB : struct, IPixel<TPixelB>; where TPixelA : struct, IPixel<TPixelA> where TPixelB : struct, IPixel<TPixelB>;
@ -30,7 +30,7 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison
public static class ImageComparerExtensions public static class ImageComparerExtensions
{ {
public static ImageSimilarityReport CompareImagesOrFrames<TPixelA, TPixelB>( public static ImageSimilarityReport<TPixelA, TPixelB> CompareImagesOrFrames<TPixelA, TPixelB>(
this ImageComparer comparer, this ImageComparer comparer,
Image<TPixelA> expected, Image<TPixelA> expected,
Image<TPixelB> actual) Image<TPixelB> actual)
@ -39,13 +39,13 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison
return comparer.CompareImagesOrFrames((ImageFrame<TPixelA>)expected, (ImageFrame<TPixelB>)actual); return comparer.CompareImagesOrFrames((ImageFrame<TPixelA>)expected, (ImageFrame<TPixelB>)actual);
} }
public static IEnumerable<ImageSimilarityReport> CompareImages<TPixelA, TPixelB>( public static IEnumerable<ImageSimilarityReport<TPixelA, TPixelB>> CompareImages<TPixelA, TPixelB>(
this ImageComparer comparer, this ImageComparer comparer,
Image<TPixelA> expected, Image<TPixelA> expected,
Image<TPixelB> actual) Image<TPixelB> actual)
where TPixelA : struct, IPixel<TPixelA> where TPixelB : struct, IPixel<TPixelB> where TPixelA : struct, IPixel<TPixelA> where TPixelB : struct, IPixel<TPixelB>
{ {
var result = new List<ImageSimilarityReport>(); var result = new List<ImageSimilarityReport<TPixelA, TPixelB>>();
if (expected.Frames.Count != actual.Frames.Count) if (expected.Frames.Count != actual.Frames.Count)
{ {
@ -53,7 +53,7 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison
} }
for (int i = 0; i < expected.Frames.Count; i++) for (int i = 0; i < expected.Frames.Count; i++)
{ {
ImageSimilarityReport report = comparer.CompareImagesOrFrames(expected.Frames[i], actual.Frames[i]); ImageSimilarityReport<TPixelA, TPixelB> report = comparer.CompareImagesOrFrames(expected.Frames[i], actual.Frames[i]);
if (!report.IsEmpty) if (!report.IsEmpty)
{ {
result.Add(report); result.Add(report);
@ -104,10 +104,10 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison
throw new ImagesSimilarityException("Image frame count does not match!"); throw new ImagesSimilarityException("Image frame count does not match!");
} }
IEnumerable<ImageSimilarityReport> reports = comparer.CompareImages(expected, actual); IEnumerable<ImageSimilarityReport<TPixelA, TPixelB>> reports = comparer.CompareImages(expected, actual);
if (reports.Any()) if (reports.Any())
{ {
List<ImageSimilarityReport> cleanedReports = new List<ImageSimilarityReport>(reports.Count()); List<ImageSimilarityReport<TPixelA, TPixelB>> cleanedReports = new List<ImageSimilarityReport<TPixelA, TPixelB>>(reports.Count());
foreach (var r in reports) foreach (var r in reports)
{ {
var outsideChanges = r.Differences.Where(x => !( var outsideChanges = r.Differences.Where(x => !(
@ -117,7 +117,7 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison
x.Position.Y <= ignoredRegion.Bottom)); x.Position.Y <= ignoredRegion.Bottom));
if (outsideChanges.Any()) if (outsideChanges.Any())
{ {
cleanedReports.Add(new ImageSimilarityReport(r.ExpectedImage, r.ActualImage, outsideChanges, null)); cleanedReports.Add(new ImageSimilarityReport<TPixelA, TPixelB>(r.ExpectedImage, r.ActualImage, outsideChanges, null));
} }
} }

38
tests/ImageSharp.Tests/TestUtilities/ImageComparison/ImageSimilarityReport.cs

@ -4,12 +4,13 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using SixLabors.ImageSharp.PixelFormats;
public class ImageSimilarityReport public class ImageSimilarityReport
{ {
public ImageSimilarityReport( protected ImageSimilarityReport(
IImageFrame expectedImage, object expectedImage,
IImageFrame actualImage, object actualImage,
IEnumerable<PixelDifference> differences, IEnumerable<PixelDifference> differences,
float? totalNormalizedDifference = null) float? totalNormalizedDifference = null)
{ {
@ -18,9 +19,9 @@
this.TotalNormalizedDifference = totalNormalizedDifference; this.TotalNormalizedDifference = totalNormalizedDifference;
this.Differences = differences.ToArray(); this.Differences = differences.ToArray();
} }
public object ExpectedImage { get; }
public static ImageSimilarityReport Empty => public object ActualImage { get; }
new ImageSimilarityReport(null, null, Enumerable.Empty<PixelDifference>(), 0f);
// TODO: This should not be a nullable value! // TODO: This should not be a nullable value!
public float? TotalNormalizedDifference { get; } public float? TotalNormalizedDifference { get; }
@ -29,10 +30,6 @@
? $"{this.TotalNormalizedDifference.Value * 100:0.0000}%" ? $"{this.TotalNormalizedDifference.Value * 100:0.0000}%"
: "?"; : "?";
public IImageFrame ExpectedImage { get; }
public IImageFrame ActualImage { get; }
public PixelDifference[] Differences { get; } public PixelDifference[] Differences { get; }
public bool IsEmpty => this.Differences.Length == 0; public bool IsEmpty => this.Differences.Length == 0;
@ -41,7 +38,7 @@
{ {
return this.IsEmpty ? "[SimilarImages]" : this.PrintDifference(); return this.IsEmpty ? "[SimilarImages]" : this.PrintDifference();
} }
private string PrintDifference() private string PrintDifference()
{ {
var sb = new StringBuilder(); var sb = new StringBuilder();
@ -66,4 +63,25 @@
return sb.ToString(); return sb.ToString();
} }
} }
public class ImageSimilarityReport<TPixelA, TPixelB> : ImageSimilarityReport
where TPixelA : struct, IPixel<TPixelA>
where TPixelB : struct, IPixel<TPixelB>
{
public ImageSimilarityReport(
ImageFrame<TPixelA> expectedImage,
ImageFrame<TPixelB> actualImage,
IEnumerable<PixelDifference> differences,
float? totalNormalizedDifference = null)
: base(expectedImage, actualImage, differences, totalNormalizedDifference)
{
}
public static ImageSimilarityReport<TPixelA, TPixelB> Empty =>
new ImageSimilarityReport<TPixelA, TPixelB>(null, null, Enumerable.Empty<PixelDifference>(), 0f);
public new ImageFrame<TPixelA> ExpectedImage => (ImageFrame<TPixelA>)base.ExpectedImage;
public new ImageFrame<TPixelB> ActualImage => (ImageFrame<TPixelB>)base.ActualImage;
}
} }

6
tests/ImageSharp.Tests/TestUtilities/ImageComparison/TolerantImageComparer.cs

@ -46,7 +46,7 @@
/// </summary> /// </summary>
public int PerPixelManhattanThreshold { get; } public int PerPixelManhattanThreshold { get; }
public override ImageSimilarityReport CompareImagesOrFrames<TPixelA, TPixelB>(ImageFrame<TPixelA> expected, ImageFrame<TPixelB> actual) public override ImageSimilarityReport<TPixelA, TPixelB> CompareImagesOrFrames<TPixelA, TPixelB>(ImageFrame<TPixelA> expected, ImageFrame<TPixelB> actual)
{ {
if (expected.Size() != actual.Size()) if (expected.Size() != actual.Size())
{ {
@ -91,11 +91,11 @@
if (normalizedDifference > this.ImageThreshold) if (normalizedDifference > this.ImageThreshold)
{ {
return new ImageSimilarityReport(expected, actual, differences, normalizedDifference); return new ImageSimilarityReport<TPixelA, TPixelB>(expected, actual, differences, normalizedDifference);
} }
else else
{ {
return ImageSimilarityReport.Empty; return ImageSimilarityReport<TPixelA, TPixelB>.Empty;
} }
} }

Loading…
Cancel
Save