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);
// 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)
{
throw new ImageProcessingException(
@ -102,14 +102,14 @@ namespace SixLabors.ImageSharp.Processing.Processors.Drawing
workingRect,
configuration,
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);
blender.Blend<TPixelFg>(configuration, background, background, foreground, this.Opacity);
}
});
Span<TPixelBg> background = source.GetPixelRowSpan(y).Slice(minX, width);
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.source = source;
// Mutate acts upon the source image only.
if (this.mutate)
{
this.destination = source;
@ -43,7 +45,8 @@ namespace SixLabors.ImageSharp.Processing
{
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();
}
@ -64,26 +67,25 @@ namespace SixLabors.ImageSharp.Processing
{
if (!this.mutate && this.destination is null)
{
// This will only work if the first processor applied is the cloning one thus
// realistically for this optimization to work the resize must the first processor
// applied any only up processors will take the double data path.
using (IImageProcessor<TPixel> specificProcessor = processor.CreatePixelSpecificProcessor(this.source, rectangle))
// When cloning an image we can optimize the processing pipeline by avoiding an unnecessary
// interim clone if the first processor in the pipeline is a cloning processor.
if (processor is CloningImageProcessor cloningImageProcessor)
{
// TODO: if 'specificProcessor' is not an ICloningImageProcessor<TPixel> we are unnecessarily disposing and recreating it.
// This should be solved in a future refactor.
if (specificProcessor is ICloningImageProcessor<TPixel> cloningImageProcessor)
using (ICloningImageProcessor<TPixel> pixelProcessor = cloningImageProcessor.CreatePixelSpecificProcessor(this.source, rectangle))
{
this.destination = cloningImageProcessor.CloneAndApply();
this.destination = pixelProcessor.CloneAndExecute();
return this;
}
}
// Not a cloning processor? We need to create a clone to operate on.
this.destination = this.source.Clone();
}
// Standard processing pipeline.
using (IImageProcessor<TPixel> specificProcessor = processor.CreatePixelSpecificProcessor(this.destination, rectangle))
{
specificProcessor.Apply();
specificProcessor.Execute();
}
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
{
/// <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>
/// <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>
{
private bool isDisposed;
@ -45,16 +47,12 @@ namespace SixLabors.ImageSharp.Processing.Processors
protected Configuration Configuration { get; }
/// <inheritdoc/>
public Image<TPixel> CloneAndApply()
public Image<TPixel> CloneAndExecute()
{
try
{
Image<TPixel> clone = this.CreateDestination();
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.");
}
this.CheckFrameCount(this.Source, clone);
Configuration configuration = this.Source.GetConfiguration();
this.BeforeImageApply(clone);
@ -86,17 +84,24 @@ namespace SixLabors.ImageSharp.Processing.Processors
}
/// <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
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.");
}
clone = this.CloneAndExecute();
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;
}
}
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.
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.Primitives;
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.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
internal interface ICloningImageProcessor<TPixel> : IImageProcessor<TPixel>
public interface ICloningImageProcessor<TPixel> : IImageProcessor<TPixel>
where TPixel : struct, IPixel<TPixel>
{
/// <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>
/// <exception cref="System.ArgumentNullException">
/// The target <see cref="Image{TPixel}"/> is null.
/// </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();
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
Image<TPixel> CloneAndExecute();
}
}

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

@ -15,7 +15,7 @@ namespace SixLabors.ImageSharp.Processing.Processors
public interface IImageProcessor
{
/// <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}"/>.
/// </summary>
/// <typeparam name="TPixel">The pixel type.</typeparam>

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

@ -3,7 +3,6 @@
using System;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing.Processors
{
@ -15,14 +14,8 @@ namespace SixLabors.ImageSharp.Processing.Processors
where TPixel : struct, IPixel<TPixel>
{
/// <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>
/// <exception cref="ArgumentNullException">
/// 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();
void Execute();
}
}

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))
{
processorImpl.Apply();
processorImpl.Execute();
}
}
}

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

@ -9,10 +9,11 @@ using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing.Processors
{
/// <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>
/// <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>
{
private bool isDisposed;
@ -45,7 +46,7 @@ namespace SixLabors.ImageSharp.Processing.Processors
protected Configuration Configuration { get; }
/// <inheritdoc/>
public void Apply()
public void Execute()
{
try
{
@ -71,7 +72,7 @@ namespace SixLabors.ImageSharp.Processing.Processors
}
/// <summary>
/// Applies the processor to just a single ImageBase.
/// Applies the processor to a single image frame.
/// </summary>
/// <param name="source">the source image.</param>
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.
using System.Numerics;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing.Processors.Transforms
@ -11,7 +9,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
/// <summary>
/// Defines an affine transformation applicable on an <see cref="Image"/>.
/// </summary>
public class AffineTransformProcessor : IImageProcessor
public class AffineTransformProcessor : CloningImageProcessor
{
/// <summary>
/// Initializes a new instance of the <see cref="AffineTransformProcessor"/> class.
@ -42,11 +40,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
/// </summary>
public Size TargetDimensions { get; }
/// <inheritdoc />
public virtual IImageProcessor<TPixel> CreatePixelSpecificProcessor<TPixel>(Image<TPixel> source, Rectangle sourceRectangle)
where TPixel : struct, IPixel<TPixel>
{
return new AffineTransformProcessor<TPixel>(this, source, sourceRectangle);
}
/// <inheritdoc/>
public override ICloningImageProcessor<TPixel> CreatePixelSpecificProcessor<TPixel>(Image<TPixel> source, Rectangle sourceRectangle)
=> new AffineTransformProcessor<TPixel>(this, source, sourceRectangle);
}
}

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

@ -1,7 +1,6 @@
// 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.Transforms
@ -9,7 +8,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
/// <summary>
/// Defines a crop operation on an image.
/// </summary>
public sealed class CropProcessor : IImageProcessor
public sealed class CropProcessor : CloningImageProcessor
{
/// <summary>
/// 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),
nameof(cropRectangle),
"Crop rectangle should be smaller than the source bounds.");
this.CropRectangle = cropRectangle;
}
@ -32,10 +32,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
public Rectangle CropRectangle { get; }
/// <inheritdoc />
public IImageProcessor<TPixel> CreatePixelSpecificProcessor<TPixel>(Image<TPixel> source, Rectangle sourceRectangle)
where TPixel : struct, IPixel<TPixel>
{
return new CropProcessor<TPixel>(this, source, sourceRectangle);
}
public override ICloningImageProcessor<TPixel> CreatePixelSpecificProcessor<TPixel>(Image<TPixel> source, Rectangle sourceRectangle)
=> 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.
using System.Numerics;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing.Processors.Transforms
@ -11,7 +9,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
/// <summary>
/// Defines a projective transformation applicable to an <see cref="Image"/>.
/// </summary>
public sealed class ProjectiveTransformProcessor : IImageProcessor
public sealed class ProjectiveTransformProcessor : CloningImageProcessor
{
/// <summary>
/// Initializes a new instance of the <see cref="ProjectiveTransformProcessor"/> class.
@ -43,10 +41,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
public Size TargetDimensions { get; }
/// <inheritdoc />
public IImageProcessor<TPixel> CreatePixelSpecificProcessor<TPixel>(Image<TPixel> source, Rectangle sourceRectangle)
where TPixel : struct, IPixel<TPixel>
{
return new ProjectiveTransformProcessor<TPixel>(this, source, sourceRectangle);
}
public override ICloningImageProcessor<TPixel> CreatePixelSpecificProcessor<TPixel>(Image<TPixel> source, Rectangle sourceRectangle)
=> 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.
// Licensed under the Apache License, Version 2.0.
using System;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing.Processors.Transforms
@ -11,7 +8,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
/// <summary>
/// Defines an image resizing operation with the given <see cref="IResampler"/> and dimensional parameters.
/// </summary>
public class ResizeProcessor : IImageProcessor
public class ResizeProcessor : CloningImageProcessor
{
/// <summary>
/// Initializes a new instance of the <see cref="ResizeProcessor"/> class.
@ -58,8 +55,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
public bool Compand { get; }
/// <inheritdoc />
public IImageProcessor<TPixel> CreatePixelSpecificProcessor<TPixel>(Image<TPixel> source, Rectangle sourceRectangle)
where TPixel : struct, IPixel<TPixel>
public override ICloningImageProcessor<TPixel> CreatePixelSpecificProcessor<TPixel>(Image<TPixel> source, Rectangle 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.
using System.Numerics;
using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing.Processors.Transforms
@ -47,9 +46,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
public float Degrees { get; }
/// <inheritdoc />
public override IImageProcessor<TPixel> CreatePixelSpecificProcessor<TPixel>(Image<TPixel> source, Rectangle sourceRectangle)
{
return new RotateProcessor<TPixel>(this, source, sourceRectangle);
}
public override ICloningImageProcessor<TPixel> CreatePixelSpecificProcessor<TPixel>(Image<TPixel> source, Rectangle sourceRectangle)
=> 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.
using System.Numerics;
using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing.Processors.Transforms
@ -56,4 +55,4 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
/// </summary>
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<CloningImageProcessor> cloningProcessorDefinition;
private readonly Mock<IImageProcessor<Rgba32>> regularProcessorImpl;
private readonly Mock<ICloningImageProcessor<Rgba32>> cloningProcessorImpl;
@ -30,18 +32,20 @@ namespace SixLabors.ImageSharp.Tests.Processing
public ImageProcessingContextTests()
{
this.processorDefinition = new Mock<IImageProcessor>();
this.cloningProcessorDefinition = new Mock<CloningImageProcessor>();
this.regularProcessorImpl = new Mock<IImageProcessor<Rgba32>>();
this.cloningProcessorImpl = new Mock<ICloningImageProcessor<Rgba32>>();
}
// bool throwException, bool useBounds
public static readonly TheoryData<bool, bool> ProcessorTestData = new TheoryData<bool, bool>()
{
{ false, false },
{ false, true },
{ true, false },
{ true, true }
};
{
{ false, false },
{ false, true },
{ true, false },
{ true, true }
};
[Theory]
[MemberData(nameof(ProcessorTestData))]
public void Mutate_RegularProcessor(bool throwException, bool useBounds)
@ -57,7 +61,7 @@ namespace SixLabors.ImageSharp.Tests.Processing
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());
}
@ -69,16 +73,15 @@ namespace SixLabors.ImageSharp.Tests.Processing
if (throwException)
{
Assert.Throws<ImageProcessingException>(() => this.CloneApply(useBounds));
Assert.Throws<ImageProcessingException>(() => this.CloneRegularApply(useBounds));
}
else
{
this.CloneApply(useBounds);
this.CloneRegularApply(useBounds);
}
// TODO: This should be Times.Once(). See comments in DefaultImageProcessingContext<T>.ApplyProcessor()
this.regularProcessorImpl.Verify(p => p.Apply(), Times.AtLeast(1));
this.regularProcessorImpl.Verify(p => p.Dispose(), Times.AtLeast(1));
this.regularProcessorImpl.Verify(p => p.Execute(), Times.Once);
this.regularProcessorImpl.Verify(p => p.Dispose(), Times.Once);
}
[Theory]
@ -96,7 +99,7 @@ namespace SixLabors.ImageSharp.Tests.Processing
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());
}
@ -108,14 +111,14 @@ namespace SixLabors.ImageSharp.Tests.Processing
if (throwException)
{
Assert.Throws<ImageProcessingException>(() => this.CloneApply(useBounds));
Assert.Throws<ImageProcessingException>(() => this.CloneCloneApply(useBounds));
}
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());
}
@ -131,7 +134,7 @@ namespace SixLabors.ImageSharp.Tests.Processing
}
}
private void CloneApply(bool useBounds)
private void CloneRegularApply(bool 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)
{
if (throwsException)
{
this.regularProcessorImpl.Setup(p => p.Apply()).Throws(new ImageProcessingException("Test"));
this.regularProcessorImpl.Setup(p => p.Execute()).Throws(new ImageProcessingException("Test"));
}
this.processorDefinition
@ -159,13 +174,17 @@ namespace SixLabors.ImageSharp.Tests.Processing
{
if (throwsException)
{
this.cloningProcessorImpl.Setup(p => p.Apply()).Throws(new ImageProcessingException("Test"));
this.cloningProcessorImpl.Setup(p => p.CloneAndApply()).Throws(new ImageProcessingException("Test"));
this.cloningProcessorImpl.Setup(p => p.Execute()).Throws(new ImageProcessingException("Test"));
this.cloningProcessorImpl.Setup(p => p.CloneAndExecute()).Throws(new ImageProcessingException("Test"));
}
this.processorDefinition
.Setup(p => p.CreatePixelSpecificProcessor(It.IsAny<Image<Rgba32>>(), It.IsAny<Rectangle>()))
.Returns(this.cloningProcessorImpl.Object);
this.cloningProcessorDefinition
.Setup(p => p.CreatePixelSpecificProcessor(It.IsAny<Image<Rgba32>>(), It.IsAny<Rectangle>()))
.Returns(this.cloningProcessorImpl.Object);
}
}
}

Loading…
Cancel
Save