Skip to content
9 changes: 9 additions & 0 deletions src/ImageSharp/Configuration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

using System;
using System.Collections.Generic;
using System.Net.Http;
using SixLabors.ImageSharp.Formats;
using SixLabors.ImageSharp.Formats.Bmp;
using SixLabors.ImageSharp.Formats.Gif;
Expand All @@ -27,6 +28,8 @@ public sealed class Configuration

private int maxDegreeOfParallelism = Environment.ProcessorCount;

private Dictionary<object, object> properties = new Dictionary<object, object>();

/// <summary>
/// Initializes a new instance of the <see cref="Configuration" /> class.
/// </summary>
Expand Down Expand Up @@ -73,6 +76,12 @@ public int MaxDegreeOfParallelism
}
}

/// <summary>
/// Gets a set of properties for the Congiguration.
/// </summary>
/// <remarks>This can be used for storing global settings and defaults to be accessable to processors.</remarks>
public IDictionary<object, object> Properties => this.properties;

/// <summary>
/// Gets the currently registered <see cref="IImageFormat"/>s.
/// </summary>
Expand Down
100 changes: 100 additions & 0 deletions src/ImageSharp/GraphicOptionsDefaultsExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.

using System;
using SixLabors.ImageSharp.Processing;

namespace SixLabors.ImageSharp
{
/// <summary>
/// Adds extensions that allow the processing of images to the <see cref="Image{TPixel}"/> type.
/// </summary>
public static class GraphicOptionsDefaultsExtensions
{
/// <summary>
/// Sets the default options against the image processing context.
/// </summary>
/// <param name="context">The image processing context to store default against.</param>
/// <param name="optionsBuilder">The action to update instance of the default options used.</param>
/// <returns>The passed in <paramref name="context"/> to allow chaining.</returns>
public static IImageProcessingContext SetGraphicsOptions(this IImageProcessingContext context, Action<GraphicsOptions> optionsBuilder)
{
var cloned = context.GetGraphicsOptions().DeepClone();
optionsBuilder(cloned);
context.Properties[typeof(GraphicsOptions)] = cloned;
return context;
}

/// <summary>
/// Sets the default options against the configuration.
/// </summary>
/// <param name="context">The image processing context to store default against.</param>
/// <param name="optionsBuilder">The default options to use.</param>
public static void SetGraphicsOptions(this Configuration context, Action<GraphicsOptions> optionsBuilder)
{
var cloned = context.GetGraphicsOptions().DeepClone();
optionsBuilder(cloned);
context.Properties[typeof(GraphicsOptions)] = cloned;
}

/// <summary>
/// Sets the default options against the image processing context.
/// </summary>
/// <param name="context">The image processing context to store default against.</param>
/// <param name="options">The default options to use.</param>
/// <returns>The passed in <paramref name="context"/> to allow chaining.</returns>
public static IImageProcessingContext SetGraphicsOptions(this IImageProcessingContext context, GraphicsOptions options)
{
context.Properties[typeof(GraphicsOptions)] = options;
return context;
}

/// <summary>
/// Sets the default options against the configuration.
/// </summary>
/// <param name="context">The image processing context to store default against.</param>
/// <param name="options">The default options to use.</param>
public static void SetGraphicsOptions(this Configuration context, GraphicsOptions options)
{
context.Properties[typeof(GraphicsOptions)] = options;
}

/// <summary>
/// Gets the default options against the image processing context.
/// </summary>
/// <param name="context">The image processing context to retrieve defaults from.</param>
/// <returns>The globaly configued default options.</returns>
public static GraphicsOptions GetGraphicsOptions(this IImageProcessingContext context)
{
if (context.Properties.TryGetValue(typeof(GraphicsOptions), out var options) && options is GraphicsOptions go)
{
return go;
}

var configOptions = context.Configuration.GetGraphicsOptions();
Copy link
Member

@antonfirsov antonfirsov Apr 21, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are we really sure we want to repeat the defaulting logic in all the Get*** extension methods, instead of populating Properties in the DefaultImageProcessingContext ctr?

What are the pros for this decision?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah yeah... If our keys are strongly typed that makes comparison faster and easier too.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FYI an interesting API proposal that also contains the concept of property bags: dotnet/runtime#1793

In total, a bit too verbose for my style, but I like the idea of having custom types for the bag, and (in some form) for the keys. I would also apply it for values, if it makes sense.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I do kinda like the pattern proposed in the runtime but, (and it is a big but) it feels soo overengineered, sometimes (and in my experience usually) the simple solution is the right one.


// do not cache the fall back to config into the the processing context
// in case someone want to change the value on the config and expects it re trflow thru
return configOptions;
}

/// <summary>
/// Gets the default options against the image processing context.
/// </summary>
/// <param name="context">The image processing context to retrieve defaults from.</param>
/// <returns>The globaly configued default options.</returns>
public static GraphicsOptions GetGraphicsOptions(this Configuration context)
{
if (context.Properties.TryGetValue(typeof(GraphicsOptions), out var options) && options is GraphicsOptions go)
{
return go;
}

var configOptions = new GraphicsOptions();

// capture the fallback so the same instance will always be returned in case its mutated
context.Properties[typeof(GraphicsOptions)] = configOptions;
return configOptions;
}
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.

using System.Collections.Generic;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing.Processors;

Expand All @@ -15,6 +16,7 @@ internal class DefaultImageProcessorContext<TPixel> : IInternalImageProcessingCo
{
private readonly bool mutate;
private readonly Image<TPixel> source;
private readonly Dictionary<object, object> properties = new Dictionary<object, object>();
private Image<TPixel> destination;

/// <summary>
Expand All @@ -39,6 +41,9 @@ public DefaultImageProcessorContext(Configuration configuration, Image<TPixel> s
/// <inheritdoc/>
public Configuration Configuration { get; }

/// <inheritdoc/>
public IDictionary<object, object> Properties => this.properties;

/// <inheritdoc/>
public Image<TPixel> GetResultImage()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ public static IImageProcessingContext DrawImage(
Image image,
float opacity)
{
var options = new GraphicsOptions();
var options = source.GetGraphicsOptions();
return source.ApplyProcessor(
new DrawImageProcessor(
image,
Expand Down Expand Up @@ -51,7 +51,7 @@ public static IImageProcessingContext DrawImage(
image,
Point.Empty,
colorBlending,
new GraphicsOptions().AlphaCompositionMode,
source.GetGraphicsOptions().AlphaCompositionMode,
opacity));

/// <summary>
Expand Down Expand Up @@ -104,7 +104,7 @@ public static IImageProcessingContext DrawImage(
Point location,
float opacity)
{
var options = new GraphicsOptions();
var options = source.GetGraphicsOptions();
return source.ApplyProcessor(
new DrawImageProcessor(
image,
Expand Down Expand Up @@ -134,7 +134,7 @@ public static IImageProcessingContext DrawImage(
image,
location,
colorBlending,
new GraphicsOptions().AlphaCompositionMode,
source.GetGraphicsOptions().AlphaCompositionMode,
opacity));

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) Six Labors and contributors.
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.

using SixLabors.ImageSharp.Processing.Processors.Filters;
Expand All @@ -17,7 +17,7 @@ public static class LomographExtensions
/// <param name="source">The image this method extends.</param>
/// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
public static IImageProcessingContext Lomograph(this IImageProcessingContext source)
=> source.ApplyProcessor(new LomographProcessor());
=> source.ApplyProcessor(new LomographProcessor(source.GetGraphicsOptions()));

/// <summary>
/// Alters the colors of the image recreating an old Lomograph camera effect.
Expand All @@ -28,6 +28,6 @@ public static IImageProcessingContext Lomograph(this IImageProcessingContext sou
/// </param>
/// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
public static IImageProcessingContext Lomograph(this IImageProcessingContext source, Rectangle rectangle)
=> source.ApplyProcessor(new LomographProcessor(), rectangle);
=> source.ApplyProcessor(new LomographProcessor(source.GetGraphicsOptions()), rectangle);
}
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) Six Labors and contributors.
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.

using SixLabors.ImageSharp.Processing.Processors.Filters;
Expand All @@ -17,7 +17,7 @@ public static class PolaroidExtensions
/// <param name="source">The image this method extends.</param>
/// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
public static IImageProcessingContext Polaroid(this IImageProcessingContext source)
=> source.ApplyProcessor(new PolaroidProcessor());
=> source.ApplyProcessor(new PolaroidProcessor(source.GetGraphicsOptions()));

/// <summary>
/// Alters the colors of the image recreating an old Polaroid camera effect.
Expand All @@ -28,6 +28,6 @@ public static IImageProcessingContext Polaroid(this IImageProcessingContext sour
/// </param>
/// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
public static IImageProcessingContext Polaroid(this IImageProcessingContext source, Rectangle rectangle)
=> source.ApplyProcessor(new PolaroidProcessor(), rectangle);
=> source.ApplyProcessor(new PolaroidProcessor(source.GetGraphicsOptions()), rectangle);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ public static class BackgroundColorExtensions
/// <param name="color">The color to set as the background.</param>
/// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
public static IImageProcessingContext BackgroundColor(this IImageProcessingContext source, Color color) =>
BackgroundColor(source, new GraphicsOptions(), color);
BackgroundColor(source, source.GetGraphicsOptions(), color);

/// <summary>
/// Replaces the background color of image with the given one.
Expand All @@ -33,7 +33,7 @@ public static IImageProcessingContext BackgroundColor(
this IImageProcessingContext source,
Color color,
Rectangle rectangle) =>
BackgroundColor(source, new GraphicsOptions(), color, rectangle);
BackgroundColor(source, source.GetGraphicsOptions(), color, rectangle);

/// <summary>
/// Replaces the background color of image with the given one.
Expand Down
10 changes: 5 additions & 5 deletions src/ImageSharp/Processing/Extensions/Overlays/GlowExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ public static class GlowExtensions
/// <param name="source">The image this method extends.</param>
/// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
public static IImageProcessingContext Glow(this IImageProcessingContext source) =>
Glow(source, new GraphicsOptions());
Glow(source, source.GetGraphicsOptions());

/// <summary>
/// Applies a radial glow effect to an image.
Expand All @@ -27,7 +27,7 @@ public static IImageProcessingContext Glow(this IImageProcessingContext source)
/// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
public static IImageProcessingContext Glow(this IImageProcessingContext source, Color color)
{
return Glow(source, new GraphicsOptions(), color);
return Glow(source, source.GetGraphicsOptions(), color);
}

/// <summary>
Expand All @@ -37,7 +37,7 @@ public static IImageProcessingContext Glow(this IImageProcessingContext source,
/// <param name="radius">The the radius.</param>
/// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
public static IImageProcessingContext Glow(this IImageProcessingContext source, float radius) =>
Glow(source, new GraphicsOptions(), radius);
Glow(source, source.GetGraphicsOptions(), radius);

/// <summary>
/// Applies a radial glow effect to an image.
Expand All @@ -48,7 +48,7 @@ public static IImageProcessingContext Glow(this IImageProcessingContext source,
/// </param>
/// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
public static IImageProcessingContext Glow(this IImageProcessingContext source, Rectangle rectangle) =>
source.Glow(new GraphicsOptions(), rectangle);
source.Glow(source.GetGraphicsOptions(), rectangle);

/// <summary>
/// Applies a radial glow effect to an image.
Expand All @@ -65,7 +65,7 @@ public static IImageProcessingContext Glow(
Color color,
float radius,
Rectangle rectangle) =>
source.Glow(new GraphicsOptions(), color, ValueSize.Absolute(radius), rectangle);
source.Glow(source.GetGraphicsOptions(), color, ValueSize.Absolute(radius), rectangle);

/// <summary>
/// Applies a radial glow effect to an image.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ public static class VignetteExtensions
/// <param name="source">The image this method extends.</param>
/// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
public static IImageProcessingContext Vignette(this IImageProcessingContext source) =>
Vignette(source, new GraphicsOptions());
Vignette(source, source.GetGraphicsOptions());

/// <summary>
/// Applies a radial vignette effect to an image.
Expand All @@ -26,7 +26,7 @@ public static IImageProcessingContext Vignette(this IImageProcessingContext sour
/// <param name="color">The color to set as the vignette.</param>
/// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
public static IImageProcessingContext Vignette(this IImageProcessingContext source, Color color) =>
Vignette(source, new GraphicsOptions(), color);
Vignette(source, source.GetGraphicsOptions(), color);

/// <summary>
/// Applies a radial vignette effect to an image.
Expand All @@ -39,7 +39,7 @@ public static IImageProcessingContext Vignette(
this IImageProcessingContext source,
float radiusX,
float radiusY) =>
Vignette(source, new GraphicsOptions(), radiusX, radiusY);
Vignette(source, source.GetGraphicsOptions(), radiusX, radiusY);

/// <summary>
/// Applies a radial vignette effect to an image.
Expand All @@ -50,7 +50,7 @@ public static IImageProcessingContext Vignette(
/// </param>
/// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
public static IImageProcessingContext Vignette(this IImageProcessingContext source, Rectangle rectangle) =>
Vignette(source, new GraphicsOptions(), rectangle);
Vignette(source, source.GetGraphicsOptions(), rectangle);

/// <summary>
/// Applies a radial vignette effect to an image.
Expand All @@ -69,7 +69,7 @@ public static IImageProcessingContext Vignette(
float radiusX,
float radiusY,
Rectangle rectangle) =>
source.Vignette(new GraphicsOptions(), color, radiusX, radiusY, rectangle);
source.Vignette(source.GetGraphicsOptions(), color, radiusX, radiusY, rectangle);

/// <summary>
/// Applies a radial vignette effect to an image.
Expand Down
7 changes: 7 additions & 0 deletions src/ImageSharp/Processing/IImageProcessingContext.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.

using System.Collections.Generic;
using SixLabors.ImageSharp.Processing.Processors;

namespace SixLabors.ImageSharp.Processing
Expand All @@ -15,6 +16,12 @@ public interface IImageProcessingContext
/// </summary>
Configuration Configuration { get; }

/// <summary>
/// Gets a set of properties for the Image Processing Context.
/// </summary>
/// <remarks>This can be used for storing global settings and defaults to be accessable to processors.</remarks>
IDictionary<object, object> Properties { get; }
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if we want to consider something more strongly-typed here?

  • System.Type or a custom object as a key
  • Restrictions for the value: do we expect simple values here? If not, maybe a marker interface.
  • Our own types GraphicsProperties / IGraphicsProperties instead of IDictionary<K,V>

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no it should be explicitly be as loosely typed as possible and we should not be limiting anything from being but in the property bag, that's why I even when as far as using <object,object> rather than <string,object> to allow developers to use it for there needs they can do anything with it... use strings, use private object instances (no way for someone to accidently reuse the key) or anything in between... we would be loosing one of the key flexibility benefits of this extension point is we make the type a custom type with restrictions..


/// <summary>
/// Gets the image dimensions at the current point in the processing pipeline.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,18 @@ public sealed class LomographProcessor : FilterProcessor
/// <summary>
/// Initializes a new instance of the <see cref="LomographProcessor" /> class.
/// </summary>
public LomographProcessor()
/// <param name="graphicsOptions">Graphics options to use within the processor.</param>
public LomographProcessor(GraphicsOptions graphicsOptions)
: base(KnownFilterMatrices.LomographFilter)
{
this.GraphicsOptions = graphicsOptions;
}

/// <summary>
/// Gets the options effecting blending and composition
/// </summary>
public GraphicsOptions GraphicsOptions { get; }

/// <inheritdoc />
public override IImageProcessor<TPixel> CreatePixelSpecificProcessor<TPixel>(Configuration configuration, Image<TPixel> source, Rectangle sourceRectangle) =>
new LomographProcessor<TPixel>(configuration, this, source, sourceRectangle);
Expand Down
Loading