📷 A modern, cross-platform, 2D Graphics library for .NET
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

99 lines
3.5 KiB

// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
#nullable disable
using System.Collections.Concurrent;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing.Processors;
namespace SixLabors.ImageSharp.Processing;
/// <summary>
/// Performs processor application operations on the source image
/// </summary>
/// <typeparam name="TPixel">The pixel format</typeparam>
internal class DefaultImageProcessorContext<TPixel> : IInternalImageProcessingContext<TPixel>
where TPixel : unmanaged, IPixel<TPixel>
{
private readonly bool mutate;
private readonly Image<TPixel> source;
private Image<TPixel> destination;
/// <summary>
/// Initializes a new instance of the <see cref="DefaultImageProcessorContext{TPixel}"/> class.
/// </summary>
/// <param name="configuration">The configuration which allows altering default behaviour or extending the library.</param>
/// <param name="source">The source image.</param>
/// <param name="mutate">Whether to mutate the image.</param>
public DefaultImageProcessorContext(Configuration configuration, Image<TPixel> source, bool mutate)
{
this.Configuration = configuration;
this.mutate = mutate;
this.source = source;
// Mutate acts upon the source image only.
if (this.mutate)
{
this.destination = source;
}
}
/// <inheritdoc/>
public Configuration Configuration { get; }
/// <inheritdoc/>
public IDictionary<object, object> Properties { get; } = new ConcurrentDictionary<object, object>();
/// <inheritdoc/>
public Image<TPixel> GetResultImage()
{
if (!this.mutate && this.destination is null)
{
// 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();
}
return this.destination;
}
/// <inheritdoc/>
public Size GetCurrentSize() => this.GetCurrentBounds().Size;
/// <inheritdoc/>
public IImageProcessingContext ApplyProcessor(IImageProcessor processor)
{
return this.ApplyProcessor(processor, this.GetCurrentBounds());
}
/// <inheritdoc/>
public IImageProcessingContext ApplyProcessor(IImageProcessor processor, Rectangle rectangle)
{
if (!this.mutate && this.destination is null)
{
// 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 ICloningImageProcessor cloningImageProcessor)
{
using (ICloningImageProcessor<TPixel> pixelProcessor = cloningImageProcessor.CreatePixelSpecificCloningProcessor(this.Configuration, this.source, rectangle))
{
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.Configuration, this.destination, rectangle))
{
specificProcessor.Execute();
}
return this;
}
private Rectangle GetCurrentBounds() => this.destination?.Bounds ?? this.source.Bounds;
}