Browse Source

Make processors public, refactor cloning.

af/merge-core
James Jackson-South 6 years ago
parent
commit
d62fa6929b
  1. 16
      src/ImageSharp.Drawing/Processing/Processors/Drawing/DrawImageProcessor{TPixelBg,TPixelFg}.cs
  2. 22
      src/ImageSharp/Processing/DefaultImageProcessorContext{TPixel}.cs
  3. 31
      src/ImageSharp/Processing/Processors/CloningImageProcessor.cs
  4. 45
      src/ImageSharp/Processing/Processors/CloningImageProcessor{TPixel}.cs
  5. 15
      src/ImageSharp/Processing/Processors/ICloningImageProcessor{TPixel}.cs
  6. 2
      src/ImageSharp/Processing/Processors/IImageProcessor.cs
  7. 11
      src/ImageSharp/Processing/Processors/IImageProcessor{TPixel}.cs
  8. 2
      src/ImageSharp/Processing/Processors/ImageProcessorExtensions.cs
  9. 9
      src/ImageSharp/Processing/Processors/ImageProcessor{TPixel}.cs
  10. 13
      src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessor.cs
  11. 11
      src/ImageSharp/Processing/Processors/Transforms/CropProcessor.cs
  12. 11
      src/ImageSharp/Processing/Processors/Transforms/ProjectiveTransformProcessor.cs
  13. 8
      src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeProcessor.cs
  14. 7
      src/ImageSharp/Processing/Processors/Transforms/RotateProcessor.cs
  15. 5
      src/ImageSharp/Processing/Processors/Transforms/SkewProcessor.cs
  16. 59
      tests/ImageSharp.Tests/Processing/ImageProcessingContextTests.cs

16
src/ImageSharp.Drawing/Processing/Processors/Drawing/DrawImageProcessor{TPixelBg,TPixelFg}.cs

@ -91,7 +91,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Drawing
var workingRect = Rectangle.FromLTRB(minX, minY, maxX, maxY); var workingRect = Rectangle.FromLTRB(minX, minY, maxX, maxY);
// not a valid operation because rectangle does not overlap with this image. // Not a valid operation because rectangle does not overlap with this image.
if (workingRect.Width <= 0 || workingRect.Height <= 0) if (workingRect.Width <= 0 || workingRect.Height <= 0)
{ {
throw new ImageProcessingException( throw new ImageProcessingException(
@ -102,14 +102,14 @@ namespace SixLabors.ImageSharp.Processing.Processors.Drawing
workingRect, workingRect,
configuration, configuration,
rows => rows =>
{
for (int y = rows.Min; y < rows.Max; y++)
{ {
for (int y = rows.Min; y < rows.Max; y++) Span<TPixelBg> background = source.GetPixelRowSpan(y).Slice(minX, width);
{ Span<TPixelFg> foreground = targetImage.GetPixelRowSpan(y - locationY).Slice(targetX, width);
Span<TPixelBg> background = source.GetPixelRowSpan(y).Slice(minX, width); blender.Blend<TPixelFg>(configuration, background, background, foreground, this.Opacity);
Span<TPixelFg> foreground = targetImage.GetPixelRowSpan(y - locationY).Slice(targetX, width); }
blender.Blend<TPixelFg>(configuration, background, background, foreground, this.Opacity); });
}
});
} }
} }
} }

22
src/ImageSharp/Processing/DefaultImageProcessorContext{TPixel}.cs

@ -29,6 +29,8 @@ namespace SixLabors.ImageSharp.Processing
{ {
this.mutate = mutate; this.mutate = mutate;
this.source = source; this.source = source;
// Mutate acts upon the source image only.
if (this.mutate) if (this.mutate)
{ {
this.destination = source; this.destination = source;
@ -43,7 +45,8 @@ namespace SixLabors.ImageSharp.Processing
{ {
if (!this.mutate && this.destination is null) if (!this.mutate && this.destination is null)
{ {
// Ensure we have cloned it if we are not mutating as we might have failed to register any processors // Ensure we have cloned the source if we are not mutating as we might have failed
// to register any processors.
this.destination = this.source.Clone(); this.destination = this.source.Clone();
} }
@ -64,26 +67,25 @@ namespace SixLabors.ImageSharp.Processing
{ {
if (!this.mutate && this.destination is null) if (!this.mutate && this.destination is null)
{ {
// This will only work if the first processor applied is the cloning one thus // When cloning an image we can optimize the processing pipeline by avoiding an unnecessary
// realistically for this optimization to work the resize must the first processor // interim clone if the first processor in the pipeline is a cloning processor.
// applied any only up processors will take the double data path. if (processor is CloningImageProcessor cloningImageProcessor)
using (IImageProcessor<TPixel> specificProcessor = processor.CreatePixelSpecificProcessor(this.source, rectangle))
{ {
// TODO: if 'specificProcessor' is not an ICloningImageProcessor<TPixel> we are unnecessarily disposing and recreating it. using (ICloningImageProcessor<TPixel> pixelProcessor = cloningImageProcessor.CreatePixelSpecificProcessor(this.source, rectangle))
// This should be solved in a future refactor.
if (specificProcessor is ICloningImageProcessor<TPixel> cloningImageProcessor)
{ {
this.destination = cloningImageProcessor.CloneAndApply(); this.destination = pixelProcessor.CloneAndExecute();
return this; return this;
} }
} }
// Not a cloning processor? We need to create a clone to operate on.
this.destination = this.source.Clone(); this.destination = this.source.Clone();
} }
// Standard processing pipeline.
using (IImageProcessor<TPixel> specificProcessor = processor.CreatePixelSpecificProcessor(this.destination, rectangle)) using (IImageProcessor<TPixel> specificProcessor = processor.CreatePixelSpecificProcessor(this.destination, rectangle))
{ {
specificProcessor.Apply(); specificProcessor.Execute();
} }
return this; return this;

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

@ -0,0 +1,31 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing.Processors
{
/// <summary>
/// The base class for all cloning image processors.
/// </summary>
public abstract class CloningImageProcessor : IImageProcessor
{
/// <summary>
/// Creates a pixel specific <see cref="ICloningImageProcessor{TPixel}"/> that is capable of executing
/// the processing algorithm on an <see cref="Image{TPixel}"/>.
/// </summary>
/// <typeparam name="TPixel">The pixel type.</typeparam>
/// <param name="source">The source image. Cannot be null.</param>
/// <param name="sourceRectangle">
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to draw.
/// </param>
/// <returns>The <see cref="ICloningImageProcessor{TPixel}"/></returns>
public abstract ICloningImageProcessor<TPixel> CreatePixelSpecificProcessor<TPixel>(Image<TPixel> source, Rectangle sourceRectangle)
where TPixel : struct, IPixel<TPixel>;
/// <inheritdoc/>
IImageProcessor<TPixel> IImageProcessor.CreatePixelSpecificProcessor<TPixel>(Image<TPixel> source, Rectangle sourceRectangle)
=> this.CreatePixelSpecificProcessor(source, sourceRectangle);
}
}

45
src/ImageSharp/Processing/Processors/CloningImageProcessor{TPixel}.cs

@ -9,10 +9,12 @@ using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing.Processors namespace SixLabors.ImageSharp.Processing.Processors
{ {
/// <summary> /// <summary>
/// Allows the application of processing algorithms to a clone of the original image. /// The base class for all pixel specific cloning image processors.
/// Allows the application of processing algorithms to the image.
/// The image is cloned before operating upon and the buffers swapped upon completion.
/// </summary> /// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam> /// <typeparam name="TPixel">The pixel format.</typeparam>
internal abstract class CloningImageProcessor<TPixel> : ICloningImageProcessor<TPixel> public abstract class CloningImageProcessor<TPixel> : ICloningImageProcessor<TPixel>
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
private bool isDisposed; private bool isDisposed;
@ -45,16 +47,12 @@ namespace SixLabors.ImageSharp.Processing.Processors
protected Configuration Configuration { get; } protected Configuration Configuration { get; }
/// <inheritdoc/> /// <inheritdoc/>
public Image<TPixel> CloneAndApply() public Image<TPixel> CloneAndExecute()
{ {
try try
{ {
Image<TPixel> clone = this.CreateDestination(); Image<TPixel> clone = this.CreateDestination();
this.CheckFrameCount(this.Source, clone);
if (clone.Frames.Count != this.Source.Frames.Count)
{
throw new ImageProcessingException($"An error occurred when processing the image using {this.GetType().Name}. The processor changed the number of frames.");
}
Configuration configuration = this.Source.GetConfiguration(); Configuration configuration = this.Source.GetConfiguration();
this.BeforeImageApply(clone); this.BeforeImageApply(clone);
@ -86,17 +84,24 @@ namespace SixLabors.ImageSharp.Processing.Processors
} }
/// <inheritdoc/> /// <inheritdoc/>
public void Apply() public void Execute()
{ {
using (Image<TPixel> cloned = this.CloneAndApply()) // Create an interim clone of the source image to operate on.
// Doing this allows for the application of transforms that will alter
// the dimensions of the image.
Image<TPixel> clone = default;
try
{ {
// we now need to move the pixel data/size data from one image base to another clone = this.CloneAndExecute();
if (cloned.Frames.Count != this.Source.Frames.Count)
{
throw new ImageProcessingException($"An error occurred when processing the image using {this.GetType().Name}. The processor changed the number of frames.");
}
this.Source.SwapOrCopyPixelsBuffersFrom(cloned); // We now need to move the pixel data/size data from the clone to the source.
this.CheckFrameCount(this.Source, clone);
this.Source.SwapOrCopyPixelsBuffersFrom(clone);
}
finally
{
// Dispose of the clone now that we have swapped the pixel/size data.
clone?.Dispose();
} }
} }
@ -165,5 +170,13 @@ namespace SixLabors.ImageSharp.Processing.Processors
this.isDisposed = true; this.isDisposed = true;
} }
} }
private void CheckFrameCount(Image<TPixel> a, Image<TPixel> b)
{
if (a.Frames.Count != b.Frames.Count)
{
throw new ImageProcessingException($"An error occurred when processing the image using {this.GetType().Name}. The processor changed the number of frames.");
}
}
} }
} }

15
src/ImageSharp/Processing/Processors/ICloningImageProcessor{TPixel}.cs

@ -2,7 +2,6 @@
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing.Processors namespace SixLabors.ImageSharp.Processing.Processors
{ {
@ -10,19 +9,13 @@ namespace SixLabors.ImageSharp.Processing.Processors
/// Encapsulates methods to alter the pixels of a new image, cloned from the original image. /// Encapsulates methods to alter the pixels of a new image, cloned from the original image.
/// </summary> /// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam> /// <typeparam name="TPixel">The pixel format.</typeparam>
internal interface ICloningImageProcessor<TPixel> : IImageProcessor<TPixel> public interface ICloningImageProcessor<TPixel> : IImageProcessor<TPixel>
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
/// <summary> /// <summary>
/// Applies the process to the specified portion of the specified <see cref="ImageFrame{TPixel}"/>. /// Clones the specified <see cref="Image{TPixel}"/> and executes the process against the clone.
/// </summary> /// </summary>
/// <exception cref="System.ArgumentNullException"> /// <returns>The <see cref="Image{TPixel}"/>.</returns>
/// The target <see cref="Image{TPixel}"/> is null. Image<TPixel> CloneAndExecute();
/// </exception>
/// <exception cref="System.ArgumentException">
/// The target <see cref="Rectangle"/> doesn't fit the dimension of the image.
/// </exception>
/// <returns>Returns the cloned image after there processor has been applied to it.</returns>
Image<TPixel> CloneAndApply();
} }
} }

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

@ -15,7 +15,7 @@ namespace SixLabors.ImageSharp.Processing.Processors
public interface IImageProcessor public interface IImageProcessor
{ {
/// <summary> /// <summary>
/// Creates a pixel specific <see cref="IImageProcessor{TPixel}"/> that is capable for executing /// Creates a pixel specific <see cref="IImageProcessor{TPixel}"/> that is capable of executing
/// the processing algorithm on an <see cref="Image{TPixel}"/>. /// the processing algorithm on an <see cref="Image{TPixel}"/>.
/// </summary> /// </summary>
/// <typeparam name="TPixel">The pixel type.</typeparam> /// <typeparam name="TPixel">The pixel type.</typeparam>

11
src/ImageSharp/Processing/Processors/IImageProcessor{TPixel}.cs

@ -3,7 +3,6 @@
using System; using System;
using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing.Processors namespace SixLabors.ImageSharp.Processing.Processors
{ {
@ -15,14 +14,8 @@ namespace SixLabors.ImageSharp.Processing.Processors
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
/// <summary> /// <summary>
/// Applies the process to the specified portion of the specified <see cref="Image{TPixel}"/>. /// Executes the process against the specified <see cref="Image{TPixel}"/>.
/// </summary> /// </summary>
/// <exception cref="ArgumentNullException"> void Execute();
/// The target <see cref="Image{TPixel}"/> is null.
/// </exception>
/// <exception cref="ArgumentException">
/// The target <see cref="Rectangle"/> doesn't fit the dimension of the image.
/// </exception>
void Apply();
} }
} }

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

@ -30,7 +30,7 @@ namespace SixLabors.ImageSharp.Processing.Processors
{ {
using (IImageProcessor<TPixel> processorImpl = this.processor.CreatePixelSpecificProcessor(image, this.sourceRectangle)) using (IImageProcessor<TPixel> processorImpl = this.processor.CreatePixelSpecificProcessor(image, this.sourceRectangle))
{ {
processorImpl.Apply(); processorImpl.Execute();
} }
} }
} }

9
src/ImageSharp/Processing/Processors/ImageProcessor{TPixel}.cs

@ -9,10 +9,11 @@ using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing.Processors namespace SixLabors.ImageSharp.Processing.Processors
{ {
/// <summary> /// <summary>
/// Allows the application of processors to images. /// The base class for all pixel specific image processors.
/// Allows the application of processing algorithms to the image.
/// </summary> /// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam> /// <typeparam name="TPixel">The pixel format.</typeparam>
internal abstract class ImageProcessor<TPixel> : IImageProcessor<TPixel> public abstract class ImageProcessor<TPixel> : IImageProcessor<TPixel>
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
private bool isDisposed; private bool isDisposed;
@ -45,7 +46,7 @@ namespace SixLabors.ImageSharp.Processing.Processors
protected Configuration Configuration { get; } protected Configuration Configuration { get; }
/// <inheritdoc/> /// <inheritdoc/>
public void Apply() public void Execute()
{ {
try try
{ {
@ -71,7 +72,7 @@ namespace SixLabors.ImageSharp.Processing.Processors
} }
/// <summary> /// <summary>
/// Applies the processor to just a single ImageBase. /// Applies the processor to a single image frame.
/// </summary> /// </summary>
/// <param name="source">the source image.</param> /// <param name="source">the source image.</param>
public void Apply(ImageFrame<TPixel> source) public void Apply(ImageFrame<TPixel> source)

13
src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessor.cs

@ -2,8 +2,6 @@
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using System.Numerics; using System.Numerics;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.Primitives; using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing.Processors.Transforms namespace SixLabors.ImageSharp.Processing.Processors.Transforms
@ -11,7 +9,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
/// <summary> /// <summary>
/// Defines an affine transformation applicable on an <see cref="Image"/>. /// Defines an affine transformation applicable on an <see cref="Image"/>.
/// </summary> /// </summary>
public class AffineTransformProcessor : IImageProcessor public class AffineTransformProcessor : CloningImageProcessor
{ {
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="AffineTransformProcessor"/> class. /// Initializes a new instance of the <see cref="AffineTransformProcessor"/> class.
@ -42,11 +40,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
/// </summary> /// </summary>
public Size TargetDimensions { get; } public Size TargetDimensions { get; }
/// <inheritdoc /> /// <inheritdoc/>
public virtual IImageProcessor<TPixel> CreatePixelSpecificProcessor<TPixel>(Image<TPixel> source, Rectangle sourceRectangle) public override ICloningImageProcessor<TPixel> CreatePixelSpecificProcessor<TPixel>(Image<TPixel> source, Rectangle sourceRectangle)
where TPixel : struct, IPixel<TPixel> => new AffineTransformProcessor<TPixel>(this, source, sourceRectangle);
{
return new AffineTransformProcessor<TPixel>(this, source, sourceRectangle);
}
} }
} }

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

@ -1,7 +1,6 @@
// Copyright (c) Six Labors and contributors. // Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.Primitives; using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing.Processors.Transforms namespace SixLabors.ImageSharp.Processing.Processors.Transforms
@ -9,7 +8,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
/// <summary> /// <summary>
/// Defines a crop operation on an image. /// Defines a crop operation on an image.
/// </summary> /// </summary>
public sealed class CropProcessor : IImageProcessor public sealed class CropProcessor : CloningImageProcessor
{ {
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="CropProcessor"/> class. /// Initializes a new instance of the <see cref="CropProcessor"/> class.
@ -23,6 +22,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
new Rectangle(Point.Empty, sourceSize).Contains(cropRectangle), new Rectangle(Point.Empty, sourceSize).Contains(cropRectangle),
nameof(cropRectangle), nameof(cropRectangle),
"Crop rectangle should be smaller than the source bounds."); "Crop rectangle should be smaller than the source bounds.");
this.CropRectangle = cropRectangle; this.CropRectangle = cropRectangle;
} }
@ -32,10 +32,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
public Rectangle CropRectangle { get; } public Rectangle CropRectangle { get; }
/// <inheritdoc /> /// <inheritdoc />
public IImageProcessor<TPixel> CreatePixelSpecificProcessor<TPixel>(Image<TPixel> source, Rectangle sourceRectangle) public override ICloningImageProcessor<TPixel> CreatePixelSpecificProcessor<TPixel>(Image<TPixel> source, Rectangle sourceRectangle)
where TPixel : struct, IPixel<TPixel> => new CropProcessor<TPixel>(this, source, sourceRectangle);
{
return new CropProcessor<TPixel>(this, source, sourceRectangle);
}
} }
} }

11
src/ImageSharp/Processing/Processors/Transforms/ProjectiveTransformProcessor.cs

@ -2,8 +2,6 @@
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using System.Numerics; using System.Numerics;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.Primitives; using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing.Processors.Transforms namespace SixLabors.ImageSharp.Processing.Processors.Transforms
@ -11,7 +9,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
/// <summary> /// <summary>
/// Defines a projective transformation applicable to an <see cref="Image"/>. /// Defines a projective transformation applicable to an <see cref="Image"/>.
/// </summary> /// </summary>
public sealed class ProjectiveTransformProcessor : IImageProcessor public sealed class ProjectiveTransformProcessor : CloningImageProcessor
{ {
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="ProjectiveTransformProcessor"/> class. /// Initializes a new instance of the <see cref="ProjectiveTransformProcessor"/> class.
@ -43,10 +41,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
public Size TargetDimensions { get; } public Size TargetDimensions { get; }
/// <inheritdoc /> /// <inheritdoc />
public IImageProcessor<TPixel> CreatePixelSpecificProcessor<TPixel>(Image<TPixel> source, Rectangle sourceRectangle) public override ICloningImageProcessor<TPixel> CreatePixelSpecificProcessor<TPixel>(Image<TPixel> source, Rectangle sourceRectangle)
where TPixel : struct, IPixel<TPixel> => new ProjectiveTransformProcessor<TPixel>(this, source, sourceRectangle);
{
return new ProjectiveTransformProcessor<TPixel>(this, source, sourceRectangle);
}
} }
} }

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

@ -1,9 +1,6 @@
// Copyright (c) Six Labors and contributors. // Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using System;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.Primitives; using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing.Processors.Transforms namespace SixLabors.ImageSharp.Processing.Processors.Transforms
@ -11,7 +8,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
/// <summary> /// <summary>
/// Defines an image resizing operation with the given <see cref="IResampler"/> and dimensional parameters. /// Defines an image resizing operation with the given <see cref="IResampler"/> and dimensional parameters.
/// </summary> /// </summary>
public class ResizeProcessor : IImageProcessor public class ResizeProcessor : CloningImageProcessor
{ {
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="ResizeProcessor"/> class. /// Initializes a new instance of the <see cref="ResizeProcessor"/> class.
@ -58,8 +55,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
public bool Compand { get; } public bool Compand { get; }
/// <inheritdoc /> /// <inheritdoc />
public IImageProcessor<TPixel> CreatePixelSpecificProcessor<TPixel>(Image<TPixel> source, Rectangle sourceRectangle) public override ICloningImageProcessor<TPixel> CreatePixelSpecificProcessor<TPixel>(Image<TPixel> source, Rectangle sourceRectangle)
where TPixel : struct, IPixel<TPixel>
=> new ResizeProcessor<TPixel>(this, source, sourceRectangle); => new ResizeProcessor<TPixel>(this, source, sourceRectangle);
} }
} }

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

@ -2,7 +2,6 @@
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using System.Numerics; using System.Numerics;
using SixLabors.Primitives; using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing.Processors.Transforms namespace SixLabors.ImageSharp.Processing.Processors.Transforms
@ -47,9 +46,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
public float Degrees { get; } public float Degrees { get; }
/// <inheritdoc /> /// <inheritdoc />
public override IImageProcessor<TPixel> CreatePixelSpecificProcessor<TPixel>(Image<TPixel> source, Rectangle sourceRectangle) public override ICloningImageProcessor<TPixel> CreatePixelSpecificProcessor<TPixel>(Image<TPixel> source, Rectangle sourceRectangle)
{ => new RotateProcessor<TPixel>(this, source, sourceRectangle);
return new RotateProcessor<TPixel>(this, source, sourceRectangle);
}
} }
} }

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

@ -1,8 +1,7 @@
// Copyright (c) Six Labors and contributors. // Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using System.Numerics; using System.Numerics;
using SixLabors.Primitives; using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing.Processors.Transforms namespace SixLabors.ImageSharp.Processing.Processors.Transforms
@ -56,4 +55,4 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
/// </summary> /// </summary>
public float DegreesY { get; } public float DegreesY { get; }
} }
} }

59
tests/ImageSharp.Tests/Processing/ImageProcessingContextTests.cs

@ -21,6 +21,8 @@ namespace SixLabors.ImageSharp.Tests.Processing
private readonly Mock<IImageProcessor> processorDefinition; private readonly Mock<IImageProcessor> processorDefinition;
private readonly Mock<CloningImageProcessor> cloningProcessorDefinition;
private readonly Mock<IImageProcessor<Rgba32>> regularProcessorImpl; private readonly Mock<IImageProcessor<Rgba32>> regularProcessorImpl;
private readonly Mock<ICloningImageProcessor<Rgba32>> cloningProcessorImpl; private readonly Mock<ICloningImageProcessor<Rgba32>> cloningProcessorImpl;
@ -30,18 +32,20 @@ namespace SixLabors.ImageSharp.Tests.Processing
public ImageProcessingContextTests() public ImageProcessingContextTests()
{ {
this.processorDefinition = new Mock<IImageProcessor>(); this.processorDefinition = new Mock<IImageProcessor>();
this.cloningProcessorDefinition = new Mock<CloningImageProcessor>();
this.regularProcessorImpl = new Mock<IImageProcessor<Rgba32>>(); this.regularProcessorImpl = new Mock<IImageProcessor<Rgba32>>();
this.cloningProcessorImpl = new Mock<ICloningImageProcessor<Rgba32>>(); this.cloningProcessorImpl = new Mock<ICloningImageProcessor<Rgba32>>();
} }
// bool throwException, bool useBounds // bool throwException, bool useBounds
public static readonly TheoryData<bool, bool> ProcessorTestData = new TheoryData<bool, bool>() public static readonly TheoryData<bool, bool> ProcessorTestData = new TheoryData<bool, bool>()
{ {
{ false, false }, { false, false },
{ false, true }, { false, true },
{ true, false }, { true, false },
{ true, true } { true, true }
}; };
[Theory] [Theory]
[MemberData(nameof(ProcessorTestData))] [MemberData(nameof(ProcessorTestData))]
public void Mutate_RegularProcessor(bool throwException, bool useBounds) public void Mutate_RegularProcessor(bool throwException, bool useBounds)
@ -57,7 +61,7 @@ namespace SixLabors.ImageSharp.Tests.Processing
this.MutateApply(useBounds); this.MutateApply(useBounds);
} }
this.regularProcessorImpl.Verify(p => p.Apply(), Times.Once()); this.regularProcessorImpl.Verify(p => p.Execute(), Times.Once());
this.regularProcessorImpl.Verify(p => p.Dispose(), Times.Once()); this.regularProcessorImpl.Verify(p => p.Dispose(), Times.Once());
} }
@ -69,16 +73,15 @@ namespace SixLabors.ImageSharp.Tests.Processing
if (throwException) if (throwException)
{ {
Assert.Throws<ImageProcessingException>(() => this.CloneApply(useBounds)); Assert.Throws<ImageProcessingException>(() => this.CloneRegularApply(useBounds));
} }
else else
{ {
this.CloneApply(useBounds); this.CloneRegularApply(useBounds);
} }
// TODO: This should be Times.Once(). See comments in DefaultImageProcessingContext<T>.ApplyProcessor() this.regularProcessorImpl.Verify(p => p.Execute(), Times.Once);
this.regularProcessorImpl.Verify(p => p.Apply(), Times.AtLeast(1)); this.regularProcessorImpl.Verify(p => p.Dispose(), Times.Once);
this.regularProcessorImpl.Verify(p => p.Dispose(), Times.AtLeast(1));
} }
[Theory] [Theory]
@ -96,7 +99,7 @@ namespace SixLabors.ImageSharp.Tests.Processing
this.MutateApply(useBounds); this.MutateApply(useBounds);
} }
this.cloningProcessorImpl.Verify(p => p.Apply(), Times.Once()); this.cloningProcessorImpl.Verify(p => p.Execute(), Times.Once());
this.cloningProcessorImpl.Verify(p => p.Dispose(), Times.Once()); this.cloningProcessorImpl.Verify(p => p.Dispose(), Times.Once());
} }
@ -108,14 +111,14 @@ namespace SixLabors.ImageSharp.Tests.Processing
if (throwException) if (throwException)
{ {
Assert.Throws<ImageProcessingException>(() => this.CloneApply(useBounds)); Assert.Throws<ImageProcessingException>(() => this.CloneCloneApply(useBounds));
} }
else else
{ {
this.CloneApply(useBounds); this.CloneCloneApply(useBounds);
} }
this.cloningProcessorImpl.Verify(p => p.CloneAndApply(), Times.Once()); this.cloningProcessorImpl.Verify(p => p.CloneAndExecute(), Times.Once());
this.cloningProcessorImpl.Verify(p => p.Dispose(), Times.Once()); this.cloningProcessorImpl.Verify(p => p.Dispose(), Times.Once());
} }
@ -131,7 +134,7 @@ namespace SixLabors.ImageSharp.Tests.Processing
} }
} }
private void CloneApply(bool useBounds) private void CloneRegularApply(bool useBounds)
{ {
if (useBounds) if (useBounds)
{ {
@ -143,11 +146,23 @@ namespace SixLabors.ImageSharp.Tests.Processing
} }
} }
private void CloneCloneApply(bool useBounds)
{
if (useBounds)
{
this.image.Clone(c => c.ApplyProcessor(this.cloningProcessorDefinition.Object, Bounds)).Dispose();
}
else
{
this.image.Clone(c => c.ApplyProcessor(this.cloningProcessorDefinition.Object)).Dispose();
}
}
private void SetupRegularProcessor(bool throwsException) private void SetupRegularProcessor(bool throwsException)
{ {
if (throwsException) if (throwsException)
{ {
this.regularProcessorImpl.Setup(p => p.Apply()).Throws(new ImageProcessingException("Test")); this.regularProcessorImpl.Setup(p => p.Execute()).Throws(new ImageProcessingException("Test"));
} }
this.processorDefinition this.processorDefinition
@ -159,13 +174,17 @@ namespace SixLabors.ImageSharp.Tests.Processing
{ {
if (throwsException) if (throwsException)
{ {
this.cloningProcessorImpl.Setup(p => p.Apply()).Throws(new ImageProcessingException("Test")); this.cloningProcessorImpl.Setup(p => p.Execute()).Throws(new ImageProcessingException("Test"));
this.cloningProcessorImpl.Setup(p => p.CloneAndApply()).Throws(new ImageProcessingException("Test")); this.cloningProcessorImpl.Setup(p => p.CloneAndExecute()).Throws(new ImageProcessingException("Test"));
} }
this.processorDefinition this.processorDefinition
.Setup(p => p.CreatePixelSpecificProcessor(It.IsAny<Image<Rgba32>>(), It.IsAny<Rectangle>())) .Setup(p => p.CreatePixelSpecificProcessor(It.IsAny<Image<Rgba32>>(), It.IsAny<Rectangle>()))
.Returns(this.cloningProcessorImpl.Object); .Returns(this.cloningProcessorImpl.Object);
this.cloningProcessorDefinition
.Setup(p => p.CreatePixelSpecificProcessor(It.IsAny<Image<Rgba32>>(), It.IsAny<Rectangle>()))
.Returns(this.cloningProcessorImpl.Object);
} }
} }
} }

Loading…
Cancel
Save