Browse Source

refactor of Overlays

af/merge-core
Anton Firszov 7 years ago
parent
commit
2168ecbb05
  1. 2
      src/ImageSharp/Color/Color.cs
  2. 2
      src/ImageSharp/Primitives/ValueSize.cs
  3. 45
      src/ImageSharp/Processing/BackgroundColorExtensions.cs
  4. 98
      src/ImageSharp/Processing/GlowExtensions.cs
  5. 4
      src/ImageSharp/Processing/Processors/Filters/LomographProcessor{TPixel}.cs
  6. 14
      src/ImageSharp/Processing/Processors/Filters/PolaroidProcessor{TPixel}.cs
  7. 86
      src/ImageSharp/Processing/Processors/Overlays/BackgroundColorProcessor.cs
  8. 101
      src/ImageSharp/Processing/Processors/Overlays/BackgroundColorProcessor{TPixel}.cs
  9. 125
      src/ImageSharp/Processing/Processors/Overlays/GlowProcessor.cs
  10. 112
      src/ImageSharp/Processing/Processors/Overlays/GlowProcessor{TPixel}.cs
  11. 120
      src/ImageSharp/Processing/Processors/Overlays/VignetteProcessor.cs
  12. 114
      src/ImageSharp/Processing/Processors/Overlays/VignetteProcessor{TPixel}.cs
  13. 121
      src/ImageSharp/Processing/VignetteExtensions.cs
  14. 4
      tests/ImageSharp.Benchmarks/Samplers/Glow.cs
  15. 6
      tests/ImageSharp.Tests/Drawing/BeziersTests.cs
  16. 2
      tests/ImageSharp.Tests/Drawing/DrawImageTest.cs
  17. 8
      tests/ImageSharp.Tests/Drawing/DrawPathTests.cs
  18. 17
      tests/ImageSharp.Tests/Drawing/LineComplexPolygonTests.cs
  19. 33
      tests/ImageSharp.Tests/Drawing/LineTests.cs
  20. 9
      tests/ImageSharp.Tests/Drawing/PolygonTests.cs
  21. 16
      tests/ImageSharp.Tests/Drawing/SolidBezierTests.cs
  22. 9
      tests/ImageSharp.Tests/Drawing/SolidComplexPolygonTests.cs
  23. 25
      tests/ImageSharp.Tests/Drawing/SolidPolygonTests.cs
  24. 24
      tests/ImageSharp.Tests/Processing/Effects/BackgroundColorTest.cs
  25. 16
      tests/ImageSharp.Tests/Processing/Overlays/GlowTest.cs
  26. 18
      tests/ImageSharp.Tests/Processing/Overlays/VignetteTest.cs
  27. 4
      tests/ImageSharp.Tests/Processing/Processors/Effects/BackgroundColorTest.cs
  28. 6
      tests/ImageSharp.Tests/Processing/Processors/Overlays/GlowTest.cs
  29. 13
      tests/ImageSharp.Tests/Processing/Processors/Overlays/OverlayTestBase.cs
  30. 6
      tests/ImageSharp.Tests/Processing/Processors/Overlays/VignetteTest.cs

2
src/ImageSharp/Color/Color.cs

@ -86,6 +86,8 @@ namespace SixLabors.ImageSharp
public static Color FromRgba(byte r, byte g, byte b, byte a) => new Color(new Rgba32(r, g, b, a));
public static Color FromRgb(byte r, byte g, byte b) => FromRgba(r, g, b, 255);
/// <summary>
/// Creates a new <see cref="Color"/> instance from the string representing a color in hexadecimal form.
/// </summary>

2
src/ImageSharp/Primitives/ValueSize.cs

@ -7,7 +7,7 @@ using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Primitives
{
/// <summary>
/// Represents a value in relation to a value on the image
/// Represents a value in relation to a value on the image.
/// </summary>
internal readonly struct ValueSize : IEquatable<ValueSize>
{

45
src/ImageSharp/Processing/BackgroundColorExtensions.cs

@ -1,7 +1,6 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing.Processors.Overlays;
using SixLabors.Primitives;
@ -16,53 +15,55 @@ namespace SixLabors.ImageSharp.Processing
/// <summary>
/// Replaces the background color of image with the given one.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="color">The color to set as the background.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> BackgroundColor<TPixel>(this IImageProcessingContext<TPixel> source, TPixel color)
where TPixel : struct, IPixel<TPixel>
=> BackgroundColor(source, GraphicsOptions.Default, color);
/// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
public static IImageProcessingContext BackgroundColor(this IImageProcessingContext source, Color color) =>
BackgroundColor(source, GraphicsOptions.Default, color);
/// <summary>
/// Replaces the background color of image with the given one.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="color">The color to set as the background.</param>
/// <param name="rectangle">
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to alter.
/// </param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> BackgroundColor<TPixel>(this IImageProcessingContext<TPixel> source, TPixel color, Rectangle rectangle)
where TPixel : struct, IPixel<TPixel>
=> BackgroundColor(source, GraphicsOptions.Default, color, rectangle);
/// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
public static IImageProcessingContext BackgroundColor(
this IImageProcessingContext source,
Color color,
Rectangle rectangle) =>
BackgroundColor(source, GraphicsOptions.Default, color, rectangle);
/// <summary>
/// Replaces the background color of image with the given one.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="options">The options effecting pixel blending.</param>
/// <param name="color">The color to set as the background.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> BackgroundColor<TPixel>(this IImageProcessingContext<TPixel> source, GraphicsOptions options, TPixel color)
where TPixel : struct, IPixel<TPixel>
=> source.ApplyProcessor(new BackgroundColorProcessor<TPixel>(color, options));
/// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
public static IImageProcessingContext BackgroundColor(
this IImageProcessingContext source,
GraphicsOptions options,
Color color) =>
source.ApplyProcessor(new BackgroundColorProcessor(color, options));
/// <summary>
/// Replaces the background color of image with the given one.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="options">The options effecting pixel blending.</param>
/// <param name="color">The color to set as the background.</param>
/// <param name="rectangle">
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to alter.
/// </param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> BackgroundColor<TPixel>(this IImageProcessingContext<TPixel> source, GraphicsOptions options, TPixel color, Rectangle rectangle)
where TPixel : struct, IPixel<TPixel>
=> source.ApplyProcessor(new BackgroundColorProcessor<TPixel>(color, options), rectangle);
/// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
public static IImageProcessingContext BackgroundColor(
this IImageProcessingContext source,
GraphicsOptions options,
Color color,
Rectangle rectangle) =>
source.ApplyProcessor(new BackgroundColorProcessor(color, options), rectangle);
}
}
}

98
src/ImageSharp/Processing/GlowExtensions.cs

@ -1,7 +1,6 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Primitives;
using SixLabors.ImageSharp.Processing.Processors.Overlays;
using SixLabors.Primitives;
@ -17,22 +16,18 @@ namespace SixLabors.ImageSharp.Processing
/// <summary>
/// Applies a radial glow effect to an image.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
public static IImageProcessingContext<TPixel> Glow<TPixel>(this IImageProcessingContext<TPixel> source)
where TPixel : struct, IPixel<TPixel>
=> Glow(source, GraphicsOptions.Default);
public static IImageProcessingContext Glow(this IImageProcessingContext source) =>
Glow(source, GraphicsOptions.Default);
/// <summary>
/// Applies a radial glow effect to an image.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="color">The color to set as the glow.</param>
/// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
public static IImageProcessingContext<TPixel> Glow<TPixel>(this IImageProcessingContext<TPixel> source, TPixel color)
where TPixel : struct, IPixel<TPixel>
public static IImageProcessingContext Glow(this IImageProcessingContext source, Color color)
{
return Glow(source, GraphicsOptions.Default, color);
}
@ -40,31 +35,26 @@ namespace SixLabors.ImageSharp.Processing
/// <summary>
/// Applies a radial glow effect to an image.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="radius">The the radius.</param>
/// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
public static IImageProcessingContext<TPixel> Glow<TPixel>(this IImageProcessingContext<TPixel> source, float radius)
where TPixel : struct, IPixel<TPixel>
=> Glow(source, GraphicsOptions.Default, radius);
public static IImageProcessingContext Glow(this IImageProcessingContext source, float radius) =>
Glow(source, GraphicsOptions.Default, radius);
/// <summary>
/// Applies a radial glow effect to an image.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="rectangle">
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to alter.
/// </param>
/// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
public static IImageProcessingContext<TPixel> Glow<TPixel>(this IImageProcessingContext<TPixel> source, Rectangle rectangle)
where TPixel : struct, IPixel<TPixel>
=> source.Glow(GraphicsOptions.Default, rectangle);
public static IImageProcessingContext Glow(this IImageProcessingContext source, Rectangle rectangle) =>
source.Glow(GraphicsOptions.Default, rectangle);
/// <summary>
/// Applies a radial glow effect to an image.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="color">The color to set as the glow.</param>
/// <param name="radius">The the radius.</param>
@ -72,63 +62,66 @@ namespace SixLabors.ImageSharp.Processing
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to alter.
/// </param>
/// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
public static IImageProcessingContext<TPixel> Glow<TPixel>(this IImageProcessingContext<TPixel> source, TPixel color, float radius, Rectangle rectangle)
where TPixel : struct, IPixel<TPixel>
=> source.Glow(GraphicsOptions.Default, color, ValueSize.Absolute(radius), rectangle);
public static IImageProcessingContext Glow(
this IImageProcessingContext source,
Color color,
float radius,
Rectangle rectangle) =>
source.Glow(GraphicsOptions.Default, color, ValueSize.Absolute(radius), rectangle);
/// <summary>
/// Applies a radial glow effect to an image.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="options">The options effecting things like blending.</param>
/// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
public static IImageProcessingContext<TPixel> Glow<TPixel>(this IImageProcessingContext<TPixel> source, GraphicsOptions options)
where TPixel : struct, IPixel<TPixel>
=> source.Glow(options, NamedColors<TPixel>.Black, ValueSize.PercentageOfWidth(0.5f));
public static IImageProcessingContext Glow(this IImageProcessingContext source, GraphicsOptions options) =>
source.Glow(options, Color.Black, ValueSize.PercentageOfWidth(0.5f));
/// <summary>
/// Applies a radial glow effect to an image.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="options">The options effecting things like blending.</param>
/// <param name="color">The color to set as the glow.</param>
/// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
public static IImageProcessingContext<TPixel> Glow<TPixel>(this IImageProcessingContext<TPixel> source, GraphicsOptions options, TPixel color)
where TPixel : struct, IPixel<TPixel>
=> source.Glow(options, color, ValueSize.PercentageOfWidth(0.5f));
public static IImageProcessingContext Glow(
this IImageProcessingContext source,
GraphicsOptions options,
Color color) =>
source.Glow(options, color, ValueSize.PercentageOfWidth(0.5f));
/// <summary>
/// Applies a radial glow effect to an image.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="options">The options effecting things like blending.</param>
/// <param name="radius">The the radius.</param>
/// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
public static IImageProcessingContext<TPixel> Glow<TPixel>(this IImageProcessingContext<TPixel> source, GraphicsOptions options, float radius)
where TPixel : struct, IPixel<TPixel>
=> source.Glow(options, NamedColors<TPixel>.Black, ValueSize.Absolute(radius));
public static IImageProcessingContext Glow(
this IImageProcessingContext source,
GraphicsOptions options,
float radius) =>
source.Glow(options, Color.Black, ValueSize.Absolute(radius));
/// <summary>
/// Applies a radial glow effect to an image.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="options">The options effecting things like blending.</param>
/// <param name="rectangle">
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to alter.
/// </param>
/// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
public static IImageProcessingContext<TPixel> Glow<TPixel>(this IImageProcessingContext<TPixel> source, GraphicsOptions options, Rectangle rectangle)
where TPixel : struct, IPixel<TPixel>
=> source.Glow(options, NamedColors<TPixel>.Black, ValueSize.PercentageOfWidth(0.5f), rectangle);
public static IImageProcessingContext Glow(
this IImageProcessingContext source,
GraphicsOptions options,
Rectangle rectangle) =>
source.Glow(options, Color.Black, ValueSize.PercentageOfWidth(0.5f), rectangle);
/// <summary>
/// Applies a radial glow effect to an image.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="options">The options effecting things like blending.</param>
/// <param name="color">The color to set as the glow.</param>
@ -137,14 +130,17 @@ namespace SixLabors.ImageSharp.Processing
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to alter.
/// </param>
/// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
public static IImageProcessingContext<TPixel> Glow<TPixel>(this IImageProcessingContext<TPixel> source, GraphicsOptions options, TPixel color, float radius, Rectangle rectangle)
where TPixel : struct, IPixel<TPixel>
=> source.Glow(options, color, ValueSize.Absolute(radius), rectangle);
public static IImageProcessingContext Glow(
this IImageProcessingContext source,
GraphicsOptions options,
Color color,
float radius,
Rectangle rectangle) =>
source.Glow(options, color, ValueSize.Absolute(radius), rectangle);
/// <summary>
/// Applies a radial glow effect to an image.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="options">The options effecting things like blending.</param>
/// <param name="color">The color to set as the glow.</param>
@ -153,21 +149,27 @@ namespace SixLabors.ImageSharp.Processing
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to alter.
/// </param>
/// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
private static IImageProcessingContext<TPixel> Glow<TPixel>(this IImageProcessingContext<TPixel> source, GraphicsOptions options, TPixel color, ValueSize radius, Rectangle rectangle)
where TPixel : struct, IPixel<TPixel>
=> source.ApplyProcessor(new GlowProcessor<TPixel>(color, radius, options), rectangle);
private static IImageProcessingContext Glow(
this IImageProcessingContext source,
GraphicsOptions options,
Color color,
ValueSize radius,
Rectangle rectangle) =>
source.ApplyProcessor(new GlowProcessor(color, radius, options), rectangle);
/// <summary>
/// Applies a radial glow effect to an image.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="options">The options effecting things like blending.</param>
/// <param name="color">The color to set as the glow.</param>
/// <param name="radius">The the radius.</param>
/// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
private static IImageProcessingContext<TPixel> Glow<TPixel>(this IImageProcessingContext<TPixel> source, GraphicsOptions options, TPixel color, ValueSize radius)
where TPixel : struct, IPixel<TPixel>
=> source.ApplyProcessor(new GlowProcessor<TPixel>(color, radius, options));
private static IImageProcessingContext Glow(
this IImageProcessingContext source,
GraphicsOptions options,
Color color,
ValueSize radius) =>
source.ApplyProcessor(new GlowProcessor(color, radius, options));
}
}

4
src/ImageSharp/Processing/Processors/Filters/LomographProcessor{TPixel}.cs

@ -13,7 +13,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Filters
internal class LomographProcessor<TPixel> : FilterProcessor<TPixel>
where TPixel : struct, IPixel<TPixel>
{
private static readonly TPixel VeryDarkGreen = ColorBuilder<TPixel>.FromRGBA(0, 10, 0, 255);
private static readonly Color VeryDarkGreen = Color.FromRgba(0, 10, 0, 255);
/// <summary>
/// Initializes a new instance of the <see cref="LomographProcessor{TPixel}"/> class.
@ -27,7 +27,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Filters
/// <inheritdoc/>
protected override void AfterFrameApply(ImageFrame<TPixel> source, Rectangle sourceRectangle, Configuration configuration)
{
new VignetteProcessor<TPixel>(VeryDarkGreen).Apply(source, sourceRectangle, configuration);
new VignetteProcessor(VeryDarkGreen).Apply(source, sourceRectangle, configuration);
}
}
}

14
src/ImageSharp/Processing/Processors/Filters/PolaroidProcessor{TPixel}.cs

@ -13,8 +13,9 @@ namespace SixLabors.ImageSharp.Processing.Processors.Filters
internal class PolaroidProcessor<TPixel> : FilterProcessor<TPixel>
where TPixel : struct, IPixel<TPixel>
{
private static readonly TPixel VeryDarkOrange = ColorBuilder<TPixel>.FromRGB(102, 34, 0);
private static readonly TPixel LightOrange = ColorBuilder<TPixel>.FromRGBA(255, 153, 102, 128);
private static readonly Color LightOrange = Color.FromRgba(255, 153, 102, 128);
private static readonly Color VeryDarkOrange = Color.FromRgb(102, 34, 0);
/// <summary>
/// Initializes a new instance of the <see cref="PolaroidProcessor{TPixel}"/> class.
@ -26,10 +27,13 @@ namespace SixLabors.ImageSharp.Processing.Processors.Filters
}
/// <inheritdoc/>
protected override void AfterFrameApply(ImageFrame<TPixel> source, Rectangle sourceRectangle, Configuration configuration)
protected override void AfterFrameApply(
ImageFrame<TPixel> source,
Rectangle sourceRectangle,
Configuration configuration)
{
new VignetteProcessor<TPixel>(VeryDarkOrange).Apply(source, sourceRectangle, configuration);
new GlowProcessor<TPixel>(LightOrange, source.Width / 4F).Apply(source, sourceRectangle, configuration);
new VignetteProcessor(VeryDarkOrange).Apply(source, sourceRectangle, configuration);
new GlowProcessor(LightOrange, source.Width / 4F).Apply(source, sourceRectangle, configuration);
}
}
}

86
src/ImageSharp/Processing/Processors/Overlays/BackgroundColorProcessor.cs

@ -1,31 +1,21 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
using System.Buffers;
using System.Threading.Tasks;
using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.ParallelUtils;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.Memory;
using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing.Processors.Overlays
{
/// <summary>
/// Sets the background color of the image.
/// Defines a processing operation to replace the background color of an <see cref="Image"/>.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
internal class BackgroundColorProcessor<TPixel> : ImageProcessor<TPixel>
where TPixel : struct, IPixel<TPixel>
public sealed class BackgroundColorProcessor : IImageProcessor
{
/// <summary>
/// Initializes a new instance of the <see cref="BackgroundColorProcessor{TPixel}"/> class.
/// Initializes a new instance of the <see cref="BackgroundColorProcessor"/> class.
/// </summary>
/// <param name="color">The <typeparamref name="TPixel"/> to set the background color to.</param>
/// <param name="color">The <see cref="Color"/> to set the background color to.</param>
/// <param name="options">The options defining blending algorithm and amount.</param>
public BackgroundColorProcessor(TPixel color, GraphicsOptions options)
public BackgroundColorProcessor(Color color, GraphicsOptions options)
{
this.Color = color;
this.GraphicsOptions = options;
@ -39,69 +29,13 @@ namespace SixLabors.ImageSharp.Processing.Processors.Overlays
/// <summary>
/// Gets the background color value.
/// </summary>
public TPixel Color { get; }
public Color Color { get; }
/// <inheritdoc/>
protected override void OnFrameApply(ImageFrame<TPixel> source, Rectangle sourceRectangle, Configuration configuration)
/// <inheritdoc />
public IImageProcessor<TPixel> CreatePixelSpecificProcessor<TPixel>()
where TPixel : struct, IPixel<TPixel>
{
int startY = sourceRectangle.Y;
int endY = sourceRectangle.Bottom;
int startX = sourceRectangle.X;
int endX = sourceRectangle.Right;
// Align start/end positions.
int minX = Math.Max(0, startX);
int maxX = Math.Min(source.Width, endX);
int minY = Math.Max(0, startY);
int maxY = Math.Min(source.Height, endY);
// Reset offset if necessary.
if (minX > 0)
{
startX = 0;
}
if (minY > 0)
{
startY = 0;
}
int width = maxX - minX;
var workingRect = Rectangle.FromLTRB(minX, minY, maxX, maxY);
using (IMemoryOwner<TPixel> colors = source.MemoryAllocator.Allocate<TPixel>(width))
using (IMemoryOwner<float> amount = source.MemoryAllocator.Allocate<float>(width))
{
// Be careful! Do not capture colorSpan & amountSpan in the lambda below!
Span<TPixel> colorSpan = colors.GetSpan();
Span<float> amountSpan = amount.GetSpan();
colorSpan.Fill(this.Color);
amountSpan.Fill(this.GraphicsOptions.BlendPercentage);
PixelBlender<TPixel> blender = PixelOperations<TPixel>.Instance.GetPixelBlender(this.GraphicsOptions);
ParallelHelper.IterateRows(
workingRect,
configuration,
rows =>
{
for (int y = rows.Min; y < rows.Max; y++)
{
Span<TPixel> destination =
source.GetPixelRowSpan(y - startY).Slice(minX - startX, width);
// This switched color & destination in the 2nd and 3rd places because we are applying the target color under the current one
blender.Blend(
source.Configuration,
destination,
colors.GetSpan(),
destination,
amount.GetSpan());
}
});
}
return new BackgroundColorProcessor<TPixel>(this);
}
}
}

101
src/ImageSharp/Processing/Processors/Overlays/BackgroundColorProcessor{TPixel}.cs

@ -0,0 +1,101 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
using System.Buffers;
using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.ParallelUtils;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing.Processors.Overlays
{
/// <summary>
/// Sets the background color of the image.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
internal class BackgroundColorProcessor<TPixel> : ImageProcessor<TPixel>
where TPixel : struct, IPixel<TPixel>
{
private readonly BackgroundColorProcessor definition;
/// <summary>
/// Initializes a new instance of the <see cref="BackgroundColorProcessor{TPixel}"/> class.
/// </summary>
public BackgroundColorProcessor(BackgroundColorProcessor definition)
{
this.definition = definition;
}
/// <inheritdoc/>
protected override void OnFrameApply(
ImageFrame<TPixel> source,
Rectangle sourceRectangle,
Configuration configuration)
{
TPixel color = this.definition.Color.ToPixel<TPixel>();
GraphicsOptions graphicsOptions = this.definition.GraphicsOptions;
int startY = sourceRectangle.Y;
int endY = sourceRectangle.Bottom;
int startX = sourceRectangle.X;
int endX = sourceRectangle.Right;
// Align start/end positions.
int minX = Math.Max(0, startX);
int maxX = Math.Min(source.Width, endX);
int minY = Math.Max(0, startY);
int maxY = Math.Min(source.Height, endY);
// Reset offset if necessary.
if (minX > 0)
{
startX = 0;
}
if (minY > 0)
{
startY = 0;
}
int width = maxX - minX;
var workingRect = Rectangle.FromLTRB(minX, minY, maxX, maxY);
using (IMemoryOwner<TPixel> colors = source.MemoryAllocator.Allocate<TPixel>(width))
using (IMemoryOwner<float> amount = source.MemoryAllocator.Allocate<float>(width))
{
// Be careful! Do not capture colorSpan & amountSpan in the lambda below!
Span<TPixel> colorSpan = colors.GetSpan();
Span<float> amountSpan = amount.GetSpan();
colorSpan.Fill(color);
amountSpan.Fill(graphicsOptions.BlendPercentage);
PixelBlender<TPixel> blender = PixelOperations<TPixel>.Instance.GetPixelBlender(graphicsOptions);
ParallelHelper.IterateRows(
workingRect,
configuration,
rows =>
{
for (int y = rows.Min; y < rows.Max; y++)
{
Span<TPixel> destination =
source.GetPixelRowSpan(y - startY).Slice(minX - startX, width);
// This switched color & destination in the 2nd and 3rd places because we are applying the target color under the current one
blender.Blend(
source.Configuration,
destination,
colors.GetSpan(),
destination,
amount.GetSpan());
}
});
}
}
}
}

125
src/ImageSharp/Processing/Processors/Overlays/GlowProcessor.cs

@ -1,69 +1,56 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
using System.Buffers;
using System.Numerics;
using System.Threading.Tasks;
using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.ParallelUtils;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Primitives;
using SixLabors.Memory;
using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing.Processors.Overlays
{
/// <summary>
/// An <see cref="IImageProcessor{TPixel}"/> that applies a radial glow effect an <see cref="Image{TPixel}"/>.
/// Defines a radial glow effect applicable to an <see cref="Image"/>.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
internal class GlowProcessor<TPixel> : ImageProcessor<TPixel>
where TPixel : struct, IPixel<TPixel>
public sealed class GlowProcessor : IImageProcessor
{
private readonly PixelBlender<TPixel> blender;
/// <summary>
/// Initializes a new instance of the <see cref="GlowProcessor{TPixel}" /> class.
/// Initializes a new instance of the <see cref="GlowProcessor" /> class.
/// </summary>
/// <param name="color">The color or the glow.</param>
public GlowProcessor(TPixel color)
public GlowProcessor(Color color)
: this(color, 0)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="GlowProcessor{TPixel}" /> class.
/// Initializes a new instance of the <see cref="GlowProcessor" /> class.
/// </summary>
/// <param name="color">The color or the glow.</param>
/// <param name="radius">The radius of the glow.</param>
public GlowProcessor(TPixel color, ValueSize radius)
: this(color, radius, GraphicsOptions.Default)
/// <param name="options">The options effecting blending and composition.</param>
public GlowProcessor(Color color, GraphicsOptions options)
: this(color, 0, options)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="GlowProcessor{TPixel}" /> class.
/// Initializes a new instance of the <see cref="GlowProcessor" /> class.
/// </summary>
/// <param name="color">The color or the glow.</param>
/// <param name="options">The options effecting blending and composition.</param>
public GlowProcessor(TPixel color, GraphicsOptions options)
: this(color, 0, options)
/// <param name="radius">The radius of the glow.</param>
internal GlowProcessor(Color color, ValueSize radius)
: this(color, radius, GraphicsOptions.Default)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="GlowProcessor{TPixel}" /> class.
/// Initializes a new instance of the <see cref="GlowProcessor" /> class.
/// </summary>
/// <param name="color">The color or the glow.</param>
/// <param name="radius">The radius of the glow.</param>
/// <param name="options">The options effecting blending and composition.</param>
public GlowProcessor(TPixel color, ValueSize radius, GraphicsOptions options)
internal GlowProcessor(Color color, ValueSize radius, GraphicsOptions options)
{
this.GlowColor = color;
this.Radius = radius;
this.blender = PixelOperations<TPixel>.Instance.GetPixelBlender(options);
this.GraphicsOptions = options;
}
@ -73,86 +60,20 @@ namespace SixLabors.ImageSharp.Processing.Processors.Overlays
public GraphicsOptions GraphicsOptions { get; }
/// <summary>
/// Gets or sets the glow color to apply.
/// Gets the glow color to apply.
/// </summary>
public TPixel GlowColor { get; set; }
public Color GlowColor { get; }
/// <summary>
/// Gets or sets the the radius.
/// Gets the the radius.
/// </summary>
public ValueSize Radius { get; set; }
internal ValueSize Radius { get; }
/// <inheritdoc/>
protected override void OnFrameApply(ImageFrame<TPixel> source, Rectangle sourceRectangle, Configuration configuration)
/// <inheritdoc />
public IImageProcessor<TPixel> CreatePixelSpecificProcessor<TPixel>()
where TPixel : struct, IPixel<TPixel>
{
// TODO: can we simplify the rectangle calculation?
int startY = sourceRectangle.Y;
int endY = sourceRectangle.Bottom;
int startX = sourceRectangle.X;
int endX = sourceRectangle.Right;
TPixel glowColor = this.GlowColor;
Vector2 center = Rectangle.Center(sourceRectangle);
float finalRadius = this.Radius.Calculate(source.Size());
float maxDistance = finalRadius > 0 ? MathF.Min(finalRadius, sourceRectangle.Width * .5F) : sourceRectangle.Width * .5F;
// Align start/end positions.
int minX = Math.Max(0, startX);
int maxX = Math.Min(source.Width, endX);
int minY = Math.Max(0, startY);
int maxY = Math.Min(source.Height, endY);
// Reset offset if necessary.
if (minX > 0)
{
startX = 0;
}
if (minY > 0)
{
startY = 0;
}
int width = maxX - minX;
int offsetX = minX - startX;
var workingRect = Rectangle.FromLTRB(minX, minY, maxX, maxY);
using (IMemoryOwner<TPixel> rowColors = source.MemoryAllocator.Allocate<TPixel>(width))
{
rowColors.GetSpan().Fill(glowColor);
ParallelHelper.IterateRowsWithTempBuffer<float>(
workingRect,
configuration,
(rows, amounts) =>
{
Span<float> amountsSpan = amounts.Span;
for (int y = rows.Min; y < rows.Max; y++)
{
int offsetY = y - startY;
for (int i = 0; i < width; i++)
{
float distance = Vector2.Distance(center, new Vector2(i + offsetX, offsetY));
amountsSpan[i] =
(this.GraphicsOptions.BlendPercentage * (1 - (.95F * (distance / maxDistance))))
.Clamp(0, 1);
}
Span<TPixel> destination = source.GetPixelRowSpan(offsetY).Slice(offsetX, width);
this.blender.Blend(
source.Configuration,
destination,
destination,
rowColors.GetSpan(),
amountsSpan);
}
});
}
return new GlowProcessor<TPixel>(this);
}
}
}

112
src/ImageSharp/Processing/Processors/Overlays/GlowProcessor{TPixel}.cs

@ -0,0 +1,112 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
using System.Buffers;
using System.Numerics;
using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.ParallelUtils;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing.Processors.Overlays
{
/// <summary>
/// An <see cref="IImageProcessor{TPixel}"/> that applies a radial glow effect an <see cref="Image{TPixel}"/>.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
internal class GlowProcessor<TPixel> : ImageProcessor<TPixel>
where TPixel : struct, IPixel<TPixel>
{
private readonly PixelBlender<TPixel> blender;
private readonly GlowProcessor definition;
public GlowProcessor(GlowProcessor definition)
{
this.definition = definition;
this.blender = PixelOperations<TPixel>.Instance.GetPixelBlender(definition.GraphicsOptions);
}
/// <inheritdoc/>
protected override void OnFrameApply(
ImageFrame<TPixel> source,
Rectangle sourceRectangle,
Configuration configuration)
{
// TODO: can we simplify the rectangle calculation?
int startY = sourceRectangle.Y;
int endY = sourceRectangle.Bottom;
int startX = sourceRectangle.X;
int endX = sourceRectangle.Right;
TPixel glowColor = this.definition.GlowColor.ToPixel<TPixel>();
Vector2 center = Rectangle.Center(sourceRectangle);
float finalRadius = this.definition.Radius.Calculate(source.Size());
float maxDistance = finalRadius > 0
? MathF.Min(finalRadius, sourceRectangle.Width * .5F)
: sourceRectangle.Width * .5F;
// Align start/end positions.
int minX = Math.Max(0, startX);
int maxX = Math.Min(source.Width, endX);
int minY = Math.Max(0, startY);
int maxY = Math.Min(source.Height, endY);
// Reset offset if necessary.
if (minX > 0)
{
startX = 0;
}
if (minY > 0)
{
startY = 0;
}
int width = maxX - minX;
int offsetX = minX - startX;
var workingRect = Rectangle.FromLTRB(minX, minY, maxX, maxY);
float blendPercentage = this.definition.GraphicsOptions.BlendPercentage;
using (IMemoryOwner<TPixel> rowColors = source.MemoryAllocator.Allocate<TPixel>(width))
{
rowColors.GetSpan().Fill(glowColor);
ParallelHelper.IterateRowsWithTempBuffer<float>(
workingRect,
configuration,
(rows, amounts) =>
{
Span<float> amountsSpan = amounts.Span;
for (int y = rows.Min; y < rows.Max; y++)
{
int offsetY = y - startY;
for (int i = 0; i < width; i++)
{
float distance = Vector2.Distance(center, new Vector2(i + offsetX, offsetY));
amountsSpan[i] =
(blendPercentage * (1 - (.95F * (distance / maxDistance)))).Clamp(0, 1);
}
Span<TPixel> destination = source.GetPixelRowSpan(offsetY).Slice(offsetX, width);
this.blender.Blend(
source.Configuration,
destination,
destination,
rowColors.GetSpan(),
amountsSpan);
}
});
}
}
}
}

120
src/ImageSharp/Processing/Processors/Overlays/VignetteProcessor.cs

@ -1,63 +1,48 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
using System.Buffers;
using System.Numerics;
using System.Threading.Tasks;
using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.ParallelUtils;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Primitives;
using SixLabors.Memory;
using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing.Processors.Overlays
{
/// <summary>
/// An <see cref="IImageProcessor{TPixel}"/> that applies a radial vignette effect to an <see cref="Image{TPixel}"/>.
/// Defines a radial vignette effect applicable to an <see cref="Image"/>.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
internal class VignetteProcessor<TPixel> : ImageProcessor<TPixel>
where TPixel : struct, IPixel<TPixel>
public sealed class VignetteProcessor : IImageProcessor
{
private readonly PixelBlender<TPixel> blender;
/// <summary>
/// Initializes a new instance of the <see cref="VignetteProcessor{TPixel}" /> class.
/// Initializes a new instance of the <see cref="VignetteProcessor" /> class.
/// </summary>
/// <param name="color">The color of the vignette.</param>
public VignetteProcessor(TPixel color)
public VignetteProcessor(Color color)
: this(color, GraphicsOptions.Default)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="VignetteProcessor{TPixel}" /> class.
/// Initializes a new instance of the <see cref="VignetteProcessor" /> class.
/// </summary>
/// <param name="color">The color of the vignette.</param>
/// <param name="options">The options effecting blending and composition.</param>
public VignetteProcessor(TPixel color, GraphicsOptions options)
public VignetteProcessor(Color color, GraphicsOptions options)
{
this.VignetteColor = color;
this.GraphicsOptions = options;
this.blender = PixelOperations<TPixel>.Instance.GetPixelBlender(options);
}
/// <summary>
/// Initializes a new instance of the <see cref="VignetteProcessor{TPixel}" /> class.
/// Initializes a new instance of the <see cref="VignetteProcessor" /> class.
/// </summary>
/// <param name="color">The color of the vignette.</param>
/// <param name="radiusX">The x-radius.</param>
/// <param name="radiusY">The y-radius.</param>
/// <param name="options">The options effecting blending and composition.</param>
public VignetteProcessor(TPixel color, ValueSize radiusX, ValueSize radiusY, GraphicsOptions options)
internal VignetteProcessor(Color color, ValueSize radiusX, ValueSize radiusY, GraphicsOptions options)
{
this.VignetteColor = color;
this.RadiusX = radiusX;
this.RadiusY = radiusY;
this.blender = PixelOperations<TPixel>.Instance.GetPixelBlender(options);
this.GraphicsOptions = options;
}
@ -67,94 +52,25 @@ namespace SixLabors.ImageSharp.Processing.Processors.Overlays
public GraphicsOptions GraphicsOptions { get; }
/// <summary>
/// Gets or sets the vignette color to apply.
/// Gets the vignette color to apply.
/// </summary>
public TPixel VignetteColor { get; set; }
public Color VignetteColor { get; }
/// <summary>
/// Gets or sets the the x-radius.
/// Gets the the x-radius.
/// </summary>
public ValueSize RadiusX { get; set; }
internal ValueSize RadiusX { get; }
/// <summary>
/// Gets or sets the the y-radius.
/// Gets the the y-radius.
/// </summary>
public ValueSize RadiusY { get; set; }
internal ValueSize RadiusY { get; }
/// <inheritdoc/>
protected override void OnFrameApply(ImageFrame<TPixel> source, Rectangle sourceRectangle, Configuration configuration)
/// <inheritdoc />
public IImageProcessor<TPixel> CreatePixelSpecificProcessor<TPixel>()
where TPixel : struct, IPixel<TPixel>
{
int startY = sourceRectangle.Y;
int endY = sourceRectangle.Bottom;
int startX = sourceRectangle.X;
int endX = sourceRectangle.Right;
TPixel vignetteColor = this.VignetteColor;
Vector2 centre = Rectangle.Center(sourceRectangle);
Size sourceSize = source.Size();
float finalRadiusX = this.RadiusX.Calculate(sourceSize);
float finalRadiusY = this.RadiusY.Calculate(sourceSize);
float rX = finalRadiusX > 0 ? MathF.Min(finalRadiusX, sourceRectangle.Width * .5F) : sourceRectangle.Width * .5F;
float rY = finalRadiusY > 0 ? MathF.Min(finalRadiusY, sourceRectangle.Height * .5F) : sourceRectangle.Height * .5F;
float maxDistance = MathF.Sqrt((rX * rX) + (rY * rY));
// Align start/end positions.
int minX = Math.Max(0, startX);
int maxX = Math.Min(source.Width, endX);
int minY = Math.Max(0, startY);
int maxY = Math.Min(source.Height, endY);
// Reset offset if necessary.
if (minX > 0)
{
startX = 0;
}
if (minY > 0)
{
startY = 0;
}
int width = maxX - minX;
int offsetX = minX - startX;
var workingRect = Rectangle.FromLTRB(minX, minY, maxX, maxY);
using (IMemoryOwner<TPixel> rowColors = source.MemoryAllocator.Allocate<TPixel>(width))
{
rowColors.GetSpan().Fill(vignetteColor);
ParallelHelper.IterateRowsWithTempBuffer<float>(
workingRect,
configuration,
(rows, amounts) =>
{
Span<float> amountsSpan = amounts.Span;
for (int y = rows.Min; y < rows.Max; y++)
{
int offsetY = y - startY;
for (int i = 0; i < width; i++)
{
float distance = Vector2.Distance(centre, new Vector2(i + offsetX, offsetY));
amountsSpan[i] =
(this.GraphicsOptions.BlendPercentage * (.9F * (distance / maxDistance))).Clamp(
0,
1);
}
Span<TPixel> destination = source.GetPixelRowSpan(offsetY).Slice(offsetX, width);
this.blender.Blend(
source.Configuration,
destination,
destination,
rowColors.GetSpan(),
amountsSpan);
}
});
}
return new VignetteProcessor<TPixel>(this);
}
}
}

114
src/ImageSharp/Processing/Processors/Overlays/VignetteProcessor{TPixel}.cs

@ -0,0 +1,114 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
using System.Buffers;
using System.Numerics;
using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.ParallelUtils;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing.Processors.Overlays
{
/// <summary>
/// An <see cref="IImageProcessor{TPixel}"/> that applies a radial vignette effect to an <see cref="Image{TPixel}"/>.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
internal class VignetteProcessor<TPixel> : ImageProcessor<TPixel>
where TPixel : struct, IPixel<TPixel>
{
private readonly PixelBlender<TPixel> blender;
private readonly VignetteProcessor definition;
public VignetteProcessor(VignetteProcessor definition)
{
this.definition = definition;
this.blender = PixelOperations<TPixel>.Instance.GetPixelBlender(definition.GraphicsOptions);
}
/// <inheritdoc/>
protected override void OnFrameApply(
ImageFrame<TPixel> source,
Rectangle sourceRectangle,
Configuration configuration)
{
int startY = sourceRectangle.Y;
int endY = sourceRectangle.Bottom;
int startX = sourceRectangle.X;
int endX = sourceRectangle.Right;
TPixel vignetteColor = this.definition.VignetteColor.ToPixel<TPixel>();
Vector2 centre = Rectangle.Center(sourceRectangle);
Size sourceSize = source.Size();
float finalRadiusX = this.definition.RadiusX.Calculate(sourceSize);
float finalRadiusY = this.definition.RadiusY.Calculate(sourceSize);
float rX = finalRadiusX > 0
? MathF.Min(finalRadiusX, sourceRectangle.Width * .5F)
: sourceRectangle.Width * .5F;
float rY = finalRadiusY > 0
? MathF.Min(finalRadiusY, sourceRectangle.Height * .5F)
: sourceRectangle.Height * .5F;
float maxDistance = MathF.Sqrt((rX * rX) + (rY * rY));
// Align start/end positions.
int minX = Math.Max(0, startX);
int maxX = Math.Min(source.Width, endX);
int minY = Math.Max(0, startY);
int maxY = Math.Min(source.Height, endY);
// Reset offset if necessary.
if (minX > 0)
{
startX = 0;
}
if (minY > 0)
{
startY = 0;
}
int width = maxX - minX;
int offsetX = minX - startX;
var workingRect = Rectangle.FromLTRB(minX, minY, maxX, maxY);
float blendPercentage = this.definition.GraphicsOptions.BlendPercentage;
using (IMemoryOwner<TPixel> rowColors = source.MemoryAllocator.Allocate<TPixel>(width))
{
rowColors.GetSpan().Fill(vignetteColor);
ParallelHelper.IterateRowsWithTempBuffer<float>(
workingRect,
configuration,
(rows, amounts) =>
{
Span<float> amountsSpan = amounts.Span;
for (int y = rows.Min; y < rows.Max; y++)
{
int offsetY = y - startY;
for (int i = 0; i < width; i++)
{
float distance = Vector2.Distance(centre, new Vector2(i + offsetX, offsetY));
amountsSpan[i] = (blendPercentage * (.9F * (distance / maxDistance))).Clamp(0, 1);
}
Span<TPixel> destination = source.GetPixelRowSpan(offsetY).Slice(offsetX, width);
this.blender.Blend(
source.Configuration,
destination,
destination,
rowColors.GetSpan(),
amountsSpan);
}
});
}
}
}
}

121
src/ImageSharp/Processing/VignetteExtensions.cs

@ -1,7 +1,6 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Primitives;
using SixLabors.ImageSharp.Processing.Processors.Overlays;
using SixLabors.Primitives;
@ -9,7 +8,7 @@ using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing
{
/// <summary>
/// Defines extensions that allow the application of a radial glow to an <see cref="Image{TPixel}"/>
/// Defines extensions that allow the application of a radial glow to an <see cref="Image"/>
/// using Mutate/Clone.
/// </summary>
public static class VignetteExtensions
@ -17,53 +16,47 @@ namespace SixLabors.ImageSharp.Processing
/// <summary>
/// Applies a radial vignette effect to an image.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
public static IImageProcessingContext<TPixel> Vignette<TPixel>(this IImageProcessingContext<TPixel> source)
where TPixel : struct, IPixel<TPixel>
=> Vignette(source, GraphicsOptions.Default);
public static IImageProcessingContext Vignette(this IImageProcessingContext source) =>
Vignette(source, GraphicsOptions.Default);
/// <summary>
/// Applies a radial vignette effect to an image.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <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<TPixel> Vignette<TPixel>(this IImageProcessingContext<TPixel> source, TPixel color)
where TPixel : struct, IPixel<TPixel>
=> Vignette(source, GraphicsOptions.Default, color);
public static IImageProcessingContext Vignette(this IImageProcessingContext source, Color color) =>
Vignette(source, GraphicsOptions.Default, color);
/// <summary>
/// Applies a radial vignette effect to an image.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="radiusX">The the x-radius.</param>
/// <param name="radiusY">The the y-radius.</param>
/// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
public static IImageProcessingContext<TPixel> Vignette<TPixel>(this IImageProcessingContext<TPixel> source, float radiusX, float radiusY)
where TPixel : struct, IPixel<TPixel>
=> Vignette(source, GraphicsOptions.Default, radiusX, radiusY);
public static IImageProcessingContext Vignette(
this IImageProcessingContext source,
float radiusX,
float radiusY) =>
Vignette(source, GraphicsOptions.Default, radiusX, radiusY);
/// <summary>
/// Applies a radial vignette effect to an image.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="rectangle">
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to alter.
/// </param>
/// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
public static IImageProcessingContext<TPixel> Vignette<TPixel>(this IImageProcessingContext<TPixel> source, Rectangle rectangle)
where TPixel : struct, IPixel<TPixel>
=> Vignette(source, GraphicsOptions.Default, rectangle);
public static IImageProcessingContext Vignette(this IImageProcessingContext source, Rectangle rectangle) =>
Vignette(source, GraphicsOptions.Default, rectangle);
/// <summary>
/// Applies a radial vignette effect to an image.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="color">The color to set as the vignette.</param>
/// <param name="radiusX">The the x-radius.</param>
@ -72,64 +65,82 @@ namespace SixLabors.ImageSharp.Processing
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to alter.
/// </param>
/// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
public static IImageProcessingContext<TPixel> Vignette<TPixel>(this IImageProcessingContext<TPixel> source, TPixel color, float radiusX, float radiusY, Rectangle rectangle)
where TPixel : struct, IPixel<TPixel>
=> source.Vignette(GraphicsOptions.Default, color, radiusX, radiusY, rectangle);
public static IImageProcessingContext Vignette(
this IImageProcessingContext source,
Color color,
float radiusX,
float radiusY,
Rectangle rectangle) =>
source.Vignette(GraphicsOptions.Default, color, radiusX, radiusY, rectangle);
/// <summary>
/// Applies a radial vignette effect to an image.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="options">The options effecting pixel blending.</param>
/// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
public static IImageProcessingContext<TPixel> Vignette<TPixel>(this IImageProcessingContext<TPixel> source, GraphicsOptions options)
where TPixel : struct, IPixel<TPixel>
=> source.VignetteInternal(options, NamedColors<TPixel>.Black, ValueSize.PercentageOfWidth(.5f), ValueSize.PercentageOfHeight(.5f));
public static IImageProcessingContext Vignette(this IImageProcessingContext source, GraphicsOptions options) =>
source.VignetteInternal(
options,
Color.Black,
ValueSize.PercentageOfWidth(.5f),
ValueSize.PercentageOfHeight(.5f));
/// <summary>
/// Applies a radial vignette effect to an image.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="options">The options effecting pixel blending.</param>
/// <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<TPixel> Vignette<TPixel>(this IImageProcessingContext<TPixel> source, GraphicsOptions options, TPixel color)
where TPixel : struct, IPixel<TPixel>
=> source.VignetteInternal(options, color, ValueSize.PercentageOfWidth(.5f), ValueSize.PercentageOfHeight(.5f));
public static IImageProcessingContext Vignette(
this IImageProcessingContext source,
GraphicsOptions options,
Color color) =>
source.VignetteInternal(
options,
color,
ValueSize.PercentageOfWidth(.5f),
ValueSize.PercentageOfHeight(.5f));
/// <summary>
/// Applies a radial vignette effect to an image.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="options">The options effecting pixel blending.</param>
/// <param name="radiusX">The the x-radius.</param>
/// <param name="radiusY">The the y-radius.</param>
/// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
public static IImageProcessingContext<TPixel> Vignette<TPixel>(this IImageProcessingContext<TPixel> source, GraphicsOptions options, float radiusX, float radiusY)
where TPixel : struct, IPixel<TPixel>
=> source.VignetteInternal(options, NamedColors<TPixel>.Black, radiusX, radiusY);
public static IImageProcessingContext Vignette(
this IImageProcessingContext source,
GraphicsOptions options,
float radiusX,
float radiusY) =>
source.VignetteInternal(options, Color.Black, radiusX, radiusY);
/// <summary>
/// Applies a radial vignette effect to an image.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="options">The options effecting pixel blending.</param>
/// <param name="rectangle">
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to alter.
/// </param>
/// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
public static IImageProcessingContext<TPixel> Vignette<TPixel>(this IImageProcessingContext<TPixel> source, GraphicsOptions options, Rectangle rectangle)
where TPixel : struct, IPixel<TPixel>
=> source.VignetteInternal(options, NamedColors<TPixel>.Black, ValueSize.PercentageOfWidth(.5f), ValueSize.PercentageOfHeight(.5f), rectangle);
public static IImageProcessingContext Vignette(
this IImageProcessingContext source,
GraphicsOptions options,
Rectangle rectangle) =>
source.VignetteInternal(
options,
Color.Black,
ValueSize.PercentageOfWidth(.5f),
ValueSize.PercentageOfHeight(.5f),
rectangle);
/// <summary>
/// Applies a radial vignette effect to an image.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="options">The options effecting pixel blending.</param>
/// <param name="color">The color to set as the vignette.</param>
@ -139,16 +150,30 @@ namespace SixLabors.ImageSharp.Processing
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to alter.
/// </param>
/// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
public static IImageProcessingContext<TPixel> Vignette<TPixel>(this IImageProcessingContext<TPixel> source, GraphicsOptions options, TPixel color, float radiusX, float radiusY, Rectangle rectangle)
where TPixel : struct, IPixel<TPixel>
=> source.VignetteInternal(options, color, radiusX, radiusY, rectangle);
public static IImageProcessingContext Vignette(
this IImageProcessingContext source,
GraphicsOptions options,
Color color,
float radiusX,
float radiusY,
Rectangle rectangle) =>
source.VignetteInternal(options, color, radiusX, radiusY, rectangle);
private static IImageProcessingContext<TPixel> VignetteInternal<TPixel>(this IImageProcessingContext<TPixel> source, GraphicsOptions options, TPixel color, ValueSize radiusX, ValueSize radiusY, Rectangle rectangle)
where TPixel : struct, IPixel<TPixel>
=> source.ApplyProcessor(new VignetteProcessor<TPixel>(color, radiusX, radiusY, options), rectangle);
private static IImageProcessingContext VignetteInternal(
this IImageProcessingContext source,
GraphicsOptions options,
Color color,
ValueSize radiusX,
ValueSize radiusY,
Rectangle rectangle) =>
source.ApplyProcessor(new VignetteProcessor(color, radiusX, radiusY, options), rectangle);
private static IImageProcessingContext<TPixel> VignetteInternal<TPixel>(this IImageProcessingContext<TPixel> source, GraphicsOptions options, TPixel color, ValueSize radiusX, ValueSize radiusY)
where TPixel : struct, IPixel<TPixel>
=> source.ApplyProcessor(new VignetteProcessor<TPixel>(color, radiusX, radiusY, options));
private static IImageProcessingContext VignetteInternal(
this IImageProcessingContext source,
GraphicsOptions options,
Color color,
ValueSize radiusX,
ValueSize radiusY) =>
source.ApplyProcessor(new VignetteProcessor(color, radiusX, radiusY, options));
}
}

4
tests/ImageSharp.Benchmarks/Samplers/Glow.cs

@ -20,14 +20,14 @@ namespace SixLabors.ImageSharp.Benchmarks
public class Glow : BenchmarkBase
{
private GlowProcessor<Rgba32> bulk;
private GlowProcessor bulk;
private GlowProcessorParallel<Rgba32> parallel;
[GlobalSetup]
public void Setup()
{
this.bulk = new GlowProcessor<Rgba32>(NamedColors<Rgba32>.Beige, 800 * .5f, GraphicsOptions.Default);
this.bulk = new GlowProcessor(Color.Beige, 800 * .5f, GraphicsOptions.Default);
this.parallel = new GlowProcessorParallel<Rgba32>(NamedColors<Rgba32>.Beige) { Radius = 800 * .5f, };
}

6
tests/ImageSharp.Tests/Drawing/BeziersTests.cs

@ -19,8 +19,9 @@ namespace SixLabors.ImageSharp.Tests.Drawing
string path = TestEnvironment.CreateOutputDirectory("Drawing", "BezierLine");
using (var image = new Image<Rgba32>(500, 500))
{
image.Mutate(x => x.BackgroundColor(Color.Blue));
image.Mutate(
x => x.BackgroundColor(Rgba32.Blue).DrawBeziers(
x => x.DrawBeziers(
Rgba32.HotPink,
5,
new SixLabors.Primitives.PointF[]
@ -56,8 +57,9 @@ namespace SixLabors.ImageSharp.Tests.Drawing
using (var image = new Image<Rgba32>(500, 500))
{
image.Mutate(x => x.BackgroundColor(Color.Blue));
image.Mutate(
x => x.BackgroundColor(Rgba32.Blue).DrawBeziers(
x => x.DrawBeziers(
color,
10,
new SixLabors.Primitives.PointF[]

2
tests/ImageSharp.Tests/Drawing/DrawImageTest.cs

@ -80,7 +80,7 @@ namespace SixLabors.ImageSharp.Tests
// Apply a background color so we can see the translation.
blend.Mutate(x => x.Transform(builder));
blend.Mutate(x => x.BackgroundColor(NamedColors<TPixel>.HotPink));
blend.Mutate(x => x.BackgroundColor(Color.HotPink));
// Lets center the matrix so we can tell whether any cut-off issues we may have belong to the drawing processor
var position = new Point((image.Width - blend.Width) / 2, (image.Height - blend.Height) / 2);

8
tests/ImageSharp.Tests/Drawing/DrawPathTests.cs

@ -30,8 +30,9 @@ namespace SixLabors.ImageSharp.Tests.Drawing
new Vector2(10, 400));
var p = new Path(linerSegemnt, bazierSegment);
image.Mutate(x => x.BackgroundColor(Rgba32.Blue).Draw(Rgba32.HotPink, 5, p));
image.Mutate(x => x.BackgroundColor(Rgba32.Blue));
image.Mutate(x => x.Draw(Rgba32.HotPink, 5, p));
image.Save($"{path}/Simple.png");
Buffer2D<Rgba32> sourcePixels = image.GetRootFramePixelBuffer();
@ -67,7 +68,8 @@ namespace SixLabors.ImageSharp.Tests.Drawing
using (var image = new Image<Rgba32>(500, 500))
{
image.Mutate(x => x.BackgroundColor(Rgba32.Blue).Draw(color, 10, p));
image.Mutate(x => x.BackgroundColor(Rgba32.Blue));
image.Mutate(x => x.Draw(color, 10, p));
image.Save($"{path}/Opacity.png");
//shift background color towards forground color by the opacity amount

17
tests/ImageSharp.Tests/Drawing/LineComplexPolygonTests.cs

@ -31,7 +31,8 @@ namespace SixLabors.ImageSharp.Tests.Drawing
using (var image = new Image<Rgba32>(500, 500))
{
image.Mutate(x => x.BackgroundColor(Rgba32.Blue).Draw(Rgba32.HotPink, 5, simplePath.Clip(hole1)));
image.Mutate(x => x.BackgroundColor(Rgba32.Blue));
image.Mutate(x => x.Draw(Rgba32.HotPink, 5, simplePath.Clip(hole1)));
image.Save($"{path}/Simple.png");
Buffer2D<Rgba32> sourcePixels = image.GetRootFramePixelBuffer();
@ -73,7 +74,8 @@ namespace SixLabors.ImageSharp.Tests.Drawing
using (var image = new Image<Rgba32>(500, 500))
{
image.Mutate(x => x.BackgroundColor(Rgba32.Blue).Draw(Rgba32.HotPink, 5, simplePath.Clip(hole1)));
image.Mutate(x => x.BackgroundColor(Rgba32.Blue));
image.Mutate(x => x.Draw(Rgba32.HotPink, 5, simplePath.Clip(hole1)));
image.Save($"{path}/SimpleVanishHole.png");
Buffer2D<Rgba32> sourcePixels = image.GetRootFramePixelBuffer();
@ -113,7 +115,8 @@ namespace SixLabors.ImageSharp.Tests.Drawing
using (var image = new Image<Rgba32>(500, 500))
{
image.Mutate(x => x.BackgroundColor(Rgba32.Blue).Draw(Rgba32.HotPink, 5, simplePath.Clip(hole1)));
image.Mutate(x => x.BackgroundColor(Rgba32.Blue));
image.Mutate(x => x.Draw(Rgba32.HotPink, 5, simplePath.Clip(hole1)));
image.Save($"{path}/SimpleOverlapping.png");
Buffer2D<Rgba32> sourcePixels = image.GetRootFramePixelBuffer();
@ -147,9 +150,8 @@ namespace SixLabors.ImageSharp.Tests.Drawing
using (var image = new Image<Rgba32>(500, 500))
{
image.Mutate(x => x
.BackgroundColor(Rgba32.Blue)
.Draw(Pens.Dash(Rgba32.HotPink, 5), simplePath.Clip(hole1)));
image.Mutate(x => x.BackgroundColor(Rgba32.Blue));
image.Mutate(x => x.Draw(Pens.Dash(Rgba32.HotPink, 5), simplePath.Clip(hole1)));
image.Save($"{path}/Dashed.png");
}
}
@ -171,7 +173,8 @@ namespace SixLabors.ImageSharp.Tests.Drawing
using (var image = new Image<Rgba32>(500, 500))
{
image.Mutate(x => x.BackgroundColor(Rgba32.Blue).Draw(color, 5, simplePath.Clip(hole1)));
image.Mutate(x => x.BackgroundColor(Rgba32.Blue));
image.Mutate(x => x.Draw(color, 5, simplePath.Clip(hole1)));
image.Save($"{path}/Opacity.png");
//shift background color towards forground color by the opacity amount

33
tests/ImageSharp.Tests/Drawing/LineTests.cs

@ -19,8 +19,9 @@ namespace SixLabors.ImageSharp.Tests.Drawing
string path = TestEnvironment.CreateOutputDirectory("Drawing", "Lines");
using (var image = new Image<Rgba32>(500, 500))
{
image.Mutate(x => x.BackgroundColor(Rgba32.Blue));
image.Mutate(
x => x.BackgroundColor(Rgba32.Blue).DrawLines(
x => x.DrawLines(
Rgba32.HotPink,
5,
new Vector2(10, 10),
@ -43,8 +44,9 @@ namespace SixLabors.ImageSharp.Tests.Drawing
string path = TestEnvironment.CreateOutputDirectory("Drawing", "Lines");
using (var image = new Image<Rgba32>(500, 500))
{
image.Mutate(x => x.BackgroundColor(Rgba32.Blue));
image.Mutate(
x => x.BackgroundColor(Rgba32.Blue).DrawLines(
x => x.DrawLines(
new GraphicsOptions(false),
Rgba32.HotPink,
5,
@ -68,9 +70,8 @@ namespace SixLabors.ImageSharp.Tests.Drawing
string path = TestEnvironment.CreateOutputDirectory("Drawing", "Lines");
using (var image = new Image<Rgba32>(500, 500))
{
image.Mutate(x => x
.BackgroundColor(Rgba32.Blue)
.DrawLines(Pens.Dash(Rgba32.HotPink, 5),
image.Mutate(x => x.BackgroundColor(Rgba32.Blue));
image.Mutate(x => x.DrawLines(Pens.Dash(Rgba32.HotPink, 5),
new SixLabors.Primitives.PointF[] {
new Vector2(10, 10),
new Vector2(200, 150),
@ -86,9 +87,8 @@ namespace SixLabors.ImageSharp.Tests.Drawing
string path = TestEnvironment.CreateOutputDirectory("Drawing", "Lines");
using (var image = new Image<Rgba32>(500, 500))
{
image.Mutate(x => x
.BackgroundColor(Rgba32.Blue)
.DrawLines(Pens.Dot(Rgba32.HotPink, 5),
image.Mutate(x => x.BackgroundColor(Rgba32.Blue));
image.Mutate(x => x.DrawLines(Pens.Dot(Rgba32.HotPink, 5),
new SixLabors.Primitives.PointF[] {
new Vector2(10, 10),
new Vector2(200, 150),
@ -104,9 +104,8 @@ namespace SixLabors.ImageSharp.Tests.Drawing
string path = TestEnvironment.CreateOutputDirectory("Drawing", "Lines");
using (var image = new Image<Rgba32>(500, 500))
{
image.Mutate(x => x
.BackgroundColor(Rgba32.Blue)
.DrawLines(Pens.DashDot(Rgba32.HotPink, 5),
image.Mutate(x => x.BackgroundColor(Rgba32.Blue));
image.Mutate(x => x.DrawLines(Pens.DashDot(Rgba32.HotPink, 5),
new SixLabors.Primitives.PointF[] {
new Vector2(10, 10),
new Vector2(200, 150),
@ -122,9 +121,9 @@ namespace SixLabors.ImageSharp.Tests.Drawing
string path = TestEnvironment.CreateOutputDirectory("Drawing", "Lines");
var image = new Image<Rgba32>(500, 500);
image.Mutate(x => x
.BackgroundColor(Rgba32.Blue)
.DrawLines(Pens.DashDotDot(Rgba32.HotPink, 5), new SixLabors.Primitives.PointF[] {
image.Mutate(x => x.BackgroundColor(Rgba32.Blue));
image.Mutate(x => x.DrawLines(Pens.DashDotDot(Rgba32.HotPink, 5),
new SixLabors.Primitives.PointF[] {
new Vector2(10, 10),
new Vector2(200, 150),
new Vector2(50, 300)
@ -141,8 +140,9 @@ namespace SixLabors.ImageSharp.Tests.Drawing
var image = new Image<Rgba32>(500, 500);
image.Mutate(x => x.BackgroundColor(Rgba32.Blue));
image.Mutate(
x => x.BackgroundColor(Rgba32.Blue).DrawLines(
x => x.DrawLines(
color,
10,
new Vector2(10, 10),
@ -169,8 +169,9 @@ namespace SixLabors.ImageSharp.Tests.Drawing
var image = new Image<Rgba32>(500, 500);
image.Mutate(x => x.BackgroundColor(Rgba32.Blue));
image.Mutate(
x => x.BackgroundColor(Rgba32.Blue).DrawLines(
x => x.DrawLines(
Rgba32.HotPink,
10,
new Vector2(10, 10),

9
tests/ImageSharp.Tests/Drawing/PolygonTests.cs

@ -20,8 +20,9 @@ namespace SixLabors.ImageSharp.Tests.Drawing
using (Image<Rgba32> image = new Image<Rgba32>(500, 500))
{
image.Mutate(x => x.BackgroundColor(Rgba32.Blue));
image.Mutate(
x => x.BackgroundColor(Rgba32.Blue).DrawPolygon(
x => x.DrawPolygon(
Rgba32.HotPink,
5,
new Vector2(10, 10),
@ -54,7 +55,8 @@ namespace SixLabors.ImageSharp.Tests.Drawing
using (Image<Rgba32> image = new Image<Rgba32>(500, 500))
{
image.Mutate(x => x.BackgroundColor(Rgba32.Blue).DrawPolygon(color, 10, simplePath));
image.Mutate(x => x.BackgroundColor(Rgba32.Blue));
image.Mutate(x => x.DrawPolygon(color, 10, simplePath));
image.Save($"{path}/Opacity.png");
//shift background color towards forground color by the opacity amount
@ -79,8 +81,9 @@ namespace SixLabors.ImageSharp.Tests.Drawing
using (Image<Rgba32> image = new Image<Rgba32>(500, 500))
{
image.Mutate(x => x.BackgroundColor(Rgba32.Blue));
image.Mutate(
x => x.BackgroundColor(Rgba32.Blue).Draw(Rgba32.HotPink, 10, new Rectangle(10, 10, 190, 140)));
x => x.Draw(Rgba32.HotPink, 10, new Rectangle(10, 10, 190, 140)));
image.Save($"{path}/Rectangle.png");
Buffer2D<Rgba32> sourcePixels = image.GetRootFramePixelBuffer();

16
tests/ImageSharp.Tests/Drawing/SolidBezierTests.cs

@ -24,15 +24,13 @@ namespace SixLabors.ImageSharp.Tests.Drawing
new Vector2(300, 400)
};
TPixel blue = NamedColors<TPixel>.Blue;
TPixel hotPink = NamedColors<TPixel>.HotPink;
Color blue = Color.Blue;
Color hotPink = Color.HotPink;
using (Image<TPixel> image = provider.GetImage())
{
image.Mutate(x => x
.BackgroundColor(blue)
.Fill(hotPink, new Polygon(new CubicBezierLineSegment(simplePath))));
image.Mutate(x => x.BackgroundColor(blue));
image.Mutate(x => x.Fill(hotPink.ToPixel<TPixel>(), new Polygon(new CubicBezierLineSegment(simplePath))));
image.DebugSave(provider);
image.CompareToReferenceOutput(provider);
}
@ -55,9 +53,9 @@ namespace SixLabors.ImageSharp.Tests.Drawing
using (var image = provider.GetImage() as Image<Rgba32>)
{
image.Mutate(x => x
.BackgroundColor(Rgba32.Blue)
.Fill(color, new Polygon(new CubicBezierLineSegment(simplePath))));
image.Mutate(x => x.BackgroundColor(Rgba32.Blue));
image.Mutate(x => x.Fill(color, new Polygon(new CubicBezierLineSegment(simplePath))));
image.DebugSave(provider);
image.CompareToReferenceOutput(provider);
}

9
tests/ImageSharp.Tests/Drawing/SolidComplexPolygonTests.cs

@ -31,7 +31,8 @@ namespace SixLabors.ImageSharp.Tests.Drawing
// var clipped = new Rectangle(10, 10, 100, 100).Clip(new Rectangle(20, 0, 20, 20));
using (var image = new Image<Rgba32>(500, 500))
{
image.Mutate(x => x.BackgroundColor(Rgba32.Blue).Fill(Rgba32.HotPink, clipped));
image.Mutate(x => x.BackgroundColor(Rgba32.Blue));
image.Mutate(x => x.Fill(Rgba32.HotPink, clipped));
image.Save($"{path}/Simple.png");
Buffer2D<Rgba32> sourcePixels = image.GetRootFramePixelBuffer();
@ -59,7 +60,8 @@ namespace SixLabors.ImageSharp.Tests.Drawing
using (var image = new Image<Rgba32>(500, 500))
{
image.Mutate(x => x.BackgroundColor(Rgba32.Blue).Fill(Rgba32.HotPink, simplePath.Clip(hole1)));
image.Mutate(x => x.BackgroundColor(Rgba32.Blue));
image.Mutate(x => x.Fill(Rgba32.HotPink, simplePath.Clip(hole1)));
image.Save($"{path}/SimpleOverlapping.png");
Buffer2D<Rgba32> sourcePixels = image.GetRootFramePixelBuffer();
@ -88,7 +90,8 @@ namespace SixLabors.ImageSharp.Tests.Drawing
using (var image = new Image<Rgba32>(500, 500))
{
image.Mutate(x => x.BackgroundColor(Rgba32.Blue).Fill(color, simplePath.Clip(hole1)));
image.Mutate(x => x.BackgroundColor(Rgba32.Blue));
image.Mutate(x => x.Fill(color, simplePath.Clip(hole1)));
image.Save($"{path}/Opacity.png");
//shift background color towards forground color by the opacity amount

25
tests/ImageSharp.Tests/Drawing/SolidPolygonTests.cs

@ -68,8 +68,9 @@ namespace SixLabors.ImageSharp.Tests.Drawing
using (var image = new Image<Rgba32>(500, 500))
{
image.Mutate(x => x.BackgroundColor(Rgba32.Blue));
image.Mutate(
x => x.BackgroundColor(Rgba32.Blue).FillPolygon(
x => x.FillPolygon(
new GraphicsOptions(false),
Rgba32.HotPink,
simplePath));
@ -101,9 +102,8 @@ namespace SixLabors.ImageSharp.Tests.Drawing
{
var brush = new ImageBrush<Rgba32>(brushImage);
image.Mutate(x => x
.BackgroundColor(Rgba32.Blue)
.FillPolygon(brush, simplePath));
image.Mutate(x => x.BackgroundColor(Rgba32.Blue));
image.Mutate(x => x.FillPolygon(brush, simplePath));
image.Save($"{path}/Image.png");
}
}
@ -121,7 +121,8 @@ namespace SixLabors.ImageSharp.Tests.Drawing
using (var image = new Image<Rgba32>(500, 500))
{
image.Mutate(x => x.BackgroundColor(Rgba32.Blue).FillPolygon(color, simplePath));
image.Mutate(x => x.BackgroundColor(Rgba32.Blue));
image.Mutate(x => x.FillPolygon(color, simplePath));
image.Save($"{path}/Opacity.png");
//shift background color towards forground color by the opacity amount
@ -140,8 +141,9 @@ namespace SixLabors.ImageSharp.Tests.Drawing
using (var image = new Image<Rgba32>(500, 500))
{
image.Mutate(x => x.BackgroundColor(Rgba32.Blue));
image.Mutate(
x => x.BackgroundColor(Rgba32.Blue).Fill(
x => x.Fill(
Rgba32.HotPink,
new SixLabors.Shapes.RectangularPolygon(10, 10, 190, 140)));
image.Save($"{path}/Rectangle.png");
@ -166,8 +168,9 @@ namespace SixLabors.ImageSharp.Tests.Drawing
using (var image = new Image<Rgba32>(100, 100))
{
image.Mutate(x => x.BackgroundColor(Rgba32.Blue));
image.Mutate(
x => x.BackgroundColor(Rgba32.Blue).Fill(Rgba32.HotPink, new RegularPolygon(50, 50, 3, 30)));
x => x.Fill(Rgba32.HotPink, new RegularPolygon(50, 50, 3, 30)));
image.Save($"{path}/Triangle.png");
Buffer2D<Rgba32> sourcePixels = image.GetRootFramePixelBuffer();
@ -186,9 +189,9 @@ namespace SixLabors.ImageSharp.Tests.Drawing
config.MaxDegreeOfParallelism = 1;
using (var image = new Image<Rgba32>(config, 100, 100))
{
image.Mutate(x => x
.BackgroundColor(Rgba32.Blue)
.Fill(Rgba32.HotPink, new RegularPolygon(50, 50, 7, 30, -(float)Math.PI)));
image.Mutate(x => x.BackgroundColor(Rgba32.Blue));
image.Mutate(x => x.Fill(Rgba32.HotPink,
new RegularPolygon(50, 50, 7, 30, -(float)Math.PI)));
image.Save($"{path}/Septagon.png");
}
}
@ -202,8 +205,8 @@ namespace SixLabors.ImageSharp.Tests.Drawing
config.MaxDegreeOfParallelism = 1;
using (var image = new Image<Rgba32>(config, 100, 100))
{
image.Mutate(x => x.BackgroundColor(Rgba32.Blue));
image.Mutate(x => x
.BackgroundColor(Rgba32.Blue)
.Fill(Rgba32.HotPink, new EllipsePolygon(50, 50, 30, 50)
.Rotate((float)(Math.PI / 3))));
image.Save($"{path}/ellipse.png");

24
tests/ImageSharp.Tests/Processing/Effects/BackgroundColorTest.cs

@ -14,41 +14,41 @@ namespace SixLabors.ImageSharp.Tests.Processing.Effects
[Fact]
public void BackgroundColor_amount_BackgroundColorProcessorDefaultsSet()
{
this.operations.BackgroundColor(Rgba32.BlanchedAlmond);
var processor = this.Verify<BackgroundColorProcessor<Rgba32>>();
this.operations.BackgroundColor(Color.BlanchedAlmond);
var processor = this.Verify<BackgroundColorProcessor>();
Assert.Equal(GraphicsOptions.Default, processor.GraphicsOptions);
Assert.Equal(Rgba32.BlanchedAlmond, processor.Color);
Assert.Equal(Color.BlanchedAlmond, processor.Color);
}
[Fact]
public void BackgroundColor_amount_rect_BackgroundColorProcessorDefaultsSet()
{
this.operations.BackgroundColor(Rgba32.BlanchedAlmond, this.rect);
var processor = this.Verify<BackgroundColorProcessor<Rgba32>>(this.rect);
this.operations.BackgroundColor(Color.BlanchedAlmond, this.rect);
var processor = this.Verify<BackgroundColorProcessor>(this.rect);
Assert.Equal(GraphicsOptions.Default, processor.GraphicsOptions);
Assert.Equal(Rgba32.BlanchedAlmond, processor.Color);
Assert.Equal(Color.BlanchedAlmond, processor.Color);
}
[Fact]
public void BackgroundColor_amount_options_BackgroundColorProcessorDefaultsSet()
{
this.operations.BackgroundColor(this.options, Rgba32.BlanchedAlmond);
var processor = this.Verify<BackgroundColorProcessor<Rgba32>>();
this.operations.BackgroundColor(this.options, Color.BlanchedAlmond);
var processor = this.Verify<BackgroundColorProcessor>();
Assert.Equal(this.options, processor.GraphicsOptions);
Assert.Equal(Rgba32.BlanchedAlmond, processor.Color);
Assert.Equal(Color.BlanchedAlmond, processor.Color);
}
[Fact]
public void BackgroundColor_amount_rect_options_BackgroundColorProcessorDefaultsSet()
{
this.operations.BackgroundColor(this.options, Rgba32.BlanchedAlmond, this.rect);
var processor = this.Verify<BackgroundColorProcessor<Rgba32>>(this.rect);
this.operations.BackgroundColor(this.options, Color.BlanchedAlmond, this.rect);
var processor = this.Verify<BackgroundColorProcessor>(this.rect);
Assert.Equal(this.options, processor.GraphicsOptions);
Assert.Equal(Rgba32.BlanchedAlmond, processor.Color);
Assert.Equal(Color.BlanchedAlmond, processor.Color);
}
}
}

16
tests/ImageSharp.Tests/Processing/Overlays/GlowTest.cs

@ -18,10 +18,10 @@ namespace SixLabors.ImageSharp.Tests.Processing.Overlays
public void Glow_GlowProcessorWithDefaultValues()
{
this.operations.Glow();
var p = this.Verify<GlowProcessor<Rgba32>>();
var p = this.Verify<GlowProcessor>();
Assert.Equal(GraphicsOptions.Default, p.GraphicsOptions);
Assert.Equal(Rgba32.Black, p.GlowColor);
Assert.Equal(Color.Black, p.GlowColor);
Assert.Equal(ValueSize.PercentageOfWidth(.5f), p.Radius);
}
@ -29,10 +29,10 @@ namespace SixLabors.ImageSharp.Tests.Processing.Overlays
public void Glow_Color_GlowProcessorWithDefaultValues()
{
this.operations.Glow(Rgba32.Aquamarine);
var p = this.Verify<GlowProcessor<Rgba32>>();
var p = this.Verify<GlowProcessor>();
Assert.Equal(GraphicsOptions.Default, p.GraphicsOptions);
Assert.Equal(Rgba32.Aquamarine, p.GlowColor);
Assert.Equal(Color.Aquamarine, p.GlowColor);
Assert.Equal(ValueSize.PercentageOfWidth(.5f), p.Radius);
}
@ -40,10 +40,10 @@ namespace SixLabors.ImageSharp.Tests.Processing.Overlays
public void Glow_Radux_GlowProcessorWithDefaultValues()
{
this.operations.Glow(3.5f);
var p = this.Verify<GlowProcessor<Rgba32>>();
var p = this.Verify<GlowProcessor>();
Assert.Equal(GraphicsOptions.Default, p.GraphicsOptions);
Assert.Equal(Rgba32.Black, p.GlowColor);
Assert.Equal(Color.Black, p.GlowColor);
Assert.Equal(ValueSize.Absolute(3.5f), p.Radius);
}
@ -52,10 +52,10 @@ namespace SixLabors.ImageSharp.Tests.Processing.Overlays
{
var rect = new Rectangle(12, 123, 43, 65);
this.operations.Glow(rect);
var p = this.Verify<GlowProcessor<Rgba32>>(rect);
var p = this.Verify<GlowProcessor>(rect);
Assert.Equal(GraphicsOptions.Default, p.GraphicsOptions);
Assert.Equal(Rgba32.Black, p.GlowColor);
Assert.Equal(Color.Black, p.GlowColor);
Assert.Equal(ValueSize.PercentageOfWidth(.5f), p.Radius);
}
}

18
tests/ImageSharp.Tests/Processing/Overlays/VignetteTest.cs

@ -16,10 +16,10 @@ namespace SixLabors.ImageSharp.Tests.Processing.Overlays
public void Vignette_VignetteProcessorWithDefaultValues()
{
this.operations.Vignette();
var p = this.Verify<VignetteProcessor<Rgba32>>();
var p = this.Verify<VignetteProcessor>();
Assert.Equal(GraphicsOptions.Default, p.GraphicsOptions);
Assert.Equal(Rgba32.Black, p.VignetteColor);
Assert.Equal(Color.Black, p.VignetteColor);
Assert.Equal(ValueSize.PercentageOfWidth(.5f), p.RadiusX);
Assert.Equal(ValueSize.PercentageOfHeight(.5f), p.RadiusY);
}
@ -27,11 +27,11 @@ namespace SixLabors.ImageSharp.Tests.Processing.Overlays
[Fact]
public void Vignette_Color_VignetteProcessorWithDefaultValues()
{
this.operations.Vignette(Rgba32.Aquamarine);
var p = this.Verify<VignetteProcessor<Rgba32>>();
this.operations.Vignette(Color.Aquamarine);
var p = this.Verify<VignetteProcessor>();
Assert.Equal(GraphicsOptions.Default, p.GraphicsOptions);
Assert.Equal(Rgba32.Aquamarine, p.VignetteColor);
Assert.Equal(Color.Aquamarine, p.VignetteColor);
Assert.Equal(ValueSize.PercentageOfWidth(.5f), p.RadiusX);
Assert.Equal(ValueSize.PercentageOfHeight(.5f), p.RadiusY);
}
@ -40,10 +40,10 @@ namespace SixLabors.ImageSharp.Tests.Processing.Overlays
public void Vignette_Radux_VignetteProcessorWithDefaultValues()
{
this.operations.Vignette(3.5f, 12123f);
var p = this.Verify<VignetteProcessor<Rgba32>>();
var p = this.Verify<VignetteProcessor>();
Assert.Equal(GraphicsOptions.Default, p.GraphicsOptions);
Assert.Equal(Rgba32.Black, p.VignetteColor);
Assert.Equal(Color.Black, p.VignetteColor);
Assert.Equal(ValueSize.Absolute(3.5f), p.RadiusX);
Assert.Equal(ValueSize.Absolute(12123f), p.RadiusY);
}
@ -53,10 +53,10 @@ namespace SixLabors.ImageSharp.Tests.Processing.Overlays
{
var rect = new Rectangle(12, 123, 43, 65);
this.operations.Vignette(rect);
var p = this.Verify<VignetteProcessor<Rgba32>>(rect);
var p = this.Verify<VignetteProcessor>(rect);
Assert.Equal(GraphicsOptions.Default, p.GraphicsOptions);
Assert.Equal(Rgba32.Black, p.VignetteColor);
Assert.Equal(Color.Black, p.VignetteColor);
Assert.Equal(ValueSize.PercentageOfWidth(.5f), p.RadiusX);
Assert.Equal(ValueSize.PercentageOfHeight(.5f), p.RadiusY);
}

4
tests/ImageSharp.Tests/Processing/Processors/Effects/BackgroundColorTest.cs

@ -24,7 +24,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Effects
public void FullImage<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : struct, IPixel<TPixel>
{
provider.RunValidatingProcessorTest(x => x.BackgroundColor(NamedColors<TPixel>.HotPink));
provider.RunValidatingProcessorTest(x => x.BackgroundColor(Color.HotPink));
}
[Theory]
@ -33,7 +33,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Effects
where TPixel : struct, IPixel<TPixel>
{
provider.RunRectangleConstrainedValidatingProcessorTest(
(x, rect) => x.BackgroundColor(NamedColors<TPixel>.HotPink, rect));
(x, rect) => x.BackgroundColor(Color.HotPink, rect));
}
}
}

6
tests/ImageSharp.Tests/Processing/Processors/Overlays/GlowTest.cs

@ -13,11 +13,11 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Overlays
[GroupOutput("Overlays")]
public class GlowTest : OverlayTestBase
{
protected override void Apply<T>(IImageProcessingContext<T> ctx, T color) => ctx.Glow(color);
protected override void Apply(IImageProcessingContext ctx, Color color) => ctx.Glow(color);
protected override void Apply<T>(IImageProcessingContext<T> ctx, float radiusX, float radiusY) =>
protected override void Apply(IImageProcessingContext ctx, float radiusX, float radiusY) =>
ctx.Glow(radiusX);
protected override void Apply<T>(IImageProcessingContext<T> ctx, Rectangle rect) => ctx.Glow(rect);
protected override void Apply(IImageProcessingContext ctx, Rectangle rect) => ctx.Glow(rect);
}
}

13
tests/ImageSharp.Tests/Processing/Processors/Overlays/OverlayTestBase.cs

@ -27,8 +27,8 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Overlays
where TPixel : struct, IPixel<TPixel>
{
provider.Utility.TestGroupName = this.GetType().Name;
var f = (FieldInfo)typeof(NamedColors<TPixel>).GetMember(colorName)[0];
TPixel color = (TPixel)f.GetValue(null);
var f = (FieldInfo)typeof(Color).GetMember(colorName)[0];
Color color = (Color)f.GetValue(null);
provider.RunValidatingProcessorTest(x => this.Apply(x, color), colorName, ValidatorComparer, appendPixelTypeToFileName: false);
}
@ -58,13 +58,10 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Overlays
provider.RunRectangleConstrainedValidatingProcessorTest((x, rect) => this.Apply(x, rect));
}
protected abstract void Apply<T>(IImageProcessingContext<T> ctx, T color)
where T : struct, IPixel<T>;
protected abstract void Apply(IImageProcessingContext ctx, Color color);
protected abstract void Apply<T>(IImageProcessingContext<T> ctx, float radiusX, float radiusY)
where T : struct, IPixel<T>;
protected abstract void Apply(IImageProcessingContext ctx, float radiusX, float radiusY);
protected abstract void Apply<T>(IImageProcessingContext<T> ctx, Rectangle rect)
where T : struct, IPixel<T>;
protected abstract void Apply(IImageProcessingContext ctx, Rectangle rect);
}
}

6
tests/ImageSharp.Tests/Processing/Processors/Overlays/VignetteTest.cs

@ -9,11 +9,11 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Overlays
[GroupOutput("Overlays")]
public class VignetteTest : OverlayTestBase
{
protected override void Apply<T>(IImageProcessingContext<T> ctx, T color) => ctx.Vignette(color);
protected override void Apply(IImageProcessingContext ctx, Color color) => ctx.Vignette(color);
protected override void Apply<T>(IImageProcessingContext<T> ctx, float radiusX, float radiusY) =>
protected override void Apply(IImageProcessingContext ctx, float radiusX, float radiusY) =>
ctx.Vignette(radiusX, radiusY);
protected override void Apply<T>(IImageProcessingContext<T> ctx, Rectangle rect) => ctx.Vignette(rect);
protected override void Apply(IImageProcessingContext ctx, Rectangle rect) => ctx.Vignette(rect);
}
}
Loading…
Cancel
Save