Browse Source

Cleanup + Rename Run to Apply

af/merge-core
James Jackson-South 9 years ago
parent
commit
7d4bc67d9f
  1. 20
      samples/AvatarWithRoundedCorner/Program.cs
  2. 4
      src/ImageSharp/ApplyProcessors.cs
  3. 20
      src/ImageSharp/DefaultInternalImageProcessorContext.cs
  4. 5
      src/ImageSharp/IImageProcessingContextFactory.cs
  5. 12
      src/ImageSharp/IImageProcessingContext{TPixel}.cs
  6. 6
      src/ImageSharp/Processing/Delegate.cs
  7. 5
      src/ImageSharp/Processing/Processors/DelegateProcessor.cs
  8. 10
      src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs
  9. 51
      src/ImageSharp/Processing/Transforms/Resize.cs
  10. 4
      src/ImageSharp/Quantizers/Quantize.cs
  11. 2
      tests/ImageSharp.Tests/Processing/DelegateTest.cs

20
samples/AvatarWithRoundedCorner/Program.cs

@ -42,13 +42,13 @@ namespace AvatarWithRoundedCorner
{ {
Size = size, Size = size,
Mode = ImageSharp.Processing.ResizeMode.Crop Mode = ImageSharp.Processing.ResizeMode.Crop
}).Run(i => ApplyRoundedCourners(i, cornerRadius)); }).Apply(i => ApplyRoundedCorners(i, cornerRadius));
} }
// the combination of `IImageOperations.Run()` + this could be replaced with an `IImageProcessor` // the combination of `IImageOperations.Run()` + this could be replaced with an `IImageProcessor`
public static void ApplyRoundedCourners(Image<Rgba32> img, float cornerRadius) public static void ApplyRoundedCorners(Image<Rgba32> img, float cornerRadius)
{ {
var corners = BuildCorners(img.Width, img.Height, cornerRadius); IPathCollection corners = BuildCorners(img.Width, img.Height, cornerRadius);
// mutating in here as we already have a cloned original // mutating in here as we already have a cloned original
img.Mutate(x => x.Fill(Rgba32.Transparent, corners, new GraphicsOptions(true) img.Mutate(x => x.Fill(Rgba32.Transparent, corners, new GraphicsOptions(true)
@ -60,22 +60,22 @@ namespace AvatarWithRoundedCorner
public static IPathCollection BuildCorners(int imageWidth, int imageHeight, float cornerRadius) public static IPathCollection BuildCorners(int imageWidth, int imageHeight, float cornerRadius)
{ {
// first create a square // first create a square
var rect = new SixLabors.Shapes.RectangularePolygon(-0.5f, -0.5f, cornerRadius, cornerRadius); var rect = new RectangularePolygon(-0.5f, -0.5f, cornerRadius, cornerRadius);
// then cut out of the square a circle so we are left with a corner // then cut out of the square a circle so we are left with a corner
var cornerToptLeft = rect.Clip(new SixLabors.Shapes.EllipsePolygon(cornerRadius - 0.5f, cornerRadius - 0.5f, cornerRadius)); IPath cornerToptLeft = rect.Clip(new EllipsePolygon(cornerRadius - 0.5f, cornerRadius - 0.5f, cornerRadius));
// corner is now a corner shape positions top left // corner is now a corner shape positions top left
//lets make 3 more positioned correctly, we cando that by translating the orgional artound the center of the image //lets make 3 more positioned correctly, we can do that by translating the orgional artound the center of the image
var center = new Vector2(imageWidth / 2, imageHeight / 2); var center = new Vector2(imageWidth / 2F, imageHeight / 2F);
float rightPos = imageWidth - cornerToptLeft.Bounds.Width + 1; float rightPos = imageWidth - cornerToptLeft.Bounds.Width + 1;
float bottomPos = imageHeight - cornerToptLeft.Bounds.Height + 1; float bottomPos = imageHeight - cornerToptLeft.Bounds.Height + 1;
// move it across the widthof the image - the width of the shape // move it across the widthof the image - the width of the shape
var cornerTopRight = cornerToptLeft.RotateDegree(90).Translate(rightPos, 0); IPath cornerTopRight = cornerToptLeft.RotateDegree(90).Translate(rightPos, 0);
var cornerBottomLeft = cornerToptLeft.RotateDegree(-90).Translate(0, bottomPos); IPath cornerBottomLeft = cornerToptLeft.RotateDegree(-90).Translate(0, bottomPos);
var cornerBottomRight = cornerToptLeft.RotateDegree(180).Translate(rightPos, bottomPos); IPath cornerBottomRight = cornerToptLeft.RotateDegree(180).Translate(rightPos, bottomPos);
return new PathCollection(cornerToptLeft, cornerBottomLeft, cornerTopRight, cornerBottomRight); return new PathCollection(cornerToptLeft, cornerBottomLeft, cornerTopRight, cornerBottomRight);
} }

4
src/ImageSharp/ApplyProcessors.cs

@ -92,7 +92,7 @@ namespace ImageSharp
/// <typeparam name="TPixel">The pixel format.</typeparam> /// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image to rotate, flip, or both.</param> /// <param name="source">The image to rotate, flip, or both.</param>
/// <param name="operations">The operations to perform on the source.</param> /// <param name="operations">The operations to perform on the source.</param>
/// <returns>returns the current optinoatins class to allow chaining of oprations.</returns> /// <returns>returns the current operations class to allow chaining of operations.</returns>
public static IImageProcessingContext<TPixel> ApplyProcessors<TPixel>(this IImageProcessingContext<TPixel> source, params IImageProcessor<TPixel>[] operations) public static IImageProcessingContext<TPixel> ApplyProcessors<TPixel>(this IImageProcessingContext<TPixel> source, params IImageProcessor<TPixel>[] operations)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
@ -104,4 +104,4 @@ namespace ImageSharp
return source; return source;
} }
} }
} }

20
src/ImageSharp/DefaultInternalImageProcessorContext.cs

@ -5,14 +5,12 @@
namespace ImageSharp namespace ImageSharp
{ {
using System;
using System.Collections.Generic;
using ImageSharp.PixelFormats; using ImageSharp.PixelFormats;
using ImageSharp.Processing; using ImageSharp.Processing;
using SixLabors.Primitives; using SixLabors.Primitives;
/// <summary> /// <summary>
/// The static collection of all the default image formats /// Performs processor application operations on the source image
/// </summary> /// </summary>
/// <typeparam name="TPixel">The pixel format</typeparam> /// <typeparam name="TPixel">The pixel format</typeparam>
internal class DefaultInternalImageProcessorContext<TPixel> : IInternalImageProcessingContext<TPixel> internal class DefaultInternalImageProcessorContext<TPixel> : IInternalImageProcessingContext<TPixel>
@ -42,7 +40,7 @@ namespace ImageSharp
{ {
if (!this.mutate && this.destination == null) if (!this.mutate && this.destination == null)
{ {
// ensure we have cloned it if we are not mutating as we might have failed to register any Processors // Ensure we have cloned it if we are not mutating as we might have failed to register any Processors
this.destination = this.source.Clone(); this.destination = this.source.Clone();
} }
@ -54,19 +52,17 @@ namespace ImageSharp
{ {
if (!this.mutate && this.destination == null) if (!this.mutate && this.destination == null)
{ {
// this will only work if the first processor applied is the cloning one thus // This will only work if the first processor applied is the cloning one thus
// realistically for this optermissation to work the resize must the first processor // realistically for this optermissation to work the resize must the first processor
// applied any only up processors will take the douple data path. // applied any only up processors will take the douple data path.
if (processor is ICloningImageProcessor<TPixel>) var cloningImageProcessor = processor as ICloningImageProcessor<TPixel>;
if (cloningImageProcessor != null)
{ {
var cloningProcessor = (ICloningImageProcessor<TPixel>)processor; this.destination = cloningImageProcessor.CloneAndApply(this.source, rectangle);
this.destination = cloningProcessor.CloneAndApply(this.source, rectangle);
return this; return this;
} }
else
{ this.destination = this.source.Clone();
this.destination = this.source.Clone();
}
} }
processor.Apply(this.destination, rectangle); processor.Apply(this.destination, rectangle);

5
src/ImageSharp/IImageProcessingContextFactory.cs

@ -5,16 +5,15 @@
namespace ImageSharp namespace ImageSharp
{ {
using System;
using ImageSharp.PixelFormats; using ImageSharp.PixelFormats;
/// <summary> /// <summary>
/// Represents an interface that will create IImageOperations /// Represents an interface that will create IInternalImageProcessingContext instances
/// </summary> /// </summary>
internal interface IImageProcessingContextFactory internal interface IImageProcessingContextFactory
{ {
/// <summary> /// <summary>
/// Called during Mutate operations to generate the imageoperations provider. /// Called during Mutate operations to generate the image operations provider.
/// </summary> /// </summary>
/// <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>

12
src/ImageSharp/IImageProcessingContext{TPixel}.cs

@ -5,8 +5,6 @@
namespace ImageSharp namespace ImageSharp
{ {
using System;
using ImageSharp.Formats;
using ImageSharp.PixelFormats; using ImageSharp.PixelFormats;
using ImageSharp.Processing; using ImageSharp.Processing;
using SixLabors.Primitives; using SixLabors.Primitives;
@ -19,18 +17,18 @@ namespace ImageSharp
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
/// <summary> /// <summary>
/// Adds the processor to the current setr of image operations to be applied. /// Adds the processor to the current set of image operations to be applied.
/// </summary> /// </summary>
/// <param name="processor">The processor to apply</param> /// <param name="processor">The processor to apply</param>
/// <param name="rectangle">The area to apply it to</param> /// <param name="rectangle">The area to apply it to</param>
/// <returns>returns the current optinoatins class to allow chaining of oprations.</returns> /// <returns>The current operations class to allow chaining of operations.</returns>
IImageProcessingContext<TPixel> ApplyProcessor(IImageProcessor<TPixel> processor, Rectangle rectangle); IImageProcessingContext<TPixel> ApplyProcessor(IImageProcessor<TPixel> processor, Rectangle rectangle);
/// <summary> /// <summary>
/// Adds the processor to the current setr of image operations to be applied. /// Adds the processor to the current set of image operations to be applied.
/// </summary> /// </summary>
/// <param name="processor">The processor to apply</param> /// <param name="processor">The processor to apply</param>
/// <returns>returns the current optinoatins class to allow chaining of oprations.</returns> /// <returns>The current operations class to allow chaining of operations.</returns>
IImageProcessingContext<TPixel> ApplyProcessor(IImageProcessor<TPixel> processor); IImageProcessingContext<TPixel> ApplyProcessor(IImageProcessor<TPixel> processor);
} }
@ -44,7 +42,7 @@ namespace ImageSharp
/// <summary> /// <summary>
/// Adds the processors to the current image /// Adds the processors to the current image
/// </summary> /// </summary>
/// <returns>returns the current image or a new image depending on withere this is alloed to mutate the source image.</returns> /// <returns>The current image or a new image depending on withere this is alloed to mutate the source image.</returns>
Image<TPixel> Apply(); Image<TPixel> Apply();
} }
} }

6
src/ImageSharp/Processing/Delegate.cs

@ -17,13 +17,13 @@ namespace ImageSharp
public static partial class ImageExtensions public static partial class ImageExtensions
{ {
/// <summary> /// <summary>
/// Queues up a simple operation that provides access to the mutatable image. /// Queues up an operation that provides access to the mutatable image.
/// </summary> /// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam> /// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image to rotate, flip, or both.</param> /// <param name="source">The image to rotate, flip, or both.</param>
/// <param name="operation">The operations to perform on the source.</param> /// <param name="operation">The operations to perform on the source.</param>
/// <returns>returns the current optinoatins class to allow chaining of oprations.</returns> /// <returns>returns the current operations class to allow chaining of operations.</returns>
public static IImageProcessingContext<TPixel> Run<TPixel>(this IImageProcessingContext<TPixel> source, Action<Image<TPixel>> operation) public static IImageProcessingContext<TPixel> Apply<TPixel>(this IImageProcessingContext<TPixel> source, Action<Image<TPixel>> operation)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
=> source.ApplyProcessor(new DelegateProcessor<TPixel>(operation)); => source.ApplyProcessor(new DelegateProcessor<TPixel>(operation));
} }

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

@ -6,7 +6,6 @@
namespace ImageSharp.Processing namespace ImageSharp.Processing
{ {
using System; using System;
using System.Threading.Tasks;
using ImageSharp.PixelFormats; using ImageSharp.PixelFormats;
using SixLabors.Primitives; using SixLabors.Primitives;
@ -37,13 +36,13 @@ namespace ImageSharp.Processing
/// <inheritdoc/> /// <inheritdoc/>
protected override void BeforeImageApply(Image<TPixel> source, Rectangle sourceRectangle) protected override void BeforeImageApply(Image<TPixel> source, Rectangle sourceRectangle)
{ {
this.action?.Invoke((Image<TPixel>)source); this.action?.Invoke(source);
} }
/// <inheritdoc/> /// <inheritdoc/>
protected override void OnApply(ImageBase<TPixel> source, Rectangle sourceRectangle) protected override void OnApply(ImageBase<TPixel> source, Rectangle sourceRectangle)
{ {
// no op, we did all we wanted to do inside BeforeImageApply // NOP, we did all we wanted to do inside BeforeImageApply
} }
} }
} }

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

@ -48,14 +48,13 @@ namespace ImageSharp.Processing.Processors
/// <inheritdoc/> /// <inheritdoc/>
protected override Image<TPixel> CreateDestination(Image<TPixel> source, Rectangle sourceRectangle) protected override Image<TPixel> CreateDestination(Image<TPixel> source, Rectangle sourceRectangle)
{ {
// we will always be creating the clone even for mutate because thatsa the way this base processor works // We will always be creating the clone even for mutate because thats the way this base processor works
// ------------ // ------------
// for resize we know we are going to populate every pixel with fresh data and we want a different target size so // For resize we know we are going to populate every pixel with fresh data and we want a different target size so
// lets manually clone an empty set of images at the correct target and then have the base class processs them in. // let's manually clone an empty set of images at the correct target and then have the base class processs them in turn.
// turn.
var image = new Image<TPixel>(source.Configuration, this.Width, this.Height, source.MetaData.Clone()); var image = new Image<TPixel>(source.Configuration, this.Width, this.Height, source.MetaData.Clone());
// now 'clone' the ImageFrames // Now 'clone' the ImageFrames
foreach (ImageFrame<TPixel> sourceFrame in source.Frames) foreach (ImageFrame<TPixel> sourceFrame in source.Frames)
{ {
var targetFrame = new ImageFrame<TPixel>(sourceFrame.Configuration, this.Width, this.Height, sourceFrame.MetaData.Clone()); var targetFrame = new ImageFrame<TPixel>(sourceFrame.Configuration, this.Width, this.Height, sourceFrame.MetaData.Clone());
@ -120,7 +119,6 @@ namespace ImageSharp.Processing.Processors
// A 2-pass 1D algorithm appears to be faster than splitting a 1-pass 2D algorithm // A 2-pass 1D algorithm appears to be faster than splitting a 1-pass 2D algorithm
// First process the columns. Since we are not using multiple threads startY and endY // First process the columns. Since we are not using multiple threads startY and endY
// are the upper and lower bounds of the source rectangle. // are the upper and lower bounds of the source rectangle.
// TODO: Using a transposed variant of 'firstPassPixels' could eliminate the need for the WeightsWindow.ComputeWeightedColumnSum() method, and improve speed! // TODO: Using a transposed variant of 'firstPassPixels' could eliminate the need for the WeightsWindow.ComputeWeightedColumnSum() method, and improve speed!
using (var firstPassPixels = new Buffer2D<Vector4>(width, source.Height)) using (var firstPassPixels = new Buffer2D<Vector4>(width, source.Height))
{ {

51
src/ImageSharp/Processing/Transforms/Resize.cs

@ -27,10 +27,9 @@ namespace ImageSharp
public static IImageProcessingContext<TPixel> Resize<TPixel>(this IImageProcessingContext<TPixel> source, ResizeOptions options) public static IImageProcessingContext<TPixel> Resize<TPixel>(this IImageProcessingContext<TPixel> source, ResizeOptions options)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
return source.Run(img => return source.Apply(img =>
{ {
// cheat and bound through a run, inside here we should just be mutating, this reallt needs moving over to a processor // Cheat and bound through a run, inside here we should just be mutating, this really needs moving over to a processor
// Ensure size is populated across both dimensions. // Ensure size is populated across both dimensions.
if (options.Size.Width == 0 && options.Size.Height > 0) if (options.Size.Width == 0 && options.Size.Height > 0)
{ {
@ -162,26 +161,26 @@ namespace ImageSharp
public static IImageProcessingContext<TPixel> Resize<TPixel>(this IImageProcessingContext<TPixel> source, int width, int height, IResampler sampler, Rectangle sourceRectangle, Rectangle targetRectangle, bool compand) public static IImageProcessingContext<TPixel> Resize<TPixel>(this IImageProcessingContext<TPixel> source, int width, int height, IResampler sampler, Rectangle sourceRectangle, Rectangle targetRectangle, bool compand)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
return source.Run(img => return source.Apply(img =>
{ {
// todo : stop cheeting here and move this stuff into the processors itself // TODO : Stop cheating here and move this stuff into the processors itself
if (width == 0 && height > 0) if (width == 0 && height > 0)
{ {
width = (int)MathF.Round(img.Width * height / (float)img.Height); width = (int)MathF.Round(img.Width * height / (float)img.Height);
targetRectangle.Width = width; targetRectangle.Width = width;
} }
if (height == 0 && width > 0) if (height == 0 && width > 0)
{ {
height = (int)MathF.Round(img.Height * width / (float)img.Width); height = (int)MathF.Round(img.Height * width / (float)img.Width);
targetRectangle.Height = height; targetRectangle.Height = height;
} }
Guard.MustBeGreaterThan(width, 0, nameof(width)); Guard.MustBeGreaterThan(width, 0, nameof(width));
Guard.MustBeGreaterThan(height, 0, nameof(height)); Guard.MustBeGreaterThan(height, 0, nameof(height));
img.Mutate(x => x.ApplyProcessor(new ResizeProcessor<TPixel>(sampler, width, height, targetRectangle) { Compand = compand }, sourceRectangle)); img.Mutate(x => x.ApplyProcessor(new ResizeProcessor<TPixel>(sampler, width, height, targetRectangle) { Compand = compand }, sourceRectangle));
}); });
} }
/// <summary> /// <summary>
@ -202,9 +201,9 @@ namespace ImageSharp
public static IImageProcessingContext<TPixel> Resize<TPixel>(this IImageProcessingContext<TPixel> source, int width, int height, IResampler sampler, Rectangle targetRectangle, bool compand) public static IImageProcessingContext<TPixel> Resize<TPixel>(this IImageProcessingContext<TPixel> source, int width, int height, IResampler sampler, Rectangle targetRectangle, bool compand)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
return source.Run(img => return source.Apply(img =>
{ {
// todo : stop cheeting here and move this stuff into the processors itself // TODO : stop cheating here and move this stuff into the processors itself
if (width == 0 && height > 0) if (width == 0 && height > 0)
{ {
width = (int)MathF.Round(img.Width * height / (float)img.Height); width = (int)MathF.Round(img.Width * height / (float)img.Height);
@ -224,4 +223,4 @@ namespace ImageSharp
}); });
} }
} }
} }

4
src/ImageSharp/Quantizers/Quantize.cs

@ -57,13 +57,13 @@ namespace ImageSharp
public static IImageProcessingContext<TPixel> Quantize<TPixel>(this IImageProcessingContext<TPixel> source, IQuantizer<TPixel> quantizer, int maxColors) public static IImageProcessingContext<TPixel> Quantize<TPixel>(this IImageProcessingContext<TPixel> source, IQuantizer<TPixel> quantizer, int maxColors)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
return source.Run(img => return source.Apply(img =>
{ {
// TODO : move helper logic into the processor // TODO : move helper logic into the processor
QuantizedImage<TPixel> quantized = quantizer.Quantize(img, maxColors); QuantizedImage<TPixel> quantized = quantizer.Quantize(img, maxColors);
int palleteCount = quantized.Palette.Length - 1; int palleteCount = quantized.Palette.Length - 1;
using (PixelAccessor<TPixel> pixels = new PixelAccessor<TPixel>(quantized.Width, quantized.Height)) using (var pixels = new PixelAccessor<TPixel>(quantized.Width, quantized.Height))
{ {
Parallel.For( Parallel.For(
0, 0,

2
tests/ImageSharp.Tests/Processing/DelegateTest.cs

@ -16,7 +16,7 @@ namespace ImageSharp.Tests.Processing
public void Run_CreatedDelegateProcessor() public void Run_CreatedDelegateProcessor()
{ {
Action<Image<Rgba32>> action = (i) => { }; Action<Image<Rgba32>> action = (i) => { };
this.operations.Run(action); this.operations.Apply(action);
DelegateProcessor<Rgba32> processor = this.Verify<DelegateProcessor<Rgba32>>(); DelegateProcessor<Rgba32> processor = this.Verify<DelegateProcessor<Rgba32>>();
Assert.Equal(action, processor.Action); Assert.Equal(action, processor.Action);

Loading…
Cancel
Save