Skip to content
Closed
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -81,9 +81,12 @@ public DrawTextProcessor(TextGraphicsOptions options, string text, Font font, IB
/// </summary>
public PointF Location { get; }

protected override void BeforeImageApply(Image<TPixel> source, Rectangle sourceRectangle)
protected override void BeforeImageApply(
Image<TPixel> source,
Rectangle sourceRectangle,
Configuration configuration)
{
base.BeforeImageApply(source, sourceRectangle);
base.BeforeImageApply(source, sourceRectangle, configuration);

// do everything at the image level as we are delegating the processing down to other processors
var style = new RendererOptions(this.Font, this.Options.DpiX, this.Options.DpiY, this.Location)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,18 +25,20 @@ internal class DefaultInternalImageProcessorContext<TPixel> : IInternalImageProc
/// </summary>
/// <param name="source">The image.</param>
/// <param name="mutate">The mutate.</param>
public DefaultInternalImageProcessorContext(Image<TPixel> source, bool mutate)
/// <param name="configuration">Overrides default configuration for the image.</param>
public DefaultInternalImageProcessorContext(Image<TPixel> source, bool mutate, Configuration configuration = null)
{
this.mutate = mutate;
this.source = source;
this.Configuration = configuration ?? source.GetConfiguration();
if (this.mutate)
{
this.destination = source;
}
}

/// <inheritdoc/>
public MemoryAllocator MemoryAllocator => this.source.GetConfiguration().MemoryAllocator;
public Configuration Configuration { get; }

/// <inheritdoc/>
public Image<TPixel> Apply()
Expand Down Expand Up @@ -70,7 +72,7 @@ public IImageProcessingContext<TPixel> ApplyProcessor(IImageProcessor<TPixel> pr
this.destination = this.source.Clone();
}

processor.Apply(this.destination, rectangle);
processor.Apply(this.destination, rectangle, this.Configuration);
return this;
}

Expand Down
7 changes: 4 additions & 3 deletions src/ImageSharp/Processing/IImageProcessingContextFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,9 @@ internal interface IImageProcessingContextFactory
/// <typeparam name="TPixel">The pixel format</typeparam>
/// <param name="source">The source image.</param>
/// <param name="mutate">A flag to determine whether image operations are allowed to mutate the source image.</param>
/// <param name="configuration">Overrides default configuration for the image.</param>
/// <returns>A new <see cref="IInternalImageProcessingContext{TPixel}"/></returns>
IInternalImageProcessingContext<TPixel> CreateImageProcessingContext<TPixel>(Image<TPixel> source, bool mutate)
IInternalImageProcessingContext<TPixel> CreateImageProcessingContext<TPixel>(Image<TPixel> source, bool mutate, Configuration configuration = null)
where TPixel : struct, IPixel<TPixel>;
}

Expand All @@ -27,10 +28,10 @@ IInternalImageProcessingContext<TPixel> CreateImageProcessingContext<TPixel>(Ima
internal class DefaultImageOperationsProviderFactory : IImageProcessingContextFactory
{
/// <inheritdoc/>
public IInternalImageProcessingContext<TPixel> CreateImageProcessingContext<TPixel>(Image<TPixel> source, bool mutate)
public IInternalImageProcessingContext<TPixel> CreateImageProcessingContext<TPixel>(Image<TPixel> source, bool mutate, Configuration configuration = null)
where TPixel : struct, IPixel<TPixel>
{
return new DefaultInternalImageProcessorContext<TPixel>(source, mutate);
return new DefaultInternalImageProcessorContext<TPixel>(source, mutate, configuration);
}
}
}
5 changes: 2 additions & 3 deletions src/ImageSharp/Processing/IImageProcessingContext{TPixel}.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,9 @@ public interface IImageProcessingContext<TPixel>
where TPixel : struct, IPixel<TPixel>
{
/// <summary>
/// Gets a reference to the <see cref="MemoryAllocator" /> used to allocate buffers
/// for this context.
/// Gets a reference to the <see cref="Configuration" /> for this context.
/// </summary>
MemoryAllocator MemoryAllocator { get; }
Configuration Configuration { get; }

/// <summary>
/// Gets the image dimensions at the current point in the processing pipeline.
Expand Down
34 changes: 29 additions & 5 deletions src/ImageSharp/Processing/ProcessingExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public static class ProcessingExtensions
/// <param name="source">The image to mutate.</param>
/// <param name="operation">The operation to perform on the source.</param>
/// <returns>The <see cref="IImageProcessingContext{TPixel}"/> to allow chaining of operations.</returns>
public static IImageProcessingContext<TPixel> Apply<TPixel>(this IImageProcessingContext<TPixel> source, Action<Image<TPixel>> operation)
public static IImageProcessingContext<TPixel> Apply<TPixel>(this IImageProcessingContext<TPixel> source, Action<Image<TPixel>, Configuration> operation)
where TPixel : struct, IPixel<TPixel> => source.ApplyProcessor(new DelegateProcessor<TPixel>(operation));

/// <summary>
Expand All @@ -31,13 +31,15 @@ public static IImageProcessingContext<TPixel> Apply<TPixel>(this IImageProcessin
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image to mutate.</param>
/// <param name="operation">The operation to perform on the source.</param>
public static void Mutate<TPixel>(this Image<TPixel> source, Action<IImageProcessingContext<TPixel>> operation)
/// <param name="configuration">Overrides default configuration for the image.</param>
public static void Mutate<TPixel>(this Image<TPixel> source, Action<IImageProcessingContext<TPixel>> operation, Configuration configuration = null)
where TPixel : struct, IPixel<TPixel>
{
Guard.NotNull(operation, nameof(operation));
Guard.NotNull(source, nameof(source));
configuration = configuration ?? source.GetConfiguration();

IInternalImageProcessingContext<TPixel> operationsRunner = source.GetConfiguration().ImageOperationsProvider.CreateImageProcessingContext(source, true);
IInternalImageProcessingContext<TPixel> operationsRunner = configuration.ImageOperationsProvider.CreateImageProcessingContext(source, true, configuration);
operation(operationsRunner);
operationsRunner.Apply();
}
Expand Down Expand Up @@ -65,14 +67,16 @@ public static void Mutate<TPixel>(this Image<TPixel> source, params IImageProces
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image to clone.</param>
/// <param name="operation">The operation to perform on the clone.</param>
/// <param name="configuration">Overrides default configuration for the image.</param>
/// <returns>The new <see cref="SixLabors.ImageSharp.Image{TPixel}"/></returns>
public static Image<TPixel> Clone<TPixel>(this Image<TPixel> source, Action<IImageProcessingContext<TPixel>> operation)
public static Image<TPixel> Clone<TPixel>(this Image<TPixel> source, Action<IImageProcessingContext<TPixel>> operation, Configuration configuration = null)
where TPixel : struct, IPixel<TPixel>
{
Guard.NotNull(operation, nameof(operation));
Guard.NotNull(source, nameof(source));
configuration = configuration ?? source.GetConfiguration();

IInternalImageProcessingContext<TPixel> operationsRunner = source.GetConfiguration().ImageOperationsProvider.CreateImageProcessingContext(source, false);
IInternalImageProcessingContext<TPixel> operationsRunner = configuration.ImageOperationsProvider.CreateImageProcessingContext(source, false, configuration);
operation(operationsRunner);
return operationsRunner.Apply();
}
Expand All @@ -95,6 +99,26 @@ public static Image<TPixel> Clone<TPixel>(this Image<TPixel> source, params IIma
return operationsRunner.Apply();
}

/// <summary>
/// Creates a deep clone of the current image. The clone is then mutated by the given operations.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image to clone.</param>
/// <param name="configuration">Overrides default configuration for the image.</param>
/// <param name="operations">The operations to perform on the clone.</param>
/// <returns>The new <see cref="SixLabors.ImageSharp.Image{TPixel}"/></returns>
public static Image<TPixel> Clone<TPixel>(this Image<TPixel> source, Configuration configuration, params IImageProcessor<TPixel>[] operations)
where TPixel : struct, IPixel<TPixel>
{
Guard.NotNull(operations, nameof(operations));
Guard.NotNull(source, nameof(source));
Guard.NotNull(configuration, nameof(configuration));

IInternalImageProcessingContext<TPixel> operationsRunner = configuration.ImageOperationsProvider.CreateImageProcessingContext(source, false, configuration);
operationsRunner.ApplyProcessors(operations);
return operationsRunner.Apply();
}

/// <summary>
/// Applies the given <see cref="IImageProcessor{TPixel}"/> collection against the context
/// </summary>
Expand Down
8 changes: 4 additions & 4 deletions src/ImageSharp/Processing/Processors/CloningImageProcessor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ internal abstract class CloningImageProcessor<TPixel> : ICloningImageProcessor<T
where TPixel : struct, IPixel<TPixel>
{
/// <inheritdoc/>
public Image<TPixel> CloneAndApply(Image<TPixel> source, Rectangle sourceRectangle)
public Image<TPixel> CloneAndApply(Image<TPixel> source, Rectangle sourceRectangle, Configuration configuration = null)
{
try
{
Expand All @@ -27,7 +27,7 @@ public Image<TPixel> CloneAndApply(Image<TPixel> source, Rectangle sourceRectang
throw new ImageProcessingException($"An error occurred when processing the image using {this.GetType().Name}. The processor changed the number of frames.");
}

Configuration configuration = source.GetConfiguration();
configuration = configuration ?? source.GetConfiguration();
this.BeforeImageApply(source, clone, sourceRectangle);

for (int i = 0; i < source.Frames.Count; i++)
Expand Down Expand Up @@ -57,9 +57,9 @@ public Image<TPixel> CloneAndApply(Image<TPixel> source, Rectangle sourceRectang
}

/// <inheritdoc/>
public void Apply(Image<TPixel> source, Rectangle sourceRectangle)
public void Apply(Image<TPixel> source, Rectangle sourceRectangle, Configuration configuration = null)
{
using (Image<TPixel> cloned = this.CloneAndApply(source, sourceRectangle))
using (Image<TPixel> cloned = this.CloneAndApply(source, sourceRectangle, configuration))
{
// we now need to move the pixel data/size data from one image base to another
if (cloned.Frames.Count != source.Frames.Count)
Expand Down
8 changes: 4 additions & 4 deletions src/ImageSharp/Processing/Processors/DelegateProcessor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,20 +18,20 @@ internal class DelegateProcessor<TPixel> : ImageProcessor<TPixel>
/// Initializes a new instance of the <see cref="DelegateProcessor{TPixel}"/> class.
/// </summary>
/// <param name="action">The action.</param>
public DelegateProcessor(Action<Image<TPixel>> action)
public DelegateProcessor(Action<Image<TPixel>, Configuration> action)
{
this.Action = action;
}

/// <summary>
/// Gets the action that will be applied to the image.
/// </summary>
internal Action<Image<TPixel>> Action { get; }
internal Action<Image<TPixel>, Configuration> Action { get; }

/// <inheritdoc/>
protected override void BeforeImageApply(Image<TPixel> source, Rectangle sourceRectangle)
protected override void BeforeImageApply(Image<TPixel> source, Rectangle sourceRectangle, Configuration configuration)
{
this.Action?.Invoke(source);
this.Action?.Invoke(source, configuration);
}

/// <inheritdoc/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,14 @@ internal interface ICloningImageProcessor<TPixel> : IImageProcessor<TPixel>
/// <param name="sourceRectangle">
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to draw.
/// </param>
/// <param name="configuration">Overrides default configuration for the image.</param>
/// <exception cref="System.ArgumentNullException">
/// <paramref name="source"/> is null.
/// </exception>
/// <exception cref="System.ArgumentException">
/// <paramref name="sourceRectangle"/> 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(Image<TPixel> source, Rectangle sourceRectangle);
Image<TPixel> CloneAndApply(Image<TPixel> source, Rectangle sourceRectangle, Configuration configuration = null);
}
}
3 changes: 2 additions & 1 deletion src/ImageSharp/Processing/Processors/IImageProcessor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,13 @@ public interface IImageProcessor<TPixel>
/// <param name="sourceRectangle">
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to draw.
/// </param>
/// <param name="configuration">Overrides default configuration for the image.</param>
/// <exception cref="System.ArgumentNullException">
/// <paramref name="source"/> is null.
/// </exception>
/// <exception cref="System.ArgumentException">
/// <paramref name="sourceRectangle"/> doesn't fit the dimension of the image.
/// </exception>
void Apply(Image<TPixel> source, Rectangle sourceRectangle);
void Apply(Image<TPixel> source, Rectangle sourceRectangle, Configuration configuration = null);
}
}
11 changes: 6 additions & 5 deletions src/ImageSharp/Processing/Processors/ImageProcessor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,16 @@ internal abstract class ImageProcessor<TPixel> : IImageProcessor<TPixel>
where TPixel : struct, IPixel<TPixel>
{
/// <inheritdoc/>
public void Apply(Image<TPixel> source, Rectangle sourceRectangle)
public void Apply(Image<TPixel> source, Rectangle sourceRectangle, Configuration configuration = null)
{
try
{
Configuration config = source.GetConfiguration();
this.BeforeImageApply(source, sourceRectangle);
configuration = configuration ?? source.GetConfiguration();
this.BeforeImageApply(source, sourceRectangle, configuration);

foreach (ImageFrame<TPixel> sourceFrame in source.Frames)
{
this.Apply(sourceFrame, sourceRectangle, config);
this.Apply(sourceFrame, sourceRectangle, configuration);
}

this.AfterImageApply(source, sourceRectangle);
Expand Down Expand Up @@ -73,7 +73,8 @@ public void Apply(ImageFrame<TPixel> source, Rectangle sourceRectangle, Configur
/// </summary>
/// <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>
protected virtual void BeforeImageApply(Image<TPixel> source, Rectangle sourceRectangle)
/// <param name="configuration">Overrides default configuration for the image.</param>
protected virtual void BeforeImageApply(Image<TPixel> source, Rectangle sourceRectangle, Configuration configuration)
{
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,40 +17,43 @@ internal class AutoOrientProcessor<TPixel> : ImageProcessor<TPixel>
where TPixel : struct, IPixel<TPixel>
{
/// <inheritdoc/>
protected override void BeforeImageApply(Image<TPixel> source, Rectangle sourceRectangle)
protected override void BeforeImageApply(
Image<TPixel> source,
Rectangle sourceRectangle,
Configuration configuration)
{
OrientationMode orientation = GetExifOrientation(source);
Size size = sourceRectangle.Size;
switch (orientation)
{
case OrientationMode.TopRight:
new FlipProcessor<TPixel>(FlipMode.Horizontal).Apply(source, sourceRectangle);
new FlipProcessor<TPixel>(FlipMode.Horizontal).Apply(source, sourceRectangle, configuration);
break;

case OrientationMode.BottomRight:
new RotateProcessor<TPixel>((int)RotateMode.Rotate180, size).Apply(source, sourceRectangle);
new RotateProcessor<TPixel>((int)RotateMode.Rotate180, size).Apply(source, sourceRectangle, configuration);
break;

case OrientationMode.BottomLeft:
new FlipProcessor<TPixel>(FlipMode.Vertical).Apply(source, sourceRectangle);
new FlipProcessor<TPixel>(FlipMode.Vertical).Apply(source, sourceRectangle, configuration);
break;

case OrientationMode.LeftTop:
new RotateProcessor<TPixel>((int)RotateMode.Rotate90, size).Apply(source, sourceRectangle);
new FlipProcessor<TPixel>(FlipMode.Horizontal).Apply(source, sourceRectangle);
new RotateProcessor<TPixel>((int)RotateMode.Rotate90, size).Apply(source, sourceRectangle, configuration);
new FlipProcessor<TPixel>(FlipMode.Horizontal).Apply(source, sourceRectangle, configuration);
break;

case OrientationMode.RightTop:
new RotateProcessor<TPixel>((int)RotateMode.Rotate90, size).Apply(source, sourceRectangle);
new RotateProcessor<TPixel>((int)RotateMode.Rotate90, size).Apply(source, sourceRectangle, configuration);
break;

case OrientationMode.RightBottom:
new FlipProcessor<TPixel>(FlipMode.Vertical).Apply(source, sourceRectangle);
new RotateProcessor<TPixel>((int)RotateMode.Rotate270, size).Apply(source, sourceRectangle);
new RotateProcessor<TPixel>((int)RotateMode.Rotate270, size).Apply(source, sourceRectangle, configuration);
break;

case OrientationMode.LeftBottom:
new RotateProcessor<TPixel>((int)RotateMode.Rotate270, size).Apply(source, sourceRectangle);
new RotateProcessor<TPixel>((int)RotateMode.Rotate270, size).Apply(source, sourceRectangle, configuration);
break;

case OrientationMode.Unknown:
Expand Down
Loading