Browse Source

Cleanup + Rename Run to Apply

pull/275/head
James Jackson-South 9 years ago
parent
commit
70892a1468
  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,
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`
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
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)
{
// 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
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
//lets make 3 more positioned correctly, we cando that by translating the orgional artound the center of the image
var center = new Vector2(imageWidth / 2, imageHeight / 2);
//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 / 2F, imageHeight / 2F);
float rightPos = imageWidth - cornerToptLeft.Bounds.Width + 1;
float bottomPos = imageHeight - cornerToptLeft.Bounds.Height + 1;
// move it across the widthof the image - the width of the shape
var cornerTopRight = cornerToptLeft.RotateDegree(90).Translate(rightPos, 0);
var cornerBottomLeft = cornerToptLeft.RotateDegree(-90).Translate(0, bottomPos);
var cornerBottomRight = cornerToptLeft.RotateDegree(180).Translate(rightPos, bottomPos);
IPath cornerTopRight = cornerToptLeft.RotateDegree(90).Translate(rightPos, 0);
IPath cornerBottomLeft = cornerToptLeft.RotateDegree(-90).Translate(0, bottomPos);
IPath cornerBottomRight = cornerToptLeft.RotateDegree(180).Translate(rightPos, bottomPos);
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>
/// <param name="source">The image to rotate, flip, or both.</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)
where TPixel : struct, IPixel<TPixel>
{
@ -104,4 +104,4 @@ namespace ImageSharp
return source;
}
}
}
}

20
src/ImageSharp/DefaultInternalImageProcessorContext.cs

@ -5,14 +5,12 @@
namespace ImageSharp
{
using System;
using System.Collections.Generic;
using ImageSharp.PixelFormats;
using ImageSharp.Processing;
using SixLabors.Primitives;
/// <summary>
/// The static collection of all the default image formats
/// Performs processor application operations on the source image
/// </summary>
/// <typeparam name="TPixel">The pixel format</typeparam>
internal class DefaultInternalImageProcessorContext<TPixel> : IInternalImageProcessingContext<TPixel>
@ -42,7 +40,7 @@ namespace ImageSharp
{
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();
}
@ -54,19 +52,17 @@ namespace ImageSharp
{
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
// 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 = cloningProcessor.CloneAndApply(this.source, rectangle);
this.destination = cloningImageProcessor.CloneAndApply(this.source, rectangle);
return this;
}
else
{
this.destination = this.source.Clone();
}
this.destination = this.source.Clone();
}
processor.Apply(this.destination, rectangle);

5
src/ImageSharp/IImageProcessingContextFactory.cs

@ -5,16 +5,15 @@
namespace ImageSharp
{
using System;
using ImageSharp.PixelFormats;
/// <summary>
/// Represents an interface that will create IImageOperations
/// Represents an interface that will create IInternalImageProcessingContext instances
/// </summary>
internal interface IImageProcessingContextFactory
{
/// <summary>
/// Called during Mutate operations to generate the imageoperations provider.
/// Called during Mutate operations to generate the image operations provider.
/// </summary>
/// <typeparam name="TPixel">The pixel format</typeparam>
/// <param name="source">The source image.</param>

12
src/ImageSharp/IImageProcessingContext{TPixel}.cs

@ -5,8 +5,6 @@
namespace ImageSharp
{
using System;
using ImageSharp.Formats;
using ImageSharp.PixelFormats;
using ImageSharp.Processing;
using SixLabors.Primitives;
@ -19,18 +17,18 @@ namespace ImageSharp
where TPixel : struct, IPixel<TPixel>
{
/// <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>
/// <param name="processor">The processor to apply</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);
/// <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>
/// <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);
}
@ -44,7 +42,7 @@ namespace ImageSharp
/// <summary>
/// Adds the processors to the current image
/// </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();
}
}

6
src/ImageSharp/Processing/Delegate.cs

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

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

@ -6,7 +6,6 @@
namespace ImageSharp.Processing
{
using System;
using System.Threading.Tasks;
using ImageSharp.PixelFormats;
using SixLabors.Primitives;
@ -37,13 +36,13 @@ namespace ImageSharp.Processing
/// <inheritdoc/>
protected override void BeforeImageApply(Image<TPixel> source, Rectangle sourceRectangle)
{
this.action?.Invoke((Image<TPixel>)source);
this.action?.Invoke(source);
}
/// <inheritdoc/>
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/>
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
// lets manually clone an empty set of images at the correct target and then have the base class processs them in.
// turn.
// For resize we know we are going to populate every pixel with fresh data and we want a different target size so
// let's manually clone an empty set of images at the correct target and then have the base class processs them in turn.
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)
{
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
// First process the columns. Since we are not using multiple threads startY and endY
// 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!
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)
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.
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)
where TPixel : struct, IPixel<TPixel>
{
return source.Run(img =>
{
// todo : stop cheeting here and move this stuff into the processors itself
if (width == 0 && height > 0)
{
width = (int)MathF.Round(img.Width * height / (float)img.Height);
targetRectangle.Width = width;
}
if (height == 0 && width > 0)
{
height = (int)MathF.Round(img.Height * width / (float)img.Width);
targetRectangle.Height = height;
}
Guard.MustBeGreaterThan(width, 0, nameof(width));
Guard.MustBeGreaterThan(height, 0, nameof(height));
img.Mutate(x => x.ApplyProcessor(new ResizeProcessor<TPixel>(sampler, width, height, targetRectangle) { Compand = compand }, sourceRectangle));
});
return source.Apply(img =>
{
// TODO : Stop cheating here and move this stuff into the processors itself
if (width == 0 && height > 0)
{
width = (int)MathF.Round(img.Width * height / (float)img.Height);
targetRectangle.Width = width;
}
if (height == 0 && width > 0)
{
height = (int)MathF.Round(img.Height * width / (float)img.Width);
targetRectangle.Height = height;
}
Guard.MustBeGreaterThan(width, 0, nameof(width));
Guard.MustBeGreaterThan(height, 0, nameof(height));
img.Mutate(x => x.ApplyProcessor(new ResizeProcessor<TPixel>(sampler, width, height, targetRectangle) { Compand = compand }, sourceRectangle));
});
}
/// <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)
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)
{
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)
where TPixel : struct, IPixel<TPixel>
{
return source.Run(img =>
return source.Apply(img =>
{
// TODO : move helper logic into the processor
QuantizedImage<TPixel> quantized = quantizer.Quantize(img, maxColors);
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(
0,

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

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

Loading…
Cancel
Save