From 97cac4934d770df166086983e75f2c0dfa520f33 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Tue, 5 Nov 2019 20:55:37 +1100 Subject: [PATCH 01/16] Fix color and pixel operations. Touches #967 #1002 --- .../Processing/GradientBrush.cs | 21 +++++++------------ .../Processing/ImageBrush.cs | 4 ++-- .../Processing/PathGradientBrush.cs | 8 +++---- .../Processing/PatternBrush.cs | 8 +++---- src/ImageSharp/ImageSharp.csproj | 4 ++-- 5 files changed, 19 insertions(+), 26 deletions(-) diff --git a/src/ImageSharp.Drawing/Processing/GradientBrush.cs b/src/ImageSharp.Drawing/Processing/GradientBrush.cs index 9826748c46..bc87a26f3b 100644 --- a/src/ImageSharp.Drawing/Processing/GradientBrush.cs +++ b/src/ImageSharp.Drawing/Processing/GradientBrush.cs @@ -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 System; @@ -92,10 +92,10 @@ protected GradientBrushApplicator( // onLocalGradient = Math.Min(0, Math.Max(1, onLocalGradient)); break; case GradientRepetitionMode.Repeat: - positionOnCompleteGradient = positionOnCompleteGradient % 1; + positionOnCompleteGradient %= 1; break; case GradientRepetitionMode.Reflect: - positionOnCompleteGradient = positionOnCompleteGradient % 2; + positionOnCompleteGradient %= 2; if (positionOnCompleteGradient > 1) { positionOnCompleteGradient = 2 - positionOnCompleteGradient; @@ -121,19 +121,12 @@ protected GradientBrushApplicator( } else { - var fromAsVector = from.Color.ToVector4(); - var toAsVector = to.Color.ToVector4(); float onLocalGradient = (positionOnCompleteGradient - from.Ratio) / (to.Ratio - from.Ratio); // TODO: this should be changeble for different gradienting functions - Vector4 result = PorterDuffFunctions.NormalSrcOver( - fromAsVector, - toAsVector, - onLocalGradient); - - TPixel resultColor = default; - resultColor.FromVector4(result); - return resultColor; + return PixelOperations + .Instance.GetPixelBlender(PixelColorBlendingMode.Normal, PixelAlphaCompositionMode.SrcOver) + .Blend(from.Color.ToPixel(), to.Color.ToPixel(), onLocalGradient); } } } @@ -176,4 +169,4 @@ protected GradientBrushApplicator( } } } -} \ No newline at end of file +} diff --git a/src/ImageSharp.Drawing/Processing/ImageBrush.cs b/src/ImageSharp.Drawing/Processing/ImageBrush.cs index 8485ddfd09..d56b1fccc2 100644 --- a/src/ImageSharp.Drawing/Processing/ImageBrush.cs +++ b/src/ImageSharp.Drawing/Processing/ImageBrush.cs @@ -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 System; @@ -167,4 +167,4 @@ internal override void Apply(Span scanline, int x, int y) } } } -} \ No newline at end of file +} diff --git a/src/ImageSharp.Drawing/Processing/PathGradientBrush.cs b/src/ImageSharp.Drawing/Processing/PathGradientBrush.cs index 7315dc5a3e..d2ad23a0d9 100644 --- a/src/ImageSharp.Drawing/Processing/PathGradientBrush.cs +++ b/src/ImageSharp.Drawing/Processing/PathGradientBrush.cs @@ -105,7 +105,7 @@ private static Color CalculateCenterColor(Color[] colors) "One or more color is needed to construct a path gradient brush."); } - return new Color(colors.Select(c => c.ToVector4()).Aggregate((p1, p2) => p1 + p2) / colors.Length); + return new Color(colors.Select(c => (Vector4)c).Aggregate((p1, p2) => p1 + p2) / colors.Length); } private static float DistanceBetween(PointF p1, PointF p2) => ((Vector2)(p2 - p1)).Length(); @@ -141,10 +141,10 @@ public Edge(Path path, Color startColor, Color endColor) Vector2[] points = path.LineSegments.SelectMany(s => s.Flatten()).Select(p => (Vector2)p).ToArray(); this.Start = points.First(); - this.StartColor = startColor.ToVector4(); + this.StartColor = (Vector4)startColor; this.End = points.Last(); - this.EndColor = endColor.ToVector4(); + this.EndColor = (Vector4)endColor; this.length = DistanceBetween(this.End, this.Start); this.buffer = new PointF[this.path.MaxIntersections]; @@ -215,7 +215,7 @@ public PathGradientBrushApplicator( PointF[] points = edges.Select(s => s.Start).ToArray(); this.center = points.Aggregate((p1, p2) => p1 + p2) / edges.Count; - this.centerColor = centerColor.ToVector4(); + this.centerColor = (Vector4)centerColor; this.maxDistance = points.Select(p => (Vector2)(p - this.center)).Select(d => d.Length()).Max(); } diff --git a/src/ImageSharp.Drawing/Processing/PatternBrush.cs b/src/ImageSharp.Drawing/Processing/PatternBrush.cs index 1999af8a39..d0db44bb34 100644 --- a/src/ImageSharp.Drawing/Processing/PatternBrush.cs +++ b/src/ImageSharp.Drawing/Processing/PatternBrush.cs @@ -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 System; @@ -61,8 +61,8 @@ public PatternBrush(Color foreColor, Color backColor, bool[,] pattern) /// The pattern. internal PatternBrush(Color foreColor, Color backColor, in DenseMatrix pattern) { - var foreColorVector = foreColor.ToVector4(); - var backColorVector = backColor.ToVector4(); + var foreColorVector = (Vector4)foreColor; + var backColorVector = (Vector4)backColor; this.pattern = new DenseMatrix(pattern.Columns, pattern.Rows); this.patternVector = new DenseMatrix(pattern.Columns, pattern.Rows); for (int i = 0; i < pattern.Data.Length; i++) @@ -181,4 +181,4 @@ internal override void Apply(Span scanline, int x, int y) } } } -} \ No newline at end of file +} diff --git a/src/ImageSharp/ImageSharp.csproj b/src/ImageSharp/ImageSharp.csproj index 86b0848663..d9e9a8d219 100644 --- a/src/ImageSharp/ImageSharp.csproj +++ b/src/ImageSharp/ImageSharp.csproj @@ -1,4 +1,4 @@ - + @@ -119,7 +119,7 @@ - + From 40b69a5bb8afac5351cb92992254651ab280555a Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Tue, 5 Nov 2019 21:18:38 +1100 Subject: [PATCH 02/16] Fix span access --- src/ImageSharp.Drawing/Primitives/ShapeRegion.cs | 6 +++--- .../Processing/BrushApplicator.cs | 6 +++--- src/ImageSharp.Drawing/Processing/ImageBrush.cs | 4 ++-- src/ImageSharp.Drawing/Processing/PatternBrush.cs | 4 ++-- .../Processors/Drawing/FillProcessor{TPixel}.cs | 4 ++-- .../Drawing/FillRegionProcessor{TPixel}.cs | 4 ++-- .../Processors/Text/DrawTextProcessor{TPixel}.cs | 4 ++-- src/ImageSharp.Drawing/Processing/RecolorBrush.cs | 8 ++++---- src/ImageSharp.Drawing/Processing/SolidBrush.cs | 14 +++++++------- src/ImageSharp/Primitives/DenseMatrix{T}.cs | 8 ++++---- 10 files changed, 31 insertions(+), 31 deletions(-) diff --git a/src/ImageSharp.Drawing/Primitives/ShapeRegion.cs b/src/ImageSharp.Drawing/Primitives/ShapeRegion.cs index f4a6458206..c008f4419e 100644 --- a/src/ImageSharp.Drawing/Primitives/ShapeRegion.cs +++ b/src/ImageSharp.Drawing/Primitives/ShapeRegion.cs @@ -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 System; @@ -49,7 +49,7 @@ public override int Scan(float y, Span buffer, Configuration configuratio using (IMemoryOwner tempBuffer = configuration.MemoryAllocator.Allocate(buffer.Length)) { - Span innerBuffer = tempBuffer.GetSpan(); + Span innerBuffer = tempBuffer.Memory.Span; int count = this.Shape.FindIntersections(start, end, innerBuffer); for (int i = 0; i < count; i++) @@ -61,4 +61,4 @@ public override int Scan(float y, Span buffer, Configuration configuratio } } } -} \ No newline at end of file +} diff --git a/src/ImageSharp.Drawing/Processing/BrushApplicator.cs b/src/ImageSharp.Drawing/Processing/BrushApplicator.cs index 7e75d7effc..ab601bb8b0 100644 --- a/src/ImageSharp.Drawing/Processing/BrushApplicator.cs +++ b/src/ImageSharp.Drawing/Processing/BrushApplicator.cs @@ -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 System; @@ -71,8 +71,8 @@ internal virtual void Apply(Span scanline, int x, int y) using (IMemoryOwner amountBuffer = memoryAllocator.Allocate(scanline.Length)) using (IMemoryOwner overlay = memoryAllocator.Allocate(scanline.Length)) { - Span amountSpan = amountBuffer.GetSpan(); - Span overlaySpan = overlay.GetSpan(); + Span amountSpan = amountBuffer.Memory.Span; + Span overlaySpan = overlay.Memory.Span; for (int i = 0; i < scanline.Length; i++) { diff --git a/src/ImageSharp.Drawing/Processing/ImageBrush.cs b/src/ImageSharp.Drawing/Processing/ImageBrush.cs index d56b1fccc2..ebcc2c0677 100644 --- a/src/ImageSharp.Drawing/Processing/ImageBrush.cs +++ b/src/ImageSharp.Drawing/Processing/ImageBrush.cs @@ -140,8 +140,8 @@ internal override void Apply(Span scanline, int x, int y) using (IMemoryOwner amountBuffer = this.Target.MemoryAllocator.Allocate(scanline.Length)) using (IMemoryOwner overlay = this.Target.MemoryAllocator.Allocate(scanline.Length)) { - Span amountSpan = amountBuffer.GetSpan(); - Span overlaySpan = overlay.GetSpan(); + Span amountSpan = amountBuffer.Memory.Span; + Span overlaySpan = overlay.Memory.Span; int sourceY = (y - this.offsetY) % this.yLength; int offsetX = x - this.offsetX; diff --git a/src/ImageSharp.Drawing/Processing/PatternBrush.cs b/src/ImageSharp.Drawing/Processing/PatternBrush.cs index d0db44bb34..1b7db970a3 100644 --- a/src/ImageSharp.Drawing/Processing/PatternBrush.cs +++ b/src/ImageSharp.Drawing/Processing/PatternBrush.cs @@ -159,8 +159,8 @@ internal override void Apply(Span scanline, int x, int y) using (IMemoryOwner amountBuffer = memoryAllocator.Allocate(scanline.Length)) using (IMemoryOwner overlay = memoryAllocator.Allocate(scanline.Length)) { - Span amountSpan = amountBuffer.GetSpan(); - Span overlaySpan = overlay.GetSpan(); + Span amountSpan = amountBuffer.Memory.Span; + Span overlaySpan = overlay.Memory.Span; for (int i = 0; i < scanline.Length; i++) { diff --git a/src/ImageSharp.Drawing/Processing/Processors/Drawing/FillProcessor{TPixel}.cs b/src/ImageSharp.Drawing/Processing/Processors/Drawing/FillProcessor{TPixel}.cs index 4e052818da..1dd4be1354 100644 --- a/src/ImageSharp.Drawing/Processing/Processors/Drawing/FillProcessor{TPixel}.cs +++ b/src/ImageSharp.Drawing/Processing/Processors/Drawing/FillProcessor{TPixel}.cs @@ -88,7 +88,7 @@ protected override void OnFrameApply(ImageFrame source) sourceRectangle, options)) { - amount.GetSpan().Fill(1f); + amount.Memory.Span.Fill(1f); ParallelHelper.IterateRows( workingRect, @@ -100,7 +100,7 @@ protected override void OnFrameApply(ImageFrame source) int offsetY = y - startY; int offsetX = minX - startX; - applicator.Apply(amount.GetSpan(), offsetX, offsetY); + applicator.Apply(amount.Memory.Span, offsetX, offsetY); } }); } diff --git a/src/ImageSharp.Drawing/Processing/Processors/Drawing/FillRegionProcessor{TPixel}.cs b/src/ImageSharp.Drawing/Processing/Processors/Drawing/FillRegionProcessor{TPixel}.cs index 45d5015ae0..69f97ce75f 100644 --- a/src/ImageSharp.Drawing/Processing/Processors/Drawing/FillRegionProcessor{TPixel}.cs +++ b/src/ImageSharp.Drawing/Processing/Processors/Drawing/FillRegionProcessor{TPixel}.cs @@ -81,8 +81,8 @@ protected override void OnFrameApply(ImageFrame source) float subpixelFraction = 1f / subpixelCount; float subpixelFractionPoint = subpixelFraction / subpixelCount; - Span buffer = bBuffer.GetSpan(); - Span scanline = bScanline.GetSpan(); + Span buffer = bBuffer.Memory.Span; + Span scanline = bScanline.Memory.Span; bool isSolidBrushWithoutBlending = this.IsSolidBrushWithoutBlending(out SolidBrush solidBrush); TPixel solidBrushColor = isSolidBrushWithoutBlending ? solidBrush.Color.ToPixel() : default; diff --git a/src/ImageSharp.Drawing/Processing/Processors/Text/DrawTextProcessor{TPixel}.cs b/src/ImageSharp.Drawing/Processing/Processors/Text/DrawTextProcessor{TPixel}.cs index ea042635dd..c2e38f67be 100644 --- a/src/ImageSharp.Drawing/Processing/Processors/Text/DrawTextProcessor{TPixel}.cs +++ b/src/ImageSharp.Drawing/Processing/Processors/Text/DrawTextProcessor{TPixel}.cs @@ -326,6 +326,8 @@ private Buffer2D Render(IPath path) { float subpixelFraction = 1f / subpixelCount; float subpixelFractionPoint = subpixelFraction / subpixelCount; + Span intersectionSpan = rowIntersectionBuffer.Memory.Span; + Span buffer = bufferBacking.Memory.Span; for (int y = 0; y <= size.Height; y++) { @@ -337,8 +339,6 @@ private Buffer2D Render(IPath path) { var start = new PointF(path.Bounds.Left - 1, subPixel); var end = new PointF(path.Bounds.Right + 1, subPixel); - Span intersectionSpan = rowIntersectionBuffer.GetSpan(); - Span buffer = bufferBacking.GetSpan(); int pointsFound = path.FindIntersections(start, end, intersectionSpan); if (pointsFound == 0) diff --git a/src/ImageSharp.Drawing/Processing/RecolorBrush.cs b/src/ImageSharp.Drawing/Processing/RecolorBrush.cs index fca95be327..d93110972c 100644 --- a/src/ImageSharp.Drawing/Processing/RecolorBrush.cs +++ b/src/ImageSharp.Drawing/Processing/RecolorBrush.cs @@ -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 System; @@ -151,8 +151,8 @@ internal override void Apply(Span scanline, int x, int y) using (IMemoryOwner amountBuffer = memoryAllocator.Allocate(scanline.Length)) using (IMemoryOwner overlay = memoryAllocator.Allocate(scanline.Length)) { - Span amountSpan = amountBuffer.GetSpan(); - Span overlaySpan = overlay.GetSpan(); + Span amountSpan = amountBuffer.Memory.Span; + Span overlaySpan = overlay.Memory.Span; for (int i = 0; i < scanline.Length; i++) { @@ -176,4 +176,4 @@ internal override void Apply(Span scanline, int x, int y) } } } -} \ No newline at end of file +} diff --git a/src/ImageSharp.Drawing/Processing/SolidBrush.cs b/src/ImageSharp.Drawing/Processing/SolidBrush.cs index c62566f6b7..71738de52b 100644 --- a/src/ImageSharp.Drawing/Processing/SolidBrush.cs +++ b/src/ImageSharp.Drawing/Processing/SolidBrush.cs @@ -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 System; @@ -62,7 +62,7 @@ public SolidBrushApplicator(ImageFrame source, TPixel color, GraphicsOpt : base(source, options) { this.Colors = source.MemoryAllocator.Allocate(source.Width); - this.Colors.GetSpan().Fill(color); + this.Colors.Memory.Span.Fill(color); } /// @@ -78,7 +78,7 @@ public SolidBrushApplicator(ImageFrame source, TPixel color, GraphicsOpt /// /// The color /// - internal override TPixel this[int x, int y] => this.Colors.GetSpan()[x]; + internal override TPixel this[int x, int y] => this.Colors.Memory.Span[x]; /// public override void Dispose() @@ -106,13 +106,13 @@ internal override void Apply(Span scanline, int x, int y) if (this.Options.BlendPercentage == 1f) { - this.Blender.Blend(configuration, destinationRow, destinationRow, this.Colors.GetSpan(), scanline); + this.Blender.Blend(configuration, destinationRow, destinationRow, this.Colors.Memory.Span, scanline); } else { using (IMemoryOwner amountBuffer = memoryAllocator.Allocate(scanline.Length)) { - Span amountSpan = amountBuffer.GetSpan(); + Span amountSpan = amountBuffer.Memory.Span; for (int i = 0; i < scanline.Length; i++) { @@ -123,11 +123,11 @@ internal override void Apply(Span scanline, int x, int y) configuration, destinationRow, destinationRow, - this.Colors.GetSpan(), + this.Colors.Memory.Span, amountSpan); } } } } } -} \ No newline at end of file +} diff --git a/src/ImageSharp/Primitives/DenseMatrix{T}.cs b/src/ImageSharp/Primitives/DenseMatrix{T}.cs index 170292e29e..cc5e4a90a3 100644 --- a/src/ImageSharp/Primitives/DenseMatrix{T}.cs +++ b/src/ImageSharp/Primitives/DenseMatrix{T}.cs @@ -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 System; @@ -98,9 +98,9 @@ public DenseMatrix(T[,] data) } /// - /// Gets a Span wrapping the Data. + /// Gets a span wrapping the . /// - internal Span Span => new Span(this.Data); + public Span Span => new Span(this.Data); /// /// Gets or sets the item at the specified position. @@ -222,4 +222,4 @@ public bool Equals(DenseMatrix other) => /// public override int GetHashCode() => this.Data.GetHashCode(); } -} \ No newline at end of file +} From 7e5794dd4e17873884040fa00a2260df5e8f1fe7 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Tue, 5 Nov 2019 21:23:33 +1100 Subject: [PATCH 03/16] Allow bulk Color => TPixel conversion. --- src/ImageSharp/Color/Color.cs | 35 +++++++++++++++++++---------------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/src/ImageSharp/Color/Color.cs b/src/ImageSharp/Color/Color.cs index 76f3995171..5fad7a8e39 100644 --- a/src/ImageSharp/Color/Color.cs +++ b/src/ImageSharp/Color/Color.cs @@ -133,8 +133,7 @@ public Color WithAlpha(float alpha) public override string ToString() => this.ToHex(); /// - /// Converts the color instance to an - /// implementation defined by . + /// Converts the color instance to a specified type. /// /// The pixel type to convert to. /// The pixel value. @@ -147,6 +146,24 @@ public TPixel ToPixel() return pixel; } + /// + /// Bulk converts a span of to a span of a specified type. + /// + /// The pixel type to convert to. + /// The configuration. + /// The source color span. + /// The destination pixel span. + [MethodImpl(InliningOptions.ShortMethod)] + public static void ToPixel( + Configuration configuration, + ReadOnlySpan source, + Span destination) + where TPixel : struct, IPixel + { + ReadOnlySpan rgba64Span = MemoryMarshal.Cast(source); + PixelOperations.Instance.FromRgba64(configuration, rgba64Span, destination); + } + /// [MethodImpl(InliningOptions.ShortMethod)] public bool Equals(Color other) @@ -166,19 +183,5 @@ public override int GetHashCode() { return this.data.PackedValue.GetHashCode(); } - - /// - /// Bulk convert a span of to a span of a specified pixel type. - /// - [MethodImpl(InliningOptions.ShortMethod)] - internal static void ToPixel( - Configuration configuration, - ReadOnlySpan source, - Span destination) - where TPixel : struct, IPixel - { - ReadOnlySpan rgba64Span = MemoryMarshal.Cast(source); - PixelOperations.Instance.FromRgba64(configuration, rgba64Span, destination); - } } } From 628eb65db83fc4a569479656e02f9d6be12bb9b8 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Tue, 5 Nov 2019 22:07:49 +1100 Subject: [PATCH 04/16] Fix GraphicsOptions --- .../Extensions/GraphicsOptionsExtensions.cs | 53 ++++++++++++++ src/ImageSharp/GraphicsOptions.cs | 72 ++++--------------- 2 files changed, 65 insertions(+), 60 deletions(-) create mode 100644 src/ImageSharp.Drawing/Common/Extensions/GraphicsOptionsExtensions.cs diff --git a/src/ImageSharp.Drawing/Common/Extensions/GraphicsOptionsExtensions.cs b/src/ImageSharp.Drawing/Common/Extensions/GraphicsOptionsExtensions.cs new file mode 100644 index 0000000000..c32d0a46e7 --- /dev/null +++ b/src/ImageSharp.Drawing/Common/Extensions/GraphicsOptionsExtensions.cs @@ -0,0 +1,53 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System.Numerics; +using SixLabors.ImageSharp.PixelFormats; + +namespace SixLabors.ImageSharp +{ + /// + /// Extensions methods fpor the class. + /// + internal static class GraphicsOptionsExtensions + { + /// + /// Evaluates if a given SOURCE color can completely replace a BACKDROP color given the current blending and composition settings. + /// + /// The graphics options. + /// The source color. + /// true if the color can be considered opaque + /// + /// Blending and composition is an expensive operation, in some cases, like + /// filling with a solid color, the blending can be avoided by a plain color replacement. + /// This method can be useful for such processors to select the fast path. + /// + public static bool IsOpaqueColorWithoutBlending(this GraphicsOptions options, Color color) + { + if (options.ColorBlendingMode != PixelColorBlendingMode.Normal) + { + return false; + } + + if (options.AlphaCompositionMode != PixelAlphaCompositionMode.SrcOver + && options.AlphaCompositionMode != PixelAlphaCompositionMode.Src) + { + return false; + } + + const float Opaque = 1F; + + if (options.BlendPercentage != Opaque) + { + return false; + } + + if (((Vector4)color).W != Opaque) + { + return false; + } + + return true; + } + } +} diff --git a/src/ImageSharp/GraphicsOptions.cs b/src/ImageSharp/GraphicsOptions.cs index 214b10810a..644bde1cff 100644 --- a/src/ImageSharp/GraphicsOptions.cs +++ b/src/ImageSharp/GraphicsOptions.cs @@ -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.PixelFormats; @@ -21,18 +21,14 @@ public struct GraphicsOptions private bool? antialias; - private PixelColorBlendingMode colorBlendingMode; - - private PixelAlphaCompositionMode alphaCompositionMode; - /// /// Initializes a new instance of the struct. /// /// If set to true [enable antialiasing]. public GraphicsOptions(bool enableAntialiasing) { - this.colorBlendingMode = PixelColorBlendingMode.Normal; - this.alphaCompositionMode = PixelAlphaCompositionMode.SrcOver; + this.ColorBlendingMode = PixelColorBlendingMode.Normal; + this.AlphaCompositionMode = PixelAlphaCompositionMode.SrcOver; this.blendPercentage = 1; this.antialiasSubpixelDepth = 16; this.antialias = enableAntialiasing; @@ -47,8 +43,8 @@ public GraphicsOptions(bool enableAntialiasing, float opacity) { Guard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); - this.colorBlendingMode = PixelColorBlendingMode.Normal; - this.alphaCompositionMode = PixelAlphaCompositionMode.SrcOver; + this.ColorBlendingMode = PixelColorBlendingMode.Normal; + this.AlphaCompositionMode = PixelAlphaCompositionMode.SrcOver; this.blendPercentage = opacity; this.antialiasSubpixelDepth = 16; this.antialias = enableAntialiasing; @@ -64,8 +60,8 @@ public GraphicsOptions(bool enableAntialiasing, PixelColorBlendingMode blending, { Guard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); - this.colorBlendingMode = blending; - this.alphaCompositionMode = PixelAlphaCompositionMode.SrcOver; + this.ColorBlendingMode = blending; + this.AlphaCompositionMode = PixelAlphaCompositionMode.SrcOver; this.blendPercentage = opacity; this.antialiasSubpixelDepth = 16; this.antialias = enableAntialiasing; @@ -82,8 +78,8 @@ public GraphicsOptions(bool enableAntialiasing, PixelColorBlendingMode blending, { Guard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); - this.colorBlendingMode = blending; - this.alphaCompositionMode = composition; + this.ColorBlendingMode = blending; + this.AlphaCompositionMode = composition; this.blendPercentage = opacity; this.antialiasSubpixelDepth = 16; this.antialias = enableAntialiasing; @@ -123,55 +119,11 @@ public float BlendPercentage /// /// Gets or sets a value indicating the color blending mode to apply to the drawing operation /// - public PixelColorBlendingMode ColorBlendingMode - { - get => this.colorBlendingMode; - set => this.colorBlendingMode = value; - } + public PixelColorBlendingMode ColorBlendingMode { get; set; } /// /// Gets or sets a value indicating the alpha composition mode to apply to the drawing operation /// - public PixelAlphaCompositionMode AlphaCompositionMode - { - get => this.alphaCompositionMode; - set => this.alphaCompositionMode = value; - } - - /// - /// Evaluates if a given SOURCE color can completely replace a BACKDROP color given the current blending and composition settings. - /// - /// the color - /// true if the color can be considered opaque - /// - /// Blending and composition is an expensive operation, in some cases, like - /// filling with a solid color, the blending can be avoided by a plain color replacement. - /// This method can be useful for such processors to select the fast path. - /// - internal bool IsOpaqueColorWithoutBlending(Color color) - { - if (this.ColorBlendingMode != PixelColorBlendingMode.Normal) - { - return false; - } - - if (this.AlphaCompositionMode != PixelAlphaCompositionMode.SrcOver && - this.AlphaCompositionMode != PixelAlphaCompositionMode.Src) - { - return false; - } - - if (this.BlendPercentage != 1f) - { - return false; - } - - if (color.ToVector4().W != 1f) - { - return false; - } - - return true; - } + public PixelAlphaCompositionMode AlphaCompositionMode { get; set; } } -} \ No newline at end of file +} From f8ae0c1388a6e64d444bdc6154342e1f4e394800 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Wed, 6 Nov 2019 20:48:05 +1100 Subject: [PATCH 05/16] Fix ImageFrame.Configuration --- .../Processing/BrushApplicator.cs | 53 ++++++++++------ .../Processing/EllipticGradientBrush.cs | 41 ++++++------ .../Processing/GradientBrush.cs | 29 ++++----- src/ImageSharp.Drawing/Processing/IBrush.cs | 10 +-- .../Processing/ImageBrush.cs | 47 +++++++------- .../Processing/LinearGradientBrush.cs | 27 ++++---- .../Processing/PathGradientBrush.cs | 18 +++--- .../Processing/PatternBrush.cs | 36 +++++------ .../Drawing/FillProcessor{TPixel}.cs | 5 +- .../Drawing/FillRegionProcessor{TPixel}.cs | 2 +- .../Text/DrawTextProcessor{TPixel}.cs | 2 +- .../Processing/RadialGradientBrush.cs | 30 ++++----- .../Processing/RecolorBrush.cs | 39 ++++-------- .../Processing/SolidBrush.cs | 62 ++++++++++--------- src/ImageSharp.Drawing/Utils/QuickSort.cs | 2 +- 15 files changed, 202 insertions(+), 201 deletions(-) diff --git a/src/ImageSharp.Drawing/Processing/BrushApplicator.cs b/src/ImageSharp.Drawing/Processing/BrushApplicator.cs index ab601bb8b0..2b02c14fe1 100644 --- a/src/ImageSharp.Drawing/Processing/BrushApplicator.cs +++ b/src/ImageSharp.Drawing/Processing/BrushApplicator.cs @@ -3,66 +3,83 @@ using System; using System.Buffers; - using SixLabors.ImageSharp.Advanced; -using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.PixelFormats; using SixLabors.Memory; namespace SixLabors.ImageSharp.Processing { /// - /// primitive that converts a point in to a color for discovering the fill color based on an implementation + /// A primitive that converts a point into a color for discovering the fill color based on an implementation. /// /// The pixel format. - /// - public abstract class BrushApplicator : IDisposable // disposable will be required if/when there is an ImageBrush + /// + public abstract class BrushApplicator : IDisposable where TPixel : struct, IPixel { /// /// Initializes a new instance of the class. /// + /// The configuration instance to use when performing operations. /// The target. /// The options. - internal BrushApplicator(ImageFrame target, GraphicsOptions options) + internal BrushApplicator(Configuration configuration, ImageFrame target, GraphicsOptions options) { + this.Configuration = configuration; this.Target = target; this.Options = options; this.Blender = PixelOperations.Instance.GetPixelBlender(options); } /// - /// Gets the blender + /// Gets the configuration instance to use when performing operations. + /// + protected Configuration Configuration { get; } + + /// + /// Gets the pixel blender. /// internal PixelBlender Blender { get; } /// - /// Gets the destination + /// Gets the target image. /// protected ImageFrame Target { get; } /// - /// Gets the blend percentage + /// Gets thegraphics options /// protected GraphicsOptions Options { get; } /// - /// Gets the color for a single pixel. + /// Gets the overlay pixel at the specified position. /// - /// The x coordinate. - /// The y coordinate. - /// The a that should be applied to the pixel. + /// The x-coordinate. + /// The y-coordinate. + /// The at the specified position. internal abstract TPixel this[int x, int y] { get; } /// - public abstract void Dispose(); + public void Dispose() + { + this.Dispose(true); + GC.SuppressFinalize(this); + } + + /// + /// Disposes the object and frees resources for the Garbage Collector. + /// + /// Whether to dispose managed and unmanaged objects. + protected virtual void Dispose(bool disposing) + { + } /// /// Applies the opacity weighting for each pixel in a scanline to the target based on the pattern contained in the brush. /// - /// The a collection of opacity values between 0 and 1 to be merged with the brushed color value before being applied to the target. - /// The x position in the target pixel space that the start of the scanline data corresponds to. - /// The y position in the target pixel space that whole scanline corresponds to. + /// A collection of opacity values between 0 and 1 to be merged with the brushed color value before being applied to the target. + /// The x-position in the target pixel space that the start of the scanline data corresponds to. + /// The y-position in the target pixel space that whole scanline corresponds to. /// scanlineBuffer will be > scanlineWidth but provide and offset in case we want to share a larger buffer across runs. internal virtual void Apply(Span scanline, int x, int y) { @@ -89,7 +106,7 @@ internal virtual void Apply(Span scanline, int x, int y) } Span destinationRow = this.Target.GetPixelRowSpan(y).Slice(x, scanline.Length); - this.Blender.Blend(this.Target.Configuration, destinationRow, destinationRow, overlaySpan, amountSpan); + this.Blender.Blend(this.Configuration, destinationRow, destinationRow, overlaySpan, amountSpan); } } } diff --git a/src/ImageSharp.Drawing/Processing/EllipticGradientBrush.cs b/src/ImageSharp.Drawing/Processing/EllipticGradientBrush.cs index 91da332a16..7810c3c6d5 100644 --- a/src/ImageSharp.Drawing/Processing/EllipticGradientBrush.cs +++ b/src/ImageSharp.Drawing/Processing/EllipticGradientBrush.cs @@ -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 System; @@ -47,17 +47,19 @@ public EllipticGradientBrush( /// public override BrushApplicator CreateApplicator( + Configuration configuration, ImageFrame source, RectangleF region, GraphicsOptions options) => new RadialGradientBrushApplicator( + configuration, source, - options, this.center, this.referenceAxisEnd, this.axisRatio, this.ColorStops, - this.RepetitionMode); + this.RepetitionMode, + options); /// private sealed class RadialGradientBrushApplicator : GradientBrushApplicator @@ -86,24 +88,26 @@ private sealed class RadialGradientBrushApplicator : GradientBrushApplic /// /// Initializes a new instance of the class. /// - /// The target image - /// The options - /// Center of the ellipse + /// The configuration instance to use when performing operations. + /// The target image. + /// Center of the ellipse. /// Point on one angular points of the ellipse. /// /// Ratio of the axis length's. Used to determine the length of the second axis, /// the first is defined by and . - /// Definition of colors + /// Definition of colors. /// Defines how the gradient colors are repeated. + /// The graphics options. public RadialGradientBrushApplicator( + Configuration configuration, ImageFrame target, - GraphicsOptions options, PointF center, PointF referenceAxisEnd, float axisRatio, ColorStop[] colorStops, - GradientRepetitionMode repetitionMode) - : base(target, options, colorStops, repetitionMode) + GradientRepetitionMode repetitionMode, + GraphicsOptions options) + : base(configuration, target, colorStops, repetitionMode, options) { this.center = center; this.referenceAxisEnd = referenceAxisEnd; @@ -122,11 +126,6 @@ public RadialGradientBrushApplicator( this.cosRotation = (float)Math.Cos(this.rotation); } - /// - public override void Dispose() - { - } - /// protected override float PositionOnGradient(float xt, float yt) { @@ -139,16 +138,13 @@ protected override float PositionOnGradient(float xt, float yt) float xSquared = x * x; float ySquared = y * y; - var inBoundaryChecker = (xSquared / this.referenceRadiusSquared) - + (ySquared / this.secondRadiusSquared); - - return inBoundaryChecker; + return (xSquared / this.referenceRadiusSquared) + (ySquared / this.secondRadiusSquared); } private float AngleBetween(PointF junction, PointF a, PointF b) { - var vA = a - junction; - var vB = b - junction; + PointF vA = a - junction; + PointF vB = b - junction; return MathF.Atan2(vB.Y, vB.X) - MathF.Atan2(vA.Y, vA.X); } @@ -156,6 +152,7 @@ private float DistanceBetween( PointF p1, PointF p2) { + // TODO: Can we not just use Vector2 distance here? float dX = p1.X - p2.X; float dXsquared = dX * dX; @@ -165,4 +162,4 @@ private float DistanceBetween( } } } -} \ No newline at end of file +} diff --git a/src/ImageSharp.Drawing/Processing/GradientBrush.cs b/src/ImageSharp.Drawing/Processing/GradientBrush.cs index bc87a26f3b..044f4e2ee8 100644 --- a/src/ImageSharp.Drawing/Processing/GradientBrush.cs +++ b/src/ImageSharp.Drawing/Processing/GradientBrush.cs @@ -2,10 +2,8 @@ // Licensed under the Apache License, Version 2.0. using System; -using System.Numerics; using SixLabors.ImageSharp.PixelFormats; -using SixLabors.ImageSharp.PixelFormats.PixelBlenders; using SixLabors.Primitives; namespace SixLabors.ImageSharp.Processing @@ -38,6 +36,7 @@ protected GradientBrush( /// public abstract BrushApplicator CreateApplicator( + Configuration configuration, ImageFrame source, RectangleF region, GraphicsOptions options) @@ -58,27 +57,24 @@ internal abstract class GradientBrushApplicator : BrushApplicator /// Initializes a new instance of the class. /// - /// The target. - /// The options. + /// The configuration instance to use when performing operations. + /// The target image. /// An array of color stops sorted by their position. /// Defines if and how the gradient should be repeated. + /// The graphics options. protected GradientBrushApplicator( + Configuration configuration, ImageFrame target, - GraphicsOptions options, ColorStop[] colorStops, - GradientRepetitionMode repetitionMode) - : base(target, options) + GradientRepetitionMode repetitionMode, + GraphicsOptions options) + : base(configuration, target, options) { this.colorStops = colorStops; // TODO: requires colorStops to be sorted by position - should that be checked? this.repetitionMode = repetitionMode; } - /// - /// Base implementation of the indexer for gradients - /// (follows the facade pattern, using abstract methods) - /// - /// X coordinate of the Pixel. - /// Y coordinate of the Pixel. + /// internal override TPixel this[int x, int y] { get @@ -123,7 +119,8 @@ protected GradientBrushApplicator( { float onLocalGradient = (positionOnCompleteGradient - from.Ratio) / (to.Ratio - from.Ratio); - // TODO: this should be changeble for different gradienting functions + // TODO: this should be changeble for different gradienting functions. + // TODO: Why not use Blender property? return PixelOperations .Instance.GetPixelBlender(PixelColorBlendingMode.Normal, PixelAlphaCompositionMode.SrcOver) .Blend(from.Color.ToPixel(), to.Color.ToPixel(), onLocalGradient); @@ -135,8 +132,8 @@ protected GradientBrushApplicator( /// calculates the position on the gradient for a given point. /// This method is abstract as it's content depends on the shape of the gradient. /// - /// The x coordinate of the point - /// The y coordinate of the point + /// The x-coordinate of the point. + /// The y-coordinate of the point. /// /// The position the given point has on the gradient. /// The position is not bound to the [0..1] interval. diff --git a/src/ImageSharp.Drawing/Processing/IBrush.cs b/src/ImageSharp.Drawing/Processing/IBrush.cs index 0cd2e20fda..f2fdc32f05 100644 --- a/src/ImageSharp.Drawing/Processing/IBrush.cs +++ b/src/ImageSharp.Drawing/Processing/IBrush.cs @@ -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.PixelFormats; @@ -19,20 +19,22 @@ public interface IBrush /// Creates the applicator for this brush. /// /// The pixel type. + /// The configuration instance to use when performing operations. /// The source image. /// The region the brush will be applied to. /// The graphic options /// - /// The brush applicator for this brush + /// The for this brush. /// /// /// The when being applied to things like shapes would usually be the - /// bounding box of the shape not necessarily the bounds of the whole image + /// bounding box of the shape not necessarily the bounds of the whole image. /// BrushApplicator CreateApplicator( + Configuration configuration, ImageFrame source, RectangleF region, GraphicsOptions options) where TPixel : struct, IPixel; } -} \ No newline at end of file +} diff --git a/src/ImageSharp.Drawing/Processing/ImageBrush.cs b/src/ImageSharp.Drawing/Processing/ImageBrush.cs index ebcc2c0677..f23fb1f18d 100644 --- a/src/ImageSharp.Drawing/Processing/ImageBrush.cs +++ b/src/ImageSharp.Drawing/Processing/ImageBrush.cs @@ -5,7 +5,6 @@ using System.Buffers; using SixLabors.ImageSharp.Advanced; -using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.PixelFormats; using SixLabors.Primitives; @@ -32,6 +31,7 @@ public ImageBrush(Image image) /// public BrushApplicator CreateApplicator( + Configuration configuration, ImageFrame source, RectangleF region, GraphicsOptions options) @@ -39,12 +39,12 @@ public BrushApplicator CreateApplicator( { if (this.image is Image specificImage) { - return new ImageBrushApplicator(source, specificImage, region, options, false); + return new ImageBrushApplicator(configuration, source, specificImage, region, false, options); } specificImage = this.image.CloneAs(); - return new ImageBrushApplicator(source, specificImage, region, options, true); + return new ImageBrushApplicator(configuration, source, specificImage, region, true, options); } /// @@ -79,21 +79,25 @@ private class ImageBrushApplicator : BrushApplicator /// private readonly int offsetX; + private bool isDisposed; + /// /// Initializes a new instance of the class. /// + /// The configuration instance to use when performing operations. /// The target image. /// The image. /// The region. - /// The options /// Whether to dispose the image on disposal of the applicator. + /// The graphics options. public ImageBrushApplicator( + Configuration configuration, ImageFrame target, Image image, RectangleF region, - GraphicsOptions options, - bool shouldDisposeImage) - : base(target, options) + bool shouldDisposeImage, + GraphicsOptions options) + : base(configuration, target, options) { this.sourceImage = image; this.sourceFrame = image.Frames.RootFrame; @@ -104,14 +108,7 @@ public ImageBrushApplicator( this.offsetX = (int)MathF.Max(MathF.Floor(region.Left), 0); } - /// - /// Gets the color for a single pixel. - /// - /// The x. - /// The y. - /// - /// The color - /// + /// internal override TPixel this[int x, int y] { get @@ -123,14 +120,21 @@ public ImageBrushApplicator( } /// - public override void Dispose() + protected override void Dispose(bool disposing) { - if (this.shouldDisposeImage) + if (this.isDisposed) + { + return; + } + + if (disposing && this.shouldDisposeImage) { this.sourceImage?.Dispose(); - this.sourceImage = null; - this.sourceFrame = null; } + + this.sourceImage = null; + this.sourceFrame = null; + this.isDisposed = true; } /// @@ -152,13 +156,12 @@ internal override void Apply(Span scanline, int x, int y) amountSpan[i] = scanline[i] * this.Options.BlendPercentage; int sourceX = (i + offsetX) % this.xLength; - TPixel pixel = sourceRow[sourceX]; - overlaySpan[i] = pixel; + overlaySpan[i] = sourceRow[sourceX]; } Span destinationRow = this.Target.GetPixelRowSpan(y).Slice(x, scanline.Length); this.Blender.Blend( - this.sourceFrame.Configuration, + this.Configuration, destinationRow, destinationRow, overlaySpan, diff --git a/src/ImageSharp.Drawing/Processing/LinearGradientBrush.cs b/src/ImageSharp.Drawing/Processing/LinearGradientBrush.cs index bb99eeb26a..bf6a6356ac 100644 --- a/src/ImageSharp.Drawing/Processing/LinearGradientBrush.cs +++ b/src/ImageSharp.Drawing/Processing/LinearGradientBrush.cs @@ -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 System; @@ -39,10 +39,12 @@ public LinearGradientBrush( /// public override BrushApplicator CreateApplicator( + Configuration configuration, ImageFrame source, RectangleF region, GraphicsOptions options) => new LinearGradientBrushApplicator( + configuration, source, this.p1, this.p2, @@ -93,20 +95,22 @@ private sealed class LinearGradientBrushApplicator : GradientBrushApplic /// /// Initializes a new instance of the class. /// - /// The source - /// start point of the gradient - /// end point of the gradient - /// tuple list of colors and their respective position between 0 and 1 on the line + /// The configuration instance to use when performing operations. + /// The source image. + /// start point of the gradient. + /// end point of the gradient. + /// tuple list of colors and their respective position between 0 and 1 on the line. /// defines how the gradient colors are repeated. - /// the graphics options + /// the graphics options. public LinearGradientBrushApplicator( + Configuration configuration, ImageFrame source, PointF start, PointF end, ColorStop[] colorStops, GradientRepetitionMode repetitionMode, GraphicsOptions options) - : base(source, options, colorStops, repetitionMode) + : base(configuration, source, colorStops, repetitionMode, options) { this.start = start; this.end = end; @@ -148,14 +152,9 @@ protected override float PositionOnGradient(float x, float y) float distance = MathF.Sqrt(MathF.Pow(x4 - this.start.X, 2) + MathF.Pow(y4 - this.start.Y, 2)); // get and return ratio - float ratio = distance / this.length; - return ratio; + return distance / this.length; } } - - public override void Dispose() - { - } } } -} \ No newline at end of file +} diff --git a/src/ImageSharp.Drawing/Processing/PathGradientBrush.cs b/src/ImageSharp.Drawing/Processing/PathGradientBrush.cs index d2ad23a0d9..be1af50118 100644 --- a/src/ImageSharp.Drawing/Processing/PathGradientBrush.cs +++ b/src/ImageSharp.Drawing/Processing/PathGradientBrush.cs @@ -83,12 +83,13 @@ public PathGradientBrush(PointF[] points, Color[] colors) /// public BrushApplicator CreateApplicator( + Configuration configuration, ImageFrame source, RectangleF region, GraphicsOptions options) where TPixel : struct, IPixel { - return new PathGradientBrushApplicator(source, this.edges, this.centerColor, options); + return new PathGradientBrushApplicator(configuration, source, this.edges, this.centerColor, options); } private static Color CalculateCenterColor(Color[] colors) @@ -199,16 +200,18 @@ private class PathGradientBrushApplicator : BrushApplicator /// /// Initializes a new instance of the class. /// + /// The configuration instance to use when performing operations. /// The source image. /// Edges of the polygon. /// Color at the center of the gradient area to which the other colors converge. - /// The options. + /// The graphics options. public PathGradientBrushApplicator( + Configuration configuration, ImageFrame source, IList edges, Color centerColor, GraphicsOptions options) - : base(source, options) + : base(configuration, source, options) { this.edges = edges; @@ -232,7 +235,7 @@ public PathGradientBrushApplicator( return new Color(this.centerColor).ToPixel(); } - Vector2 direction = Vector2.Normalize(point - this.center); + var direction = Vector2.Normalize(point - this.center); PointF end = point + (PointF)(direction * this.maxDistance); @@ -250,7 +253,7 @@ public PathGradientBrushApplicator( float length = DistanceBetween(intersection, this.center); float ratio = length > 0 ? DistanceBetween(intersection, point) / length : 0; - Vector4 color = Vector4.Lerp(edgeColor, this.centerColor, ratio); + var color = Vector4.Lerp(edgeColor, this.centerColor, ratio); return new Color(color).ToPixel(); } @@ -277,11 +280,6 @@ public PathGradientBrushApplicator( return closest; } - - /// - public override void Dispose() - { - } } } } diff --git a/src/ImageSharp.Drawing/Processing/PatternBrush.cs b/src/ImageSharp.Drawing/Processing/PatternBrush.cs index 1b7db970a3..37bb9b0fc0 100644 --- a/src/ImageSharp.Drawing/Processing/PatternBrush.cs +++ b/src/ImageSharp.Drawing/Processing/PatternBrush.cs @@ -92,13 +92,15 @@ internal PatternBrush(PatternBrush brush) /// public BrushApplicator CreateApplicator( + Configuration configuration, ImageFrame source, RectangleF region, GraphicsOptions options) where TPixel : struct, IPixel => new PatternBrushApplicator( + configuration, source, - this.pattern.ToPixelMatrix(source.Configuration), + this.pattern.ToPixelMatrix(configuration), options); /// @@ -115,41 +117,33 @@ private class PatternBrushApplicator : BrushApplicator /// /// Initializes a new instance of the class. /// + /// The configuration instance to use when performing operations. /// The source image. /// The pattern. - /// The options - public PatternBrushApplicator(ImageFrame source, in DenseMatrix pattern, GraphicsOptions options) - : base(source, options) + /// The graphics options. + public PatternBrushApplicator( + Configuration configuration, + ImageFrame source, + in DenseMatrix pattern, + GraphicsOptions options) + : base(configuration, source, options) { this.pattern = pattern; } - /// - /// Gets the color for a single pixel. - /// # - /// The x. - /// The y. - /// - /// The Color. - /// + /// internal override TPixel this[int x, int y] { get { - x = x % this.pattern.Columns; - y = y % this.pattern.Rows; + x %= this.pattern.Columns; + y %= this.pattern.Rows; // 2d array index at row/column return this.pattern[y, x]; } } - /// - public override void Dispose() - { - // noop - } - /// internal override void Apply(Span scanline, int x, int y) { @@ -172,7 +166,7 @@ internal override void Apply(Span scanline, int x, int y) Span destinationRow = this.Target.GetPixelRowSpan(y).Slice(x, scanline.Length); this.Blender.Blend( - this.Target.Configuration, + this.Configuration, destinationRow, destinationRow, overlaySpan, diff --git a/src/ImageSharp.Drawing/Processing/Processors/Drawing/FillProcessor{TPixel}.cs b/src/ImageSharp.Drawing/Processing/Processors/Drawing/FillProcessor{TPixel}.cs index 1dd4be1354..0309c561aa 100644 --- a/src/ImageSharp.Drawing/Processing/Processors/Drawing/FillProcessor{TPixel}.cs +++ b/src/ImageSharp.Drawing/Processing/Processors/Drawing/FillProcessor{TPixel}.cs @@ -45,7 +45,7 @@ protected override void OnFrameApply(ImageFrame source) int width = maxX - minX; - Rectangle workingRect = Rectangle.FromLTRB(minX, minY, maxX, maxY); + var workingRect = Rectangle.FromLTRB(minX, minY, maxX, maxY); IBrush brush = this.definition.Brush; GraphicsOptions options = this.definition.Options; @@ -56,7 +56,7 @@ protected override void OnFrameApply(ImageFrame source) ParallelExecutionSettings parallelSettings = ParallelExecutionSettings.FromConfiguration(configuration) .MultiplyMinimumPixelsPerTask(4); - var colorPixel = solidBrush.Color.ToPixel(); + TPixel colorPixel = solidBrush.Color.ToPixel(); ParallelHelper.IterateRows( workingRect, @@ -84,6 +84,7 @@ protected override void OnFrameApply(ImageFrame source) using (IMemoryOwner amount = source.MemoryAllocator.Allocate(width)) using (BrushApplicator applicator = brush.CreateApplicator( + configuration, source, sourceRectangle, options)) diff --git a/src/ImageSharp.Drawing/Processing/Processors/Drawing/FillRegionProcessor{TPixel}.cs b/src/ImageSharp.Drawing/Processing/Processors/Drawing/FillRegionProcessor{TPixel}.cs index 69f97ce75f..8c665826fe 100644 --- a/src/ImageSharp.Drawing/Processing/Processors/Drawing/FillRegionProcessor{TPixel}.cs +++ b/src/ImageSharp.Drawing/Processing/Processors/Drawing/FillRegionProcessor{TPixel}.cs @@ -71,7 +71,7 @@ protected override void OnFrameApply(ImageFrame source) } } - using (BrushApplicator applicator = brush.CreateApplicator(source, rect, options)) + using (BrushApplicator applicator = brush.CreateApplicator(configuration, source, rect, options)) { int scanlineWidth = maxX - minX; using (IMemoryOwner bBuffer = source.MemoryAllocator.Allocate(maxIntersections)) diff --git a/src/ImageSharp.Drawing/Processing/Processors/Text/DrawTextProcessor{TPixel}.cs b/src/ImageSharp.Drawing/Processing/Processors/Text/DrawTextProcessor{TPixel}.cs index c2e38f67be..8ae6ee4916 100644 --- a/src/ImageSharp.Drawing/Processing/Processors/Text/DrawTextProcessor{TPixel}.cs +++ b/src/ImageSharp.Drawing/Processing/Processors/Text/DrawTextProcessor{TPixel}.cs @@ -83,7 +83,7 @@ void Draw(List operations, IBrush brush) { if (operations?.Count > 0) { - using (BrushApplicator app = brush.CreateApplicator(source, this.SourceRectangle, this.textRenderer.Options)) + using (BrushApplicator app = brush.CreateApplicator(this.Configuration, source, this.SourceRectangle, this.textRenderer.Options)) { foreach (DrawingOperation operation in operations) { diff --git a/src/ImageSharp.Drawing/Processing/RadialGradientBrush.cs b/src/ImageSharp.Drawing/Processing/RadialGradientBrush.cs index f4d2dd81f4..7f1fa818eb 100644 --- a/src/ImageSharp.Drawing/Processing/RadialGradientBrush.cs +++ b/src/ImageSharp.Drawing/Processing/RadialGradientBrush.cs @@ -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 System; @@ -9,7 +9,7 @@ namespace SixLabors.ImageSharp.Processing { /// - /// A Circular Gradient Brush, defined by center point and radius. + /// A radial gradient brush, defined by center point and radius. /// public sealed class RadialGradientBrush : GradientBrush { @@ -35,16 +35,18 @@ public RadialGradientBrush( /// public override BrushApplicator CreateApplicator( + Configuration configuration, ImageFrame source, RectangleF region, GraphicsOptions options) => new RadialGradientBrushApplicator( + configuration, source, - options, this.center, this.radius, this.ColorStops, - this.RepetitionMode); + this.RepetitionMode, + options); /// private sealed class RadialGradientBrushApplicator : GradientBrushApplicator @@ -57,30 +59,27 @@ private sealed class RadialGradientBrushApplicator : GradientBrushApplic /// /// Initializes a new instance of the class. /// - /// The target image - /// The options. + /// The configuration instance to use when performing operations. + /// The target image. /// Center point of the gradient. /// Radius of the gradient. /// Definition of colors. /// How the colors are repeated beyond the first gradient. + /// The graphics options. public RadialGradientBrushApplicator( + Configuration configuration, ImageFrame target, - GraphicsOptions options, PointF center, float radius, ColorStop[] colorStops, - GradientRepetitionMode repetitionMode) - : base(target, options, colorStops, repetitionMode) + GradientRepetitionMode repetitionMode, + GraphicsOptions options) + : base(configuration, target, colorStops, repetitionMode, options) { this.center = center; this.radius = radius; } - /// - public override void Dispose() - { - } - /// /// As this is a circular gradient, the position on the gradient is based on /// the distance of the point to the center. @@ -90,6 +89,7 @@ public override void Dispose() /// the position on the color gradient. protected override float PositionOnGradient(float x, float y) { + // TODO: Can this not use Vector2 distance? float distance = MathF.Sqrt(MathF.Pow(this.center.X - x, 2) + MathF.Pow(this.center.Y - y, 2)); return distance / this.radius; } @@ -101,4 +101,4 @@ internal override void Apply(Span scanline, int x, int y) } } } -} \ No newline at end of file +} diff --git a/src/ImageSharp.Drawing/Processing/RecolorBrush.cs b/src/ImageSharp.Drawing/Processing/RecolorBrush.cs index d93110972c..1ad613bf82 100644 --- a/src/ImageSharp.Drawing/Processing/RecolorBrush.cs +++ b/src/ImageSharp.Drawing/Processing/RecolorBrush.cs @@ -5,7 +5,6 @@ using System.Buffers; using System.Numerics; using SixLabors.ImageSharp.Advanced; -using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.PixelFormats; using SixLabors.Memory; using SixLabors.Primitives; @@ -38,9 +37,6 @@ public RecolorBrush(Color sourceColor, Color targetColor, float threshold) /// /// Gets the source color. /// - /// - /// The color of the source. - /// public Color SourceColor { get; } /// @@ -50,12 +46,14 @@ public RecolorBrush(Color sourceColor, Color targetColor, float threshold) /// public BrushApplicator CreateApplicator( + Configuration configuration, ImageFrame source, RectangleF region, GraphicsOptions options) where TPixel : struct, IPixel { return new RecolorBrushApplicator( + configuration, source, this.SourceColor.ToPixel(), this.TargetColor.ToPixel(), @@ -74,11 +72,6 @@ private class RecolorBrushApplicator : BrushApplicator /// private readonly Vector4 sourceColor; - /// - /// The target color. - /// - private readonly Vector4 targetColor; - /// /// The threshold. /// @@ -89,16 +82,22 @@ private class RecolorBrushApplicator : BrushApplicator /// /// Initializes a new instance of the class. /// + /// The configuration instance to use when performing operations. /// The source image. /// Color of the source. /// Color of the target. /// The threshold . /// The options - public RecolorBrushApplicator(ImageFrame source, TPixel sourceColor, TPixel targetColor, float threshold, GraphicsOptions options) - : base(source, options) + public RecolorBrushApplicator( + Configuration configuration, + ImageFrame source, + TPixel sourceColor, + TPixel targetColor, + float threshold, + GraphicsOptions options) + : base(configuration, source, options) { this.sourceColor = sourceColor.ToVector4(); - this.targetColor = targetColor.ToVector4(); this.targetColorPixel = targetColor; // Lets hack a min max extremes for a color space by letting the IPackedPixel clamp our values to something in the correct spaces :) @@ -109,14 +108,7 @@ public RecolorBrushApplicator(ImageFrame source, TPixel sourceColor, TPi this.threshold = Vector4.DistanceSquared(maxColor.ToVector4(), minColor.ToVector4()) * threshold; } - /// - /// Gets the color for a single pixel. - /// - /// The x. - /// The y. - /// - /// The color - /// + /// internal override TPixel this[int x, int y] { get @@ -138,11 +130,6 @@ public RecolorBrushApplicator(ImageFrame source, TPixel sourceColor, TPi } } - /// - public override void Dispose() - { - } - /// internal override void Apply(Span scanline, int x, int y) { @@ -167,7 +154,7 @@ internal override void Apply(Span scanline, int x, int y) Span destinationRow = this.Target.GetPixelRowSpan(y).Slice(x, scanline.Length); this.Blender.Blend( - this.Target.Configuration, + this.Configuration, destinationRow, destinationRow, overlaySpan, diff --git a/src/ImageSharp.Drawing/Processing/SolidBrush.cs b/src/ImageSharp.Drawing/Processing/SolidBrush.cs index 71738de52b..a2be775daa 100644 --- a/src/ImageSharp.Drawing/Processing/SolidBrush.cs +++ b/src/ImageSharp.Drawing/Processing/SolidBrush.cs @@ -5,7 +5,6 @@ using System.Buffers; using SixLabors.ImageSharp.Advanced; -using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.PixelFormats; using SixLabors.Memory; using SixLabors.Primitives; @@ -17,33 +16,29 @@ namespace SixLabors.ImageSharp.Processing /// public class SolidBrush : IBrush { - /// - /// The color to paint. - /// - private readonly Color color; - /// /// Initializes a new instance of the class. /// /// The color. public SolidBrush(Color color) { - this.color = color; + this.Color = color; } /// /// Gets the color. /// - /// - /// The color. - /// - public Color Color => this.color; + public Color Color { get; } /// - public BrushApplicator CreateApplicator(ImageFrame source, RectangleF region, GraphicsOptions options) + public BrushApplicator CreateApplicator( + Configuration configuration, + ImageFrame source, + RectangleF region, + GraphicsOptions options) where TPixel : struct, IPixel { - return new SolidBrushApplicator(source, this.color.ToPixel(), options); + return new SolidBrushApplicator(configuration, source, this.Color.ToPixel(), options); } /// @@ -52,14 +47,21 @@ public BrushApplicator CreateApplicator(ImageFrame sourc private class SolidBrushApplicator : BrushApplicator where TPixel : struct, IPixel { + private bool isDisposed; + /// /// Initializes a new instance of the class. /// + /// The configuration instance to use when performing operations. /// The source image. /// The color. - /// The options - public SolidBrushApplicator(ImageFrame source, TPixel color, GraphicsOptions options) - : base(source, options) + /// The graphics options. + public SolidBrushApplicator( + Configuration configuration, + ImageFrame source, + TPixel color, + GraphicsOptions options) + : base(configuration, source, options) { this.Colors = source.MemoryAllocator.Allocate(source.Width); this.Colors.Memory.Span.Fill(color); @@ -68,22 +70,26 @@ public SolidBrushApplicator(ImageFrame source, TPixel color, GraphicsOpt /// /// Gets the colors. /// - protected IMemoryOwner Colors { get; } + protected IMemoryOwner Colors { get; private set; } - /// - /// Gets the color for a single pixel. - /// - /// The x. - /// The y. - /// - /// The color - /// + /// internal override TPixel this[int x, int y] => this.Colors.Memory.Span[x]; /// - public override void Dispose() + protected override void Dispose(bool disposing) { - this.Colors.Dispose(); + if (this.isDisposed) + { + return; + } + + if (disposing) + { + this.Colors.Dispose(); + } + + this.Colors = null; + this.isDisposed = true; } /// @@ -102,7 +108,7 @@ internal override void Apply(Span scanline, int x, int y) } MemoryAllocator memoryAllocator = this.Target.MemoryAllocator; - Configuration configuration = this.Target.Configuration; + Configuration configuration = this.Configuration; if (this.Options.BlendPercentage == 1f) { diff --git a/src/ImageSharp.Drawing/Utils/QuickSort.cs b/src/ImageSharp.Drawing/Utils/QuickSort.cs index ca1da5505a..14e3146a0b 100644 --- a/src/ImageSharp.Drawing/Utils/QuickSort.cs +++ b/src/ImageSharp.Drawing/Utils/QuickSort.cs @@ -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 System; From f7eed913d65537fcd63ca241b420840f53cd9f6e Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Wed, 6 Nov 2019 21:35:57 +1100 Subject: [PATCH 06/16] Fix float clamp accessibility. --- .../Processing/PatternBrush.cs | 2 +- .../Processing/TextGraphicsOptions.cs | 12 ++++---- src/ImageSharp.Drawing/Utils/NumberUtils.cs | 29 +++++++++++++++++++ 3 files changed, 36 insertions(+), 7 deletions(-) create mode 100644 src/ImageSharp.Drawing/Utils/NumberUtils.cs diff --git a/src/ImageSharp.Drawing/Processing/PatternBrush.cs b/src/ImageSharp.Drawing/Processing/PatternBrush.cs index 37bb9b0fc0..9024036d02 100644 --- a/src/ImageSharp.Drawing/Processing/PatternBrush.cs +++ b/src/ImageSharp.Drawing/Processing/PatternBrush.cs @@ -158,7 +158,7 @@ internal override void Apply(Span scanline, int x, int y) for (int i = 0; i < scanline.Length; i++) { - amountSpan[i] = (scanline[i] * this.Options.BlendPercentage).Clamp(0, 1); + amountSpan[i] = NumberUtils.ClampFloat(scanline[i] * this.Options.BlendPercentage, 0, 1F); int patternX = (x + i) % this.pattern.Columns; overlaySpan[i] = this.pattern[patternY, patternX]; diff --git a/src/ImageSharp.Drawing/Processing/TextGraphicsOptions.cs b/src/ImageSharp.Drawing/Processing/TextGraphicsOptions.cs index 6c140be72e..13c7f4bdf9 100644 --- a/src/ImageSharp.Drawing/Processing/TextGraphicsOptions.cs +++ b/src/ImageSharp.Drawing/Processing/TextGraphicsOptions.cs @@ -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.Fonts; @@ -11,13 +11,13 @@ namespace SixLabors.ImageSharp.Processing /// public struct TextGraphicsOptions { - private const int DefaultTextDpi = 72; - /// /// Represents the default . /// public static readonly TextGraphicsOptions Default = new TextGraphicsOptions(true); + private const int DefaultTextDpi = 72; + private float? blendPercentage; private int? antialiasSubpixelDepth; @@ -51,7 +51,7 @@ public TextGraphicsOptions(bool enableAntialiasing) this.antialiasSubpixelDepth = 16; this.ColorBlendingMode = PixelColorBlendingMode.Normal; this.AlphaCompositionMode = PixelAlphaCompositionMode.SrcOver; - this.blendPercentage = 1; + this.blendPercentage = 1F; this.antialias = enableAntialiasing; this.dpiX = DefaultTextDpi; this.dpiY = DefaultTextDpi; @@ -70,7 +70,7 @@ public TextGraphicsOptions(bool enableAntialiasing) /// /// Gets or sets a value indicating the blending percentage to apply to the drawing operation /// - public float BlendPercentage { get => (this.blendPercentage ?? 1).Clamp(0, 1); set => this.blendPercentage = value; } + public float BlendPercentage { get => this.blendPercentage ?? 1F; set => this.blendPercentage = NumberUtils.ClampFloat(value, 0, 1F); } // In the future we could expose a PixelBlender directly on here // or some forms of PixelBlender factory for each pixel type. Will need @@ -160,4 +160,4 @@ public static explicit operator GraphicsOptions(TextGraphicsOptions options) }; } } -} \ No newline at end of file +} diff --git a/src/ImageSharp.Drawing/Utils/NumberUtils.cs b/src/ImageSharp.Drawing/Utils/NumberUtils.cs new file mode 100644 index 0000000000..d034c5d7ed --- /dev/null +++ b/src/ImageSharp.Drawing/Utils/NumberUtils.cs @@ -0,0 +1,29 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System.Runtime.CompilerServices; + +namespace SixLabors.ImageSharp +{ + /// + /// Utility methods for numeric primitives. + /// + internal static class NumberUtils + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static float ClampFloat(float value, float min, float max) + { + if (value >= max) + { + return max; + } + + if (value <= min) + { + return min; + } + + return value; + } + } +} From ff023b833e3dee44c6bd01b6b17099afc397d435 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Fri, 8 Nov 2019 17:10:31 +1100 Subject: [PATCH 07/16] Fix #1044 --- .../Processing/GradientBrush.cs | 8 ++-- src/ImageSharp/ImageSharp.csproj | 4 +- .../Drawing/FillLinearGradientBrushTests.cs | 44 ++++++++++++++++++- tests/Images/External | 2 +- 4 files changed, 48 insertions(+), 10 deletions(-) diff --git a/src/ImageSharp.Drawing/Processing/GradientBrush.cs b/src/ImageSharp.Drawing/Processing/GradientBrush.cs index 044f4e2ee8..69659431d0 100644 --- a/src/ImageSharp.Drawing/Processing/GradientBrush.cs +++ b/src/ImageSharp.Drawing/Processing/GradientBrush.cs @@ -2,7 +2,7 @@ // Licensed under the Apache License, Version 2.0. using System; - +using System.Numerics; using SixLabors.ImageSharp.PixelFormats; using SixLabors.Primitives; @@ -120,10 +120,8 @@ protected GradientBrushApplicator( float onLocalGradient = (positionOnCompleteGradient - from.Ratio) / (to.Ratio - from.Ratio); // TODO: this should be changeble for different gradienting functions. - // TODO: Why not use Blender property? - return PixelOperations - .Instance.GetPixelBlender(PixelColorBlendingMode.Normal, PixelAlphaCompositionMode.SrcOver) - .Blend(from.Color.ToPixel(), to.Color.ToPixel(), onLocalGradient); + // TODO: Is the comment above still relevent? + return new Color(Vector4.Lerp((Vector4)from.Color, (Vector4)to.Color, onLocalGradient)).ToPixel(); } } } diff --git a/src/ImageSharp/ImageSharp.csproj b/src/ImageSharp/ImageSharp.csproj index d9e9a8d219..86b0848663 100644 --- a/src/ImageSharp/ImageSharp.csproj +++ b/src/ImageSharp/ImageSharp.csproj @@ -1,4 +1,4 @@ - + @@ -119,7 +119,7 @@ - + diff --git a/tests/ImageSharp.Tests/Drawing/FillLinearGradientBrushTests.cs b/tests/ImageSharp.Tests/Drawing/FillLinearGradientBrushTests.cs index 361e7e70d1..8aae342cba 100644 --- a/tests/ImageSharp.Tests/Drawing/FillLinearGradientBrushTests.cs +++ b/tests/ImageSharp.Tests/Drawing/FillLinearGradientBrushTests.cs @@ -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 System; @@ -16,6 +16,8 @@ namespace SixLabors.ImageSharp.Tests.Drawing { using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison; + using SixLabors.Primitives; + using SixLabors.Shapes; [GroupOutput("Drawing/GradientBrushes")] public class FillLinearGradientBrushTests @@ -392,5 +394,43 @@ public void MultiplePointGradients( false, false); } + + [Theory] + [WithBlankImages(200, 200, PixelTypes.Rgba32)] + public void GradientsWithTransparencyOnExistingBackground(TestImageProvider provider) + where TPixel : struct, IPixel + { + provider.VerifyOperation( + image => + { + image.Mutate(i => i.Fill(Color.Red)); + image.Mutate(ApplyGloss); + + }); + + void ApplyGloss(IImageProcessingContext ctx) + { + Size size = ctx.GetCurrentSize(); + IPathCollection glossPath = BuildGloss(size.Width, size.Height); + var graphicsOptions = new GraphicsOptions(true) + { + ColorBlendingMode = PixelColorBlendingMode.Normal, + AlphaCompositionMode = PixelAlphaCompositionMode.SrcAtop + }; + var linearGradientBrush = new LinearGradientBrush(new Point(0, 0), new Point(0, size.Height / 2), GradientRepetitionMode.Repeat, new ColorStop(0, Color.White.WithAlpha(0.5f)), new ColorStop(1, Color.White.WithAlpha(0.25f))); + ctx.Fill(graphicsOptions, linearGradientBrush, glossPath); + } + + IPathCollection BuildGloss(int imageWidth, int imageHeight) + { + var pathBuilder = new PathBuilder(); + pathBuilder.AddLine(new PointF(0, 0), new PointF(imageWidth, 0)); + pathBuilder.AddLine(new PointF(imageWidth, 0), new PointF(imageWidth, imageHeight * 0.4f)); + pathBuilder.AddBezier(new PointF(imageWidth, imageHeight * 0.4f), new PointF(imageWidth / 2, imageHeight * 0.6f), new PointF(0, imageHeight * 0.4f)); + pathBuilder.CloseFigure(); + return new PathCollection(pathBuilder.Build()); + } + } + } -} \ No newline at end of file +} diff --git a/tests/Images/External b/tests/Images/External index 563ec6f777..f0c4033667 160000 --- a/tests/Images/External +++ b/tests/Images/External @@ -1 +1 @@ -Subproject commit 563ec6f7774734ba39924174c8961705a1ea6fa2 +Subproject commit f0c4033667bd23ad9dde82ccb625c232d402ee05 From 87f494713d98e7adbe8b6d886b1af50bb02e45af Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Sat, 9 Nov 2019 21:26:48 +1100 Subject: [PATCH 08/16] Convert options into classes. --- .../Processing/GradientBrush.cs | 3 - .../Processing/TextGraphicsOptions.cs | 140 ++++++++++++------ src/ImageSharp/GraphicsOptions.cs | 120 ++++++++------- .../Drawing/Paths/DrawPathCollection.cs | 2 +- .../Drawing/Paths/FillPath.cs | 2 +- .../Drawing/Paths/FillPathCollection.cs | 2 +- .../Drawing/Paths/FillPolygon.cs | 2 +- .../Drawing/Paths/FillRectangle.cs | 4 +- .../PorterDuffCompositorTests.cs | 11 +- 9 files changed, 174 insertions(+), 112 deletions(-) diff --git a/src/ImageSharp.Drawing/Processing/GradientBrush.cs b/src/ImageSharp.Drawing/Processing/GradientBrush.cs index 69659431d0..f17adf6335 100644 --- a/src/ImageSharp.Drawing/Processing/GradientBrush.cs +++ b/src/ImageSharp.Drawing/Processing/GradientBrush.cs @@ -118,9 +118,6 @@ protected GradientBrushApplicator( else { float onLocalGradient = (positionOnCompleteGradient - from.Ratio) / (to.Ratio - from.Ratio); - - // TODO: this should be changeble for different gradienting functions. - // TODO: Is the comment above still relevent? return new Color(Vector4.Lerp((Vector4)from.Color, (Vector4)to.Color, onLocalGradient)).ToPixel(); } } diff --git a/src/ImageSharp.Drawing/Processing/TextGraphicsOptions.cs b/src/ImageSharp.Drawing/Processing/TextGraphicsOptions.cs index 13c7f4bdf9..23d7aebf58 100644 --- a/src/ImageSharp.Drawing/Processing/TextGraphicsOptions.cs +++ b/src/ImageSharp.Drawing/Processing/TextGraphicsOptions.cs @@ -1,6 +1,7 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. +using System; using SixLabors.Fonts; using SixLabors.ImageSharp.PixelFormats; @@ -9,68 +10,87 @@ namespace SixLabors.ImageSharp.Processing /// /// Options for influencing the drawing functions. /// - public struct TextGraphicsOptions + public class TextGraphicsOptions { + private static readonly Lazy Lazy = new Lazy(); + private int antialiasSubpixelDepth; + private float blendPercentage; + private float tabWidth; + private float dpiX; + private float dpiY; + /// - /// Represents the default . + /// Initializes a new instance of the class. /// - public static readonly TextGraphicsOptions Default = new TextGraphicsOptions(true); - - private const int DefaultTextDpi = 72; - - private float? blendPercentage; - - private int? antialiasSubpixelDepth; - - private bool? antialias; - - private bool? applyKerning; - - private float? tabWidth; - - private float? dpiX; - - private float? dpiY; - - private HorizontalAlignment? horizontalAlignment; - - private VerticalAlignment? verticalAlignment; + public TextGraphicsOptions() + : this(true) + { + } /// - /// Initializes a new instance of the struct. + /// Initializes a new instance of the class. /// /// If set to true [enable antialiasing]. public TextGraphicsOptions(bool enableAntialiasing) { - this.applyKerning = true; - this.tabWidth = 4; + this.ApplyKerning = true; + this.TabWidth = 4F; this.WrapTextWidth = 0; - this.horizontalAlignment = HorizontalAlignment.Left; - this.verticalAlignment = VerticalAlignment.Top; + this.HorizontalAlignment = HorizontalAlignment.Left; + this.VerticalAlignment = VerticalAlignment.Top; this.antialiasSubpixelDepth = 16; this.ColorBlendingMode = PixelColorBlendingMode.Normal; this.AlphaCompositionMode = PixelAlphaCompositionMode.SrcOver; this.blendPercentage = 1F; - this.antialias = enableAntialiasing; - this.dpiX = DefaultTextDpi; - this.dpiY = DefaultTextDpi; + this.Antialias = enableAntialiasing; + this.dpiX = 72F; + this.dpiY = 72F; } + /// + /// Gets the default instance. + /// + public static TextGraphicsOptions Default { get; } = Lazy.Value; + /// /// Gets or sets a value indicating whether antialiasing should be applied. /// - public bool Antialias { get => this.antialias ?? true; set => this.antialias = value; } + public bool Antialias { get; set; } /// /// Gets or sets a value indicating the number of subpixels to use while rendering with antialiasing enabled. /// - public int AntialiasSubpixelDepth { get => this.antialiasSubpixelDepth ?? 16; set => this.antialiasSubpixelDepth = value; } + public int AntialiasSubpixelDepth + { + get + { + return this.antialiasSubpixelDepth; + } + + set + { + Guard.MustBeGreaterThanOrEqualTo(value, 0, nameof(this.AntialiasSubpixelDepth)); + this.antialiasSubpixelDepth = value; + } + } /// - /// Gets or sets a value indicating the blending percentage to apply to the drawing operation + /// Gets or sets a value indicating the blending percentage to apply to the drawing operation. /// - public float BlendPercentage { get => this.blendPercentage ?? 1F; set => this.blendPercentage = NumberUtils.ClampFloat(value, 0, 1F); } + public float BlendPercentage + { + get + { + return this.blendPercentage; + } + + set + { + Guard.MustBeBetweenOrEqualTo(value, 0, 1F, nameof(this.BlendPercentage)); + this.blendPercentage = value; + } + } // In the future we could expose a PixelBlender directly on here // or some forms of PixelBlender factory for each pixel type. Will need @@ -89,27 +109,63 @@ public TextGraphicsOptions(bool enableAntialiasing) /// /// Gets or sets a value indicating whether the text should be drawing with kerning enabled. /// - public bool ApplyKerning { get => this.applyKerning ?? true; set => this.applyKerning = value; } + public bool ApplyKerning { get; set; } /// /// Gets or sets a value indicating the number of space widths a tab should lock to. /// - public float TabWidth { get => this.tabWidth ?? 4; set => this.tabWidth = value; } + public float TabWidth + { + get + { + return this.tabWidth; + } + + set + { + Guard.MustBeGreaterThanOrEqualTo(value, 0, nameof(this.TabWidth)); + this.tabWidth = value; + } + } /// - /// Gets or sets a value indicating if greater than zero determine the width at which text should wrap. + /// Gets or sets a value, if greater than 0, indicating the width at which text should wrap. /// public float WrapTextWidth { get; set; } /// /// Gets or sets a value indicating the DPI to render text along the X axis. /// - public float DpiX { get => this.dpiX ?? DefaultTextDpi; set => this.dpiX = value; } + public float DpiX + { + get + { + return this.dpiX; + } + + set + { + Guard.MustBeGreaterThanOrEqualTo(value, 0, nameof(this.DpiX)); + this.dpiX = value; + } + } /// /// Gets or sets a value indicating the DPI to render text along the Y axis. /// - public float DpiY { get => this.dpiY ?? DefaultTextDpi; set => this.dpiY = value; } + public float DpiY + { + get + { + return this.dpiY; + } + + set + { + Guard.MustBeGreaterThanOrEqualTo(value, 0, nameof(this.DpiY)); + this.dpiY = value; + } + } /// /// Gets or sets a value indicating how to align the text relative to the rendering space. @@ -117,12 +173,12 @@ public TextGraphicsOptions(bool enableAntialiasing) /// defined by the location and width, if equals zero, and thus /// wrapping disabled, then the alignment is relative to the drawing location. /// - public HorizontalAlignment HorizontalAlignment { get => this.horizontalAlignment ?? HorizontalAlignment.Left; set => this.horizontalAlignment = value; } + public HorizontalAlignment HorizontalAlignment { get; set; } /// /// Gets or sets a value indicating how to align the text relative to the rendering space. /// - public VerticalAlignment VerticalAlignment { get => this.verticalAlignment ?? VerticalAlignment.Top; set => this.verticalAlignment = value; } + public VerticalAlignment VerticalAlignment { get; set; } /// /// Performs an implicit conversion from to . diff --git a/src/ImageSharp/GraphicsOptions.cs b/src/ImageSharp/GraphicsOptions.cs index 644bde1cff..1e18edb4ae 100644 --- a/src/ImageSharp/GraphicsOptions.cs +++ b/src/ImageSharp/GraphicsOptions.cs @@ -1,6 +1,7 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. +using System; using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp @@ -8,108 +9,115 @@ namespace SixLabors.ImageSharp /// /// Options for influencing the drawing functions. /// - public struct GraphicsOptions + public class GraphicsOptions { + private static readonly Lazy Lazy = new Lazy(); + private int antialiasSubpixelDepth; + private float blendPercentage; + /// - /// Represents the default . + /// Initializes a new instance of the class. /// - public static readonly GraphicsOptions Default = new GraphicsOptions(true); - - private float? blendPercentage; - - private int? antialiasSubpixelDepth; - - private bool? antialias; + public GraphicsOptions() + : this(true) + { + } /// - /// Initializes a new instance of the struct. + /// Initializes a new instance of the class. /// /// If set to true [enable antialiasing]. public GraphicsOptions(bool enableAntialiasing) + : this(enableAntialiasing, 1F) { - this.ColorBlendingMode = PixelColorBlendingMode.Normal; - this.AlphaCompositionMode = PixelAlphaCompositionMode.SrcOver; - this.blendPercentage = 1; - this.antialiasSubpixelDepth = 16; - this.antialias = enableAntialiasing; } /// - /// Initializes a new instance of the struct. + /// Initializes a new instance of the class. /// /// If set to true [enable antialiasing]. - /// blending percentage to apply to the drawing operation - public GraphicsOptions(bool enableAntialiasing, float opacity) + /// The blending percentage to apply to the drawing operation + public GraphicsOptions(bool enableAntialiasing, float blendPercentage) + : this(enableAntialiasing, PixelColorBlendingMode.Normal, blendPercentage) { - Guard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); - - this.ColorBlendingMode = PixelColorBlendingMode.Normal; - this.AlphaCompositionMode = PixelAlphaCompositionMode.SrcOver; - this.blendPercentage = opacity; - this.antialiasSubpixelDepth = 16; - this.antialias = enableAntialiasing; } /// - /// Initializes a new instance of the struct. + /// Initializes a new instance of the class. /// /// If set to true [enable antialiasing]. - /// blending percentage to apply to the drawing operation - /// color blending mode to apply to the drawing operation - public GraphicsOptions(bool enableAntialiasing, PixelColorBlendingMode blending, float opacity) + /// The color blending mode to apply to the drawing operation + /// The blending percentage to apply to the drawing operation + public GraphicsOptions( + bool enableAntialiasing, + PixelColorBlendingMode blending, + float blendPercentage) + : this(enableAntialiasing, blending, PixelAlphaCompositionMode.SrcOver, blendPercentage) { - Guard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); - - this.ColorBlendingMode = blending; - this.AlphaCompositionMode = PixelAlphaCompositionMode.SrcOver; - this.blendPercentage = opacity; - this.antialiasSubpixelDepth = 16; - this.antialias = enableAntialiasing; } /// - /// Initializes a new instance of the struct. + /// Initializes a new instance of the class. /// /// If set to true [enable antialiasing]. - /// blending percentage to apply to the drawing operation - /// color blending mode to apply to the drawing operation - /// alpha composition mode to apply to the drawing operation - public GraphicsOptions(bool enableAntialiasing, PixelColorBlendingMode blending, PixelAlphaCompositionMode composition, float opacity) + /// The color blending mode to apply to the drawing operation + /// The alpha composition mode to apply to the drawing operation + /// The blending percentage to apply to the drawing operation + public GraphicsOptions( + bool enableAntialiasing, + PixelColorBlendingMode blending, + PixelAlphaCompositionMode composition, + float blendPercentage) { - Guard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); - this.ColorBlendingMode = blending; this.AlphaCompositionMode = composition; - this.blendPercentage = opacity; - this.antialiasSubpixelDepth = 16; - this.antialias = enableAntialiasing; + this.BlendPercentage = blendPercentage; + this.AntialiasSubpixelDepth = 16; + this.Antialias = enableAntialiasing; } + /// + /// Gets the default instance. + /// + public static GraphicsOptions Default { get; } = Lazy.Value; + /// /// Gets or sets a value indicating whether antialiasing should be applied. /// - public bool Antialias - { - get => this.antialias ?? true; - set => this.antialias = value; - } + public bool Antialias { get; set; } /// /// Gets or sets a value indicating the number of subpixels to use while rendering with antialiasing enabled. /// public int AntialiasSubpixelDepth { - get => this.antialiasSubpixelDepth ?? 16; - set => this.antialiasSubpixelDepth = value; + get + { + return this.antialiasSubpixelDepth; + } + + set + { + Guard.MustBeGreaterThanOrEqualTo(value, 0, nameof(this.AntialiasSubpixelDepth)); + this.antialiasSubpixelDepth = value; + } } /// - /// Gets or sets a value indicating the blending percentage to apply to the drawing operation + /// Gets or sets a value indicating the blending percentage to apply to the drawing operation. /// public float BlendPercentage { - get => (this.blendPercentage ?? 1).Clamp(0, 1); - set => this.blendPercentage = value; + get + { + return this.blendPercentage; + } + + set + { + Guard.MustBeBetweenOrEqualTo(value, 0, 1F, nameof(this.BlendPercentage)); + this.blendPercentage = value; + } } // In the future we could expose a PixelBlender directly on here diff --git a/tests/ImageSharp.Tests/Drawing/Paths/DrawPathCollection.cs b/tests/ImageSharp.Tests/Drawing/Paths/DrawPathCollection.cs index 3691b54ce3..5d309d2995 100644 --- a/tests/ImageSharp.Tests/Drawing/Paths/DrawPathCollection.cs +++ b/tests/ImageSharp.Tests/Drawing/Paths/DrawPathCollection.cs @@ -14,7 +14,7 @@ namespace SixLabors.ImageSharp.Tests.Drawing.Paths { public class DrawPathCollection : BaseImageOperationsExtensionTest { - GraphicsOptions noneDefault = new GraphicsOptions(); + GraphicsOptions noneDefault = new GraphicsOptions(false); Color color = Color.HotPink; Pen pen = Pens.Solid(Rgba32.HotPink, 1); IPath path1 = new Path(new LinearLineSegment(new SixLabors.Primitives.PointF[] { diff --git a/tests/ImageSharp.Tests/Drawing/Paths/FillPath.cs b/tests/ImageSharp.Tests/Drawing/Paths/FillPath.cs index 160ff22a3e..cb247ac039 100644 --- a/tests/ImageSharp.Tests/Drawing/Paths/FillPath.cs +++ b/tests/ImageSharp.Tests/Drawing/Paths/FillPath.cs @@ -14,7 +14,7 @@ namespace SixLabors.ImageSharp.Tests.Drawing.Paths { public class FillPath : BaseImageOperationsExtensionTest { - GraphicsOptions noneDefault = new GraphicsOptions(); + GraphicsOptions noneDefault = new GraphicsOptions(false); Color color = Color.HotPink; SolidBrush brush = Brushes.Solid(Rgba32.HotPink); IPath path = new Path(new LinearLineSegment(new SixLabors.Primitives.PointF[] { diff --git a/tests/ImageSharp.Tests/Drawing/Paths/FillPathCollection.cs b/tests/ImageSharp.Tests/Drawing/Paths/FillPathCollection.cs index b76ee8ffcd..0c4d6ca3ca 100644 --- a/tests/ImageSharp.Tests/Drawing/Paths/FillPathCollection.cs +++ b/tests/ImageSharp.Tests/Drawing/Paths/FillPathCollection.cs @@ -14,7 +14,7 @@ namespace SixLabors.ImageSharp.Tests.Drawing.Paths { public class FillPathCollection : BaseImageOperationsExtensionTest { - GraphicsOptions noneDefault = new GraphicsOptions(); + GraphicsOptions noneDefault = new GraphicsOptions(false); Color color = Color.HotPink; SolidBrush brush = Brushes.Solid(Rgba32.HotPink); IPath path1 = new Path(new LinearLineSegment(new SixLabors.Primitives.PointF[] { diff --git a/tests/ImageSharp.Tests/Drawing/Paths/FillPolygon.cs b/tests/ImageSharp.Tests/Drawing/Paths/FillPolygon.cs index c62a871481..06a7348427 100644 --- a/tests/ImageSharp.Tests/Drawing/Paths/FillPolygon.cs +++ b/tests/ImageSharp.Tests/Drawing/Paths/FillPolygon.cs @@ -14,7 +14,7 @@ namespace SixLabors.ImageSharp.Tests.Drawing.Paths { public class FillPolygon : BaseImageOperationsExtensionTest { - GraphicsOptions noneDefault = new GraphicsOptions(); + GraphicsOptions noneDefault = new GraphicsOptions(false); Color color = Color.HotPink; SolidBrush brush = Brushes.Solid(Rgba32.HotPink); SixLabors.Primitives.PointF[] path = { diff --git a/tests/ImageSharp.Tests/Drawing/Paths/FillRectangle.cs b/tests/ImageSharp.Tests/Drawing/Paths/FillRectangle.cs index 17a2b87c0e..c1ad059a85 100644 --- a/tests/ImageSharp.Tests/Drawing/Paths/FillRectangle.cs +++ b/tests/ImageSharp.Tests/Drawing/Paths/FillRectangle.cs @@ -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.PixelFormats; @@ -13,7 +13,7 @@ namespace SixLabors.ImageSharp.Tests.Drawing.Paths { public class FillRectangle : BaseImageOperationsExtensionTest { - GraphicsOptions noneDefault = new GraphicsOptions(); + GraphicsOptions noneDefault = new GraphicsOptions(false); Color color = Color.HotPink; SolidBrush brush = Brushes.Solid(Rgba32.HotPink); SixLabors.Primitives.Rectangle rectangle = new SixLabors.Primitives.Rectangle(10, 10, 77, 76); diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelBlenders/PorterDuffCompositorTests.cs b/tests/ImageSharp.Tests/PixelFormats/PixelBlenders/PorterDuffCompositorTests.cs index 09a78a6aa1..693dd6bd81 100644 --- a/tests/ImageSharp.Tests/PixelFormats/PixelBlenders/PorterDuffCompositorTests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/PixelBlenders/PorterDuffCompositorTests.cs @@ -1,4 +1,4 @@ -// Copyright (c) Six Labors and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelBlenders @@ -36,9 +36,10 @@ public void PorterDuffOutputIsCorrect(TestImageProvider provider, PixelA using (Image src = srcFile.CreateRgba32Image()) using (Image dest = provider.GetImage()) { - GraphicsOptions options = new GraphicsOptions - { - AlphaCompositionMode = mode + var options = new GraphicsOptions + { + Antialias = false, + AlphaCompositionMode = mode }; using (Image res = dest.Clone(x => x.DrawImage(src, options))) @@ -53,4 +54,4 @@ public void PorterDuffOutputIsCorrect(TestImageProvider provider, PixelA } } } -} \ No newline at end of file +} From 86c056a38e7e3fcc7c5f08784891af47f138babf Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Sat, 9 Nov 2019 21:54:48 +1100 Subject: [PATCH 09/16] Fix MemoryAllocator access. --- .../Processing/Processors/Text/DrawTextProcessor{TPixel}.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ImageSharp.Drawing/Processing/Processors/Text/DrawTextProcessor{TPixel}.cs b/src/ImageSharp.Drawing/Processing/Processors/Text/DrawTextProcessor{TPixel}.cs index 8ae6ee4916..244e18b81c 100644 --- a/src/ImageSharp.Drawing/Processing/Processors/Text/DrawTextProcessor{TPixel}.cs +++ b/src/ImageSharp.Drawing/Processing/Processors/Text/DrawTextProcessor{TPixel}.cs @@ -59,7 +59,7 @@ protected override void BeforeImageApply() VerticalAlignment = this.Options.VerticalAlignment }; - this.textRenderer = new CachingGlyphRenderer(this.Source.GetMemoryAllocator(), this.Text.Length, this.Pen, this.Brush != null); + this.textRenderer = new CachingGlyphRenderer(this.Configuration.MemoryAllocator, this.Text.Length, this.Pen, this.Brush != null); this.textRenderer.Options = (GraphicsOptions)this.Options; var renderer = new TextRenderer(this.textRenderer); renderer.RenderText(this.Text, style); From 58fd88787f8010de1ac4fab714c3ebcaee009185 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Sat, 9 Nov 2019 22:39:23 +1100 Subject: [PATCH 10/16] Expose Allocate2D --- .../Memory/MemoryAllocatorExtensions.cs | 27 ++++++++++++++++--- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/src/ImageSharp/Memory/MemoryAllocatorExtensions.cs b/src/ImageSharp/Memory/MemoryAllocatorExtensions.cs index b596351b5f..a3fa0e1ff1 100644 --- a/src/ImageSharp/Memory/MemoryAllocatorExtensions.cs +++ b/src/ImageSharp/Memory/MemoryAllocatorExtensions.cs @@ -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 System.Buffers; @@ -11,8 +11,18 @@ namespace SixLabors.ImageSharp.Memory /// /// Extension methods for . /// - internal static class MemoryAllocatorExtensions + public static class MemoryAllocatorExtensions { + /// + /// Allocates a buffer of value type objects interpreted as a 2D region + /// of x elements. + /// + /// The type of buffer items to allocate. + /// The memory allocator. + /// The buffer width. + /// The buffer heght. + /// The allocation options. + /// The . public static Buffer2D Allocate2D( this MemoryAllocator memoryAllocator, int width, @@ -26,6 +36,15 @@ public static Buffer2D Allocate2D( return new Buffer2D(memorySource, width, height); } + /// + /// Allocates a buffer of value type objects interpreted as a 2D region + /// of width x height elements. + /// + /// The type of buffer items to allocate. + /// The memory allocator. + /// The buffer size. + /// The allocation options. + /// The . public static Buffer2D Allocate2D( this MemoryAllocator memoryAllocator, Size size, @@ -41,7 +60,7 @@ public static Buffer2D Allocate2D( /// The pixel size in bytes, eg. 3 for RGB /// The padding /// A - public static IManagedByteBuffer AllocatePaddedPixelRowBuffer( + internal static IManagedByteBuffer AllocatePaddedPixelRowBuffer( this MemoryAllocator memoryAllocator, int width, int pixelSizeInBytes, @@ -51,4 +70,4 @@ public static IManagedByteBuffer AllocatePaddedPixelRowBuffer( return memoryAllocator.AllocateManagedByteBuffer(length); } } -} \ No newline at end of file +} From eae0a95e0efae8a135b36cbd27e41d8135bd0526 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Sun, 10 Nov 2019 20:28:55 +1100 Subject: [PATCH 11/16] Simplify options and add clone + tests --- .../Processing/TextGraphicsOptions.cs | 103 +++++++------- .../ImageSharp.Benchmarks/Drawing/DrawText.cs | 10 +- .../Drawing/DrawTextOutline.cs | 14 +- .../Drawing/DrawLinesTests.cs | 22 +-- .../Drawing/DrawPolygonTests.cs | 2 +- .../Drawing/FillLinearGradientBrushTests.cs | 3 +- .../Drawing/FillPolygonTests.cs | 2 +- .../Drawing/FillRegionProcessorTests.cs | 16 +-- .../Drawing/FillSolidBrushTests.cs | 24 ++-- .../Drawing/Paths/DrawPathCollection.cs | 2 +- .../Drawing/Paths/FillPath.cs | 2 +- .../Drawing/Paths/FillPathCollection.cs | 2 +- .../Drawing/Paths/FillPolygon.cs | 2 +- .../Drawing/Paths/FillRectangle.cs | 2 +- .../Drawing/SolidFillBlendedShapesTests.cs | 29 ++-- .../ImageSharp.Tests/Drawing/Text/DrawText.cs | 12 +- .../Drawing/Text/DrawTextOnImageTests.cs | 9 +- .../Drawing/Text/TextGraphicsOptionsTests.cs | 128 +++++++++++++++++- .../ImageSharp.Tests/GraphicsOptionsTests.cs | 65 ++++++++- tests/ImageSharp.Tests/Issues/Issue412.cs | 4 +- .../BaseImageOperationsExtensionTest.cs | 2 +- 21 files changed, 316 insertions(+), 139 deletions(-) diff --git a/src/ImageSharp.Drawing/Processing/TextGraphicsOptions.cs b/src/ImageSharp.Drawing/Processing/TextGraphicsOptions.cs index 23d7aebf58..60a48a31fa 100644 --- a/src/ImageSharp.Drawing/Processing/TextGraphicsOptions.cs +++ b/src/ImageSharp.Drawing/Processing/TextGraphicsOptions.cs @@ -12,51 +12,22 @@ namespace SixLabors.ImageSharp.Processing /// public class TextGraphicsOptions { - private static readonly Lazy Lazy = new Lazy(); - private int antialiasSubpixelDepth; - private float blendPercentage; - private float tabWidth; - private float dpiX; - private float dpiY; - - /// - /// Initializes a new instance of the class. - /// - public TextGraphicsOptions() - : this(true) - { - } - - /// - /// Initializes a new instance of the class. - /// - /// If set to true [enable antialiasing]. - public TextGraphicsOptions(bool enableAntialiasing) - { - this.ApplyKerning = true; - this.TabWidth = 4F; - this.WrapTextWidth = 0; - this.HorizontalAlignment = HorizontalAlignment.Left; - this.VerticalAlignment = VerticalAlignment.Top; - - this.antialiasSubpixelDepth = 16; - this.ColorBlendingMode = PixelColorBlendingMode.Normal; - this.AlphaCompositionMode = PixelAlphaCompositionMode.SrcOver; - this.blendPercentage = 1F; - this.Antialias = enableAntialiasing; - this.dpiX = 72F; - this.dpiY = 72F; - } + private int antialiasSubpixelDepth = 16; + private float blendPercentage = 1F; + private float tabWidth = 4F; + private float dpiX = 72F; + private float dpiY = 72F; /// /// Gets the default instance. /// - public static TextGraphicsOptions Default { get; } = Lazy.Value; + public static TextGraphicsOptions Default { get; } = new TextGraphicsOptions(); /// /// Gets or sets a value indicating whether antialiasing should be applied. + /// Defaults to true. /// - public bool Antialias { get; set; } + public bool Antialias { get; set; } = true; /// /// Gets or sets a value indicating the number of subpixels to use while rendering with antialiasing enabled. @@ -92,27 +63,27 @@ public float BlendPercentage } } - // In the future we could expose a PixelBlender directly on here - // or some forms of PixelBlender factory for each pixel type. Will need - // some API thought post V1. - /// - /// Gets or sets a value indicating the color blending percentage to apply to the drawing operation + /// Gets or sets a value indicating the color blending percentage to apply to the drawing operation. + /// Defaults to . /// - public PixelColorBlendingMode ColorBlendingMode { get; set; } + public PixelColorBlendingMode ColorBlendingMode { get; set; } = PixelColorBlendingMode.Normal; /// /// Gets or sets a value indicating the color blending percentage to apply to the drawing operation + /// Defaults to . /// - public PixelAlphaCompositionMode AlphaCompositionMode { get; set; } + public PixelAlphaCompositionMode AlphaCompositionMode { get; set; } = PixelAlphaCompositionMode.SrcOver; /// /// Gets or sets a value indicating whether the text should be drawing with kerning enabled. + /// Defaults to true; /// - public bool ApplyKerning { get; set; } + public bool ApplyKerning { get; set; } = true; /// /// Gets or sets a value indicating the number of space widths a tab should lock to. + /// Defaults to 4. /// public float TabWidth { @@ -130,11 +101,13 @@ public float TabWidth /// /// Gets or sets a value, if greater than 0, indicating the width at which text should wrap. + /// Defaults to 0. /// public float WrapTextWidth { get; set; } /// - /// Gets or sets a value indicating the DPI to render text along the X axis. + /// Gets or sets a value indicating the DPI (Dots Per Inch) to render text along the X axis. + /// Defaults to 72. /// public float DpiX { @@ -151,7 +124,8 @@ public float DpiX } /// - /// Gets or sets a value indicating the DPI to render text along the Y axis. + /// Gets or sets a value indicating the DPI (Dots Per Inch) to render text along the Y axis. + /// Defaults to 72. /// public float DpiY { @@ -172,13 +146,15 @@ public float DpiY /// If is greater than zero it will align relative to the space /// defined by the location and width, if equals zero, and thus /// wrapping disabled, then the alignment is relative to the drawing location. + /// Defaults to . /// - public HorizontalAlignment HorizontalAlignment { get; set; } + public HorizontalAlignment HorizontalAlignment { get; set; } = HorizontalAlignment.Left; /// /// Gets or sets a value indicating how to align the text relative to the rendering space. + /// Defaults to . /// - public VerticalAlignment VerticalAlignment { get; set; } + public VerticalAlignment VerticalAlignment { get; set; } = VerticalAlignment.Top; /// /// Performs an implicit conversion from to . @@ -189,8 +165,9 @@ public float DpiY /// public static implicit operator TextGraphicsOptions(GraphicsOptions options) { - return new TextGraphicsOptions(options.Antialias) + return new TextGraphicsOptions() { + Antialias = options.Antialias, AntialiasSubpixelDepth = options.AntialiasSubpixelDepth, blendPercentage = options.BlendPercentage, ColorBlendingMode = options.ColorBlendingMode, @@ -207,13 +184,37 @@ public static implicit operator TextGraphicsOptions(GraphicsOptions options) /// public static explicit operator GraphicsOptions(TextGraphicsOptions options) { - return new GraphicsOptions(options.Antialias) + return new GraphicsOptions() { + Antialias = options.Antialias, AntialiasSubpixelDepth = options.AntialiasSubpixelDepth, ColorBlendingMode = options.ColorBlendingMode, AlphaCompositionMode = options.AlphaCompositionMode, BlendPercentage = options.BlendPercentage }; } + + /// + /// Creates a shallow copy of the . + /// + /// A new options instance. + public TextGraphicsOptions Clone() + { + return new TextGraphicsOptions + { + AlphaCompositionMode = this.AlphaCompositionMode, + Antialias = this.Antialias, + AntialiasSubpixelDepth = this.AntialiasSubpixelDepth, + ApplyKerning = this.ApplyKerning, + BlendPercentage = this.BlendPercentage, + ColorBlendingMode = this.ColorBlendingMode, + DpiX = this.DpiX, + DpiY = this.DpiY, + HorizontalAlignment = this.HorizontalAlignment, + TabWidth = this.TabWidth, + WrapTextWidth = this.WrapTextWidth, + VerticalAlignment = this.VerticalAlignment + }; + } } } diff --git a/tests/ImageSharp.Benchmarks/Drawing/DrawText.cs b/tests/ImageSharp.Benchmarks/Drawing/DrawText.cs index 0982db3340..c199613900 100644 --- a/tests/ImageSharp.Benchmarks/Drawing/DrawText.cs +++ b/tests/ImageSharp.Benchmarks/Drawing/DrawText.cs @@ -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 System.Drawing; @@ -31,7 +31,7 @@ public void DrawTextSystemDrawing() graphics.SmoothingMode = SmoothingMode.AntiAlias; using (var font = new Font("Arial", 12, GraphicsUnit.Point)) { - graphics.DrawString(TextToRender, font, System.Drawing.Brushes.HotPink, new RectangleF(10, 10, 780, 780)); + graphics.DrawString(this.TextToRender, font, System.Drawing.Brushes.HotPink, new RectangleF(10, 10, 780, 780)); } } } @@ -42,7 +42,7 @@ public void DrawTextCore() using (var image = new Image(800, 800)) { var font = SixLabors.Fonts.SystemFonts.CreateFont("Arial", 12); - image.Mutate(x => x.ApplyProcessor(new DrawTextProcessor(new TextGraphicsOptions(true) { WrapTextWidth = 780 }, TextToRender, font, Processing.Brushes.Solid(Rgba32.HotPink), null, new SixLabors.Primitives.PointF(10, 10)))); + image.Mutate(x => x.ApplyProcessor(new DrawTextProcessor(new TextGraphicsOptions { Antialias = true, WrapTextWidth = 780 }, this.TextToRender, font, Processing.Brushes.Solid(Rgba32.HotPink), null, new SixLabors.Primitives.PointF(10, 10)))); } } @@ -52,7 +52,7 @@ public void DrawTextCoreOld() using (var image = new Image(800, 800)) { var font = SixLabors.Fonts.SystemFonts.CreateFont("Arial", 12); - image.Mutate(x => DrawTextOldVersion(x, new TextGraphicsOptions(true) { WrapTextWidth = 780 }, TextToRender, font, Processing.Brushes.Solid(Rgba32.HotPink), null, new SixLabors.Primitives.PointF(10, 10))); + image.Mutate(x => DrawTextOldVersion(x, new TextGraphicsOptions { Antialias = true, WrapTextWidth = 780 }, this.TextToRender, font, Processing.Brushes.Solid(Rgba32.HotPink), null, new SixLabors.Primitives.PointF(10, 10))); } IImageProcessingContext DrawTextOldVersion( @@ -93,4 +93,4 @@ IImageProcessingContext DrawTextOldVersion( } } } -} \ No newline at end of file +} diff --git a/tests/ImageSharp.Benchmarks/Drawing/DrawTextOutline.cs b/tests/ImageSharp.Benchmarks/Drawing/DrawTextOutline.cs index c5c1ba5ac1..7d8b776598 100644 --- a/tests/ImageSharp.Benchmarks/Drawing/DrawTextOutline.cs +++ b/tests/ImageSharp.Benchmarks/Drawing/DrawTextOutline.cs @@ -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 System.Drawing; @@ -17,7 +17,7 @@ public class DrawTextOutline : BenchmarkBase [Params(10, 100)] public int TextIterations { get; set; } public string TextPhrase { get; set; } = "Hello World"; - public string TextToRender => string.Join(" ", Enumerable.Repeat(TextPhrase, TextIterations)); + public string TextToRender => string.Join(" ", Enumerable.Repeat(this.TextPhrase, this.TextIterations)); [Benchmark(Baseline = true, Description = "System.Drawing Draw Text Outline")] public void DrawTextSystemDrawing() @@ -31,7 +31,7 @@ public void DrawTextSystemDrawing() using (var font = new Font("Arial", 12, GraphicsUnit.Point)) using (var gp = new GraphicsPath()) { - gp.AddString(TextToRender, font.FontFamily, (int)font.Style, font.Size, new RectangleF(10, 10, 780, 780), new StringFormat()); + gp.AddString(this.TextToRender, font.FontFamily, (int)font.Style, font.Size, new RectangleF(10, 10, 780, 780), new StringFormat()); graphics.DrawPath(pen, gp); } } @@ -43,7 +43,7 @@ public void DrawTextCore() using (var image = new Image(800, 800)) { var font = SixLabors.Fonts.SystemFonts.CreateFont("Arial", 12); - image.Mutate(x => x.ApplyProcessor(new DrawTextProcessor(new TextGraphicsOptions(true) { WrapTextWidth = 780 }, TextToRender, font, null, Processing.Pens.Solid(Rgba32.HotPink, 10), new SixLabors.Primitives.PointF(10, 10)))); + image.Mutate(x => x.ApplyProcessor(new DrawTextProcessor(new TextGraphicsOptions { Antialias = true, WrapTextWidth = 780 }, this.TextToRender, font, null, Processing.Pens.Solid(Rgba32.HotPink, 10), new SixLabors.Primitives.PointF(10, 10)))); } } @@ -56,8 +56,8 @@ public void DrawTextCoreOld() image.Mutate( x => DrawTextOldVersion( x, - new TextGraphicsOptions(true) { WrapTextWidth = 780 }, - TextToRender, + new TextGraphicsOptions { Antialias = true, WrapTextWidth = 780 }, + this.TextToRender, font, null, Processing.Pens.Solid(Rgba32.HotPink, 10), @@ -99,4 +99,4 @@ IImageProcessingContext DrawTextOldVersion( } } } -} \ No newline at end of file +} diff --git a/tests/ImageSharp.Tests/Drawing/DrawLinesTests.cs b/tests/ImageSharp.Tests/Drawing/DrawLinesTests.cs index 2836f8a38d..b45fc620b2 100644 --- a/tests/ImageSharp.Tests/Drawing/DrawLinesTests.cs +++ b/tests/ImageSharp.Tests/Drawing/DrawLinesTests.cs @@ -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 System; @@ -24,10 +24,10 @@ public void DrawLines_Simple(TestImageProvider provider, string { Color color = TestUtils.GetColorByName(colorName).WithAlpha(alpha); Pen pen = new Pen(color, thickness); - + DrawLinesImpl(provider, colorName, alpha, thickness, antialias, pen); } - + [Theory] [WithBasicTestPatternImages(250, 350, PixelTypes.Rgba32, "White", 1f, 5, false)] public void DrawLines_Dash(TestImageProvider provider, string colorName, float alpha, float thickness, bool antialias) @@ -35,10 +35,10 @@ public void DrawLines_Dash(TestImageProvider provider, string co { Color color = TestUtils.GetColorByName(colorName).WithAlpha(alpha); Pen pen = Pens.Dash(color, thickness); - + DrawLinesImpl(provider, colorName, alpha, thickness, antialias, pen); } - + [Theory] [WithBasicTestPatternImages(250, 350, PixelTypes.Rgba32, "LightGreen", 1f, 5, false)] public void DrawLines_Dot(TestImageProvider provider, string colorName, float alpha, float thickness, bool antialias) @@ -46,10 +46,10 @@ public void DrawLines_Dot(TestImageProvider provider, string col { Color color = TestUtils.GetColorByName(colorName).WithAlpha(alpha); Pen pen = Pens.Dot(color, thickness); - + DrawLinesImpl(provider, colorName, alpha, thickness, antialias, pen); } - + [Theory] [WithBasicTestPatternImages(250, 350, PixelTypes.Rgba32, "Yellow", 1f, 5, false)] public void DrawLines_DashDot(TestImageProvider provider, string colorName, float alpha, float thickness, bool antialias) @@ -57,7 +57,7 @@ public void DrawLines_DashDot(TestImageProvider provider, string { Color color = TestUtils.GetColorByName(colorName).WithAlpha(alpha); Pen pen = Pens.DashDot(color, thickness); - + DrawLinesImpl(provider, colorName, alpha, thickness, antialias, pen); } @@ -68,11 +68,11 @@ public void DrawLines_DashDotDot(TestImageProvider provider, str { Color color = TestUtils.GetColorByName(colorName).WithAlpha(alpha); Pen pen = Pens.DashDotDot(color, thickness); - + DrawLinesImpl(provider, colorName, alpha, thickness, antialias, pen); } - + private static void DrawLinesImpl( TestImageProvider provider, string colorName, @@ -84,7 +84,7 @@ private static void DrawLinesImpl( { SixLabors.Primitives.PointF[] simplePath = { new Vector2(10, 10), new Vector2(200, 150), new Vector2(50, 300) }; - GraphicsOptions options = new GraphicsOptions(antialias); + GraphicsOptions options = new GraphicsOptions { Antialias = antialias }; string aa = antialias ? "" : "_NoAntialias"; FormattableString outputDetails = $"{colorName}_A({alpha})_T({thickness}){aa}"; diff --git a/tests/ImageSharp.Tests/Drawing/DrawPolygonTests.cs b/tests/ImageSharp.Tests/Drawing/DrawPolygonTests.cs index 18fde6ad8f..4a6cb430a8 100644 --- a/tests/ImageSharp.Tests/Drawing/DrawPolygonTests.cs +++ b/tests/ImageSharp.Tests/Drawing/DrawPolygonTests.cs @@ -27,7 +27,7 @@ public void DrawPolygon(TestImageProvider provider, string color }; Color color = TestUtils.GetColorByName(colorName).WithAlpha(alpha); - GraphicsOptions options = new GraphicsOptions(antialias); + GraphicsOptions options = new GraphicsOptions { Antialias = antialias }; string aa = antialias ? "" : "_NoAntialias"; FormattableString outputDetails = $"{colorName}_A({alpha})_T({thickness}){aa}"; diff --git a/tests/ImageSharp.Tests/Drawing/FillLinearGradientBrushTests.cs b/tests/ImageSharp.Tests/Drawing/FillLinearGradientBrushTests.cs index 8aae342cba..031e732eaa 100644 --- a/tests/ImageSharp.Tests/Drawing/FillLinearGradientBrushTests.cs +++ b/tests/ImageSharp.Tests/Drawing/FillLinearGradientBrushTests.cs @@ -412,8 +412,9 @@ void ApplyGloss(IImageProcessingContext ctx) { Size size = ctx.GetCurrentSize(); IPathCollection glossPath = BuildGloss(size.Width, size.Height); - var graphicsOptions = new GraphicsOptions(true) + var graphicsOptions = new GraphicsOptions { + Antialias = true, ColorBlendingMode = PixelColorBlendingMode.Normal, AlphaCompositionMode = PixelAlphaCompositionMode.SrcAtop }; diff --git a/tests/ImageSharp.Tests/Drawing/FillPolygonTests.cs b/tests/ImageSharp.Tests/Drawing/FillPolygonTests.cs index 104237ec3e..22294e76df 100644 --- a/tests/ImageSharp.Tests/Drawing/FillPolygonTests.cs +++ b/tests/ImageSharp.Tests/Drawing/FillPolygonTests.cs @@ -29,7 +29,7 @@ public void FillPolygon_Solid(TestImageProvider provider, string }; Color color = TestUtils.GetColorByName(colorName).WithAlpha(alpha); - var options = new GraphicsOptions(antialias); + var options = new GraphicsOptions { Antialias = antialias }; string aa = antialias ? "" : "_NoAntialias"; FormattableString outputDetails = $"{colorName}_A{alpha}{aa}"; diff --git a/tests/ImageSharp.Tests/Drawing/FillRegionProcessorTests.cs b/tests/ImageSharp.Tests/Drawing/FillRegionProcessorTests.cs index c0388ea2d4..6230d52a17 100644 --- a/tests/ImageSharp.Tests/Drawing/FillRegionProcessorTests.cs +++ b/tests/ImageSharp.Tests/Drawing/FillRegionProcessorTests.cs @@ -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 System.Numerics; @@ -16,8 +16,6 @@ namespace SixLabors.ImageSharp.Tests.Drawing { - - public class FillRegionProcessorTests { @@ -35,8 +33,9 @@ public void MinimumAntialiasSubpixelDepth(bool antialias, int antialiasSubpixelD var brush = new Mock(); var region = new MockRegion2(bounds); - var options = new GraphicsOptions(antialias) + var options = new GraphicsOptions { + Antialias = antialias, AntialiasSubpixelDepth = 1 }; var processor = new FillRegionProcessor(brush.Object, region, options); @@ -51,7 +50,7 @@ public void FillOffCanvas() { var bounds = new Rectangle(-100, -10, 10, 10); var brush = new Mock(); - var options = new GraphicsOptions(true); + var options = new GraphicsOptions { Antialias = true }; var processor = new FillRegionProcessor(brush.Object, new MockRegion1(), options); var img = new Image(10, 10); processor.Execute(img, bounds); @@ -77,7 +76,8 @@ public void DoesNotThrowForIssue928() { img.Mutate(x => x.Fill(Rgba32.Transparent)); - img.Mutate(ctx => { + img.Mutate(ctx => + { ctx.DrawLines( Rgba32.Red, 0.984252f, @@ -90,7 +90,7 @@ public void DoesNotThrowForIssue928() new PointF(104.782608f, 1075.13245f), new PointF(104.782608f, 1075.13245f) ); - } + } ); } } @@ -98,7 +98,7 @@ public void DoesNotThrowForIssue928() [Fact] public void DoesNotThrowFillingTriangle() { - using(var image = new Image(28, 28)) + using (var image = new Image(28, 28)) { var path = new Polygon( new LinearLineSegment(new PointF(17.11f, 13.99659f), new PointF(14.01433f, 27.06201f)), diff --git a/tests/ImageSharp.Tests/Drawing/FillSolidBrushTests.cs b/tests/ImageSharp.Tests/Drawing/FillSolidBrushTests.cs index a5e7450839..1e3688fead 100644 --- a/tests/ImageSharp.Tests/Drawing/FillSolidBrushTests.cs +++ b/tests/ImageSharp.Tests/Drawing/FillSolidBrushTests.cs @@ -156,10 +156,12 @@ public void BlendFillColorOverBackground( { TPixel bgColor = image[0, 0]; - var options = new GraphicsOptions(false) - { - ColorBlendingMode = blenderMode, BlendPercentage = blendPercentage - }; + var options = new GraphicsOptions + { + Antialias = false, + ColorBlendingMode = blenderMode, + BlendPercentage = blendPercentage + }; if (triggerFillRegion) { @@ -173,13 +175,13 @@ public void BlendFillColorOverBackground( } var testOutputDetails = new - { - triggerFillRegion = triggerFillRegion, - newColorName = newColorName, - alpha = alpha, - blenderMode = blenderMode, - blendPercentage = blendPercentage - }; + { + triggerFillRegion = triggerFillRegion, + newColorName = newColorName, + alpha = alpha, + blenderMode = blenderMode, + blendPercentage = blendPercentage + }; image.DebugSave( provider, diff --git a/tests/ImageSharp.Tests/Drawing/Paths/DrawPathCollection.cs b/tests/ImageSharp.Tests/Drawing/Paths/DrawPathCollection.cs index 5d309d2995..f6d9c7fe5c 100644 --- a/tests/ImageSharp.Tests/Drawing/Paths/DrawPathCollection.cs +++ b/tests/ImageSharp.Tests/Drawing/Paths/DrawPathCollection.cs @@ -14,7 +14,7 @@ namespace SixLabors.ImageSharp.Tests.Drawing.Paths { public class DrawPathCollection : BaseImageOperationsExtensionTest { - GraphicsOptions noneDefault = new GraphicsOptions(false); + GraphicsOptions noneDefault = new GraphicsOptions { Antialias = false }; Color color = Color.HotPink; Pen pen = Pens.Solid(Rgba32.HotPink, 1); IPath path1 = new Path(new LinearLineSegment(new SixLabors.Primitives.PointF[] { diff --git a/tests/ImageSharp.Tests/Drawing/Paths/FillPath.cs b/tests/ImageSharp.Tests/Drawing/Paths/FillPath.cs index cb247ac039..fa1949e673 100644 --- a/tests/ImageSharp.Tests/Drawing/Paths/FillPath.cs +++ b/tests/ImageSharp.Tests/Drawing/Paths/FillPath.cs @@ -14,7 +14,7 @@ namespace SixLabors.ImageSharp.Tests.Drawing.Paths { public class FillPath : BaseImageOperationsExtensionTest { - GraphicsOptions noneDefault = new GraphicsOptions(false); + GraphicsOptions noneDefault = new GraphicsOptions { Antialias = false }; Color color = Color.HotPink; SolidBrush brush = Brushes.Solid(Rgba32.HotPink); IPath path = new Path(new LinearLineSegment(new SixLabors.Primitives.PointF[] { diff --git a/tests/ImageSharp.Tests/Drawing/Paths/FillPathCollection.cs b/tests/ImageSharp.Tests/Drawing/Paths/FillPathCollection.cs index 0c4d6ca3ca..39e2fc2f97 100644 --- a/tests/ImageSharp.Tests/Drawing/Paths/FillPathCollection.cs +++ b/tests/ImageSharp.Tests/Drawing/Paths/FillPathCollection.cs @@ -14,7 +14,7 @@ namespace SixLabors.ImageSharp.Tests.Drawing.Paths { public class FillPathCollection : BaseImageOperationsExtensionTest { - GraphicsOptions noneDefault = new GraphicsOptions(false); + GraphicsOptions noneDefault = new GraphicsOptions { Antialias = false }; Color color = Color.HotPink; SolidBrush brush = Brushes.Solid(Rgba32.HotPink); IPath path1 = new Path(new LinearLineSegment(new SixLabors.Primitives.PointF[] { diff --git a/tests/ImageSharp.Tests/Drawing/Paths/FillPolygon.cs b/tests/ImageSharp.Tests/Drawing/Paths/FillPolygon.cs index 06a7348427..03a827a6a9 100644 --- a/tests/ImageSharp.Tests/Drawing/Paths/FillPolygon.cs +++ b/tests/ImageSharp.Tests/Drawing/Paths/FillPolygon.cs @@ -14,7 +14,7 @@ namespace SixLabors.ImageSharp.Tests.Drawing.Paths { public class FillPolygon : BaseImageOperationsExtensionTest { - GraphicsOptions noneDefault = new GraphicsOptions(false); + GraphicsOptions noneDefault = new GraphicsOptions { Antialias = false }; Color color = Color.HotPink; SolidBrush brush = Brushes.Solid(Rgba32.HotPink); SixLabors.Primitives.PointF[] path = { diff --git a/tests/ImageSharp.Tests/Drawing/Paths/FillRectangle.cs b/tests/ImageSharp.Tests/Drawing/Paths/FillRectangle.cs index c1ad059a85..cc108fb54e 100644 --- a/tests/ImageSharp.Tests/Drawing/Paths/FillRectangle.cs +++ b/tests/ImageSharp.Tests/Drawing/Paths/FillRectangle.cs @@ -13,7 +13,7 @@ namespace SixLabors.ImageSharp.Tests.Drawing.Paths { public class FillRectangle : BaseImageOperationsExtensionTest { - GraphicsOptions noneDefault = new GraphicsOptions(false); + GraphicsOptions noneDefault = new GraphicsOptions { Antialias = false }; Color color = Color.HotPink; SolidBrush brush = Brushes.Solid(Rgba32.HotPink); SixLabors.Primitives.Rectangle rectangle = new SixLabors.Primitives.Rectangle(10, 10, 77, 76); diff --git a/tests/ImageSharp.Tests/Drawing/SolidFillBlendedShapesTests.cs b/tests/ImageSharp.Tests/Drawing/SolidFillBlendedShapesTests.cs index da7c865b96..f1a62cf292 100644 --- a/tests/ImageSharp.Tests/Drawing/SolidFillBlendedShapesTests.cs +++ b/tests/ImageSharp.Tests/Drawing/SolidFillBlendedShapesTests.cs @@ -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 System; using System.Collections.Generic; @@ -27,7 +27,7 @@ private static IEnumerable GetAllModeCombinations() } } } - + [Theory] [WithBlankImages(nameof(modes), 250, 250, PixelTypes.Rgba32)] @@ -46,7 +46,8 @@ public void _1DarkBlueRect_2BlendHotPinkRect( Color.DarkBlue, new Rectangle(0 * scaleX, 40 * scaleY, 100 * scaleX, 20 * scaleY) ) - .Fill(new GraphicsOptions(true) { ColorBlendingMode = blending, AlphaCompositionMode=composition }, + .Fill( + new GraphicsOptions { Antialias = true, ColorBlendingMode = blending, AlphaCompositionMode = composition }, Color.HotPink, new Rectangle(20 * scaleX, 0 * scaleY, 30 * scaleX, 100 * scaleY)) ); @@ -73,12 +74,12 @@ public void _1DarkBlueRect_2BlendHotPinkRect_3BlendTransparentEllipse( new Rectangle(0 * scaleX, 40 * scaleY, 100 * scaleX, 20 * scaleY))); img.Mutate( x => x.Fill( - new GraphicsOptions(true) { ColorBlendingMode = blending, AlphaCompositionMode = composition }, + new GraphicsOptions { Antialias = true, ColorBlendingMode = blending, AlphaCompositionMode = composition }, Color.HotPink, new Rectangle(20 * scaleX, 0 * scaleY, 30 * scaleX, 100 * scaleY))); img.Mutate( x => x.Fill( - new GraphicsOptions(true) { ColorBlendingMode = blending, AlphaCompositionMode = composition }, + new GraphicsOptions { Antialias = true, ColorBlendingMode = blending, AlphaCompositionMode = composition }, Color.Transparent, new Shapes.EllipsePolygon(40 * scaleX, 50 * scaleY, 50 * scaleX, 50 * scaleY)) ); @@ -105,7 +106,7 @@ public void _1DarkBlueRect_2BlendHotPinkRect_3BlendSemiTransparentRedEllipse x.Fill( - new GraphicsOptions(true) { ColorBlendingMode = blending, AlphaCompositionMode = composition }, + new GraphicsOptions { Antialias = true, ColorBlendingMode = blending, AlphaCompositionMode = composition }, Color.HotPink, new Rectangle(20 * scaleX, 0, 30 * scaleX, 100 * scaleY))); @@ -113,7 +114,7 @@ public void _1DarkBlueRect_2BlendHotPinkRect_3BlendSemiTransparentRedEllipse x.Fill( - new GraphicsOptions(true) { ColorBlendingMode = blending, AlphaCompositionMode = composition }, + new GraphicsOptions { Antialias = true, ColorBlendingMode = blending, AlphaCompositionMode = composition }, transparentRed, new Shapes.EllipsePolygon(40 * scaleX, 50 * scaleY, 50 * scaleX, 50 * scaleY)) ); @@ -130,7 +131,7 @@ public void _1DarkBlueRect_2BlendBlackEllipse( PixelAlphaCompositionMode composition) where TPixel : struct, IPixel { - using(Image dstImg = provider.GetImage(), srcImg = provider.GetImage()) + using (Image dstImg = provider.GetImage(), srcImg = provider.GetImage()) { int scaleX = (dstImg.Width / 100); int scaleY = (dstImg.Height / 100); @@ -146,13 +147,13 @@ public void _1DarkBlueRect_2BlendBlackEllipse( new Shapes.EllipsePolygon(40 * scaleX, 50 * scaleY, 50 * scaleX, 50 * scaleY))); dstImg.Mutate( - x => x.DrawImage(srcImg, new GraphicsOptions(true) { ColorBlendingMode = blending, AlphaCompositionMode = composition }) - ); + x => x.DrawImage(srcImg, new GraphicsOptions { Antialias = true, ColorBlendingMode = blending, AlphaCompositionMode = composition }) + ); VerifyImage(provider, blending, composition, dstImg); } } - + private static void VerifyImage( TestImageProvider provider, PixelColorBlendingMode blending, @@ -165,13 +166,13 @@ private static void VerifyImage( new { composition, blending }, appendPixelTypeToFileName: false, appendSourceFileOrDescription: false); - + var comparer = ImageComparer.TolerantPercentage(0.01f, 3); img.CompareFirstFrameToReferenceOutput(comparer, provider, new { composition, blending }, appendPixelTypeToFileName: false, - appendSourceFileOrDescription: false); + appendSourceFileOrDescription: false); } } -} \ No newline at end of file +} diff --git a/tests/ImageSharp.Tests/Drawing/Text/DrawText.cs b/tests/ImageSharp.Tests/Drawing/Text/DrawText.cs index e6866c6579..2a39e18cb6 100644 --- a/tests/ImageSharp.Tests/Drawing/Text/DrawText.cs +++ b/tests/ImageSharp.Tests/Drawing/Text/DrawText.cs @@ -27,7 +27,7 @@ public DrawText() public void FillsForEachACharacterWhenBrushSetAndNotPen() { this.operations.DrawText( - new TextGraphicsOptions(true), + new TextGraphicsOptions { Antialias = true }, "123", this.Font, Brushes.Solid(Color.Red), @@ -48,7 +48,7 @@ public void FillsForEachACharacterWhenBrushSetAndNotPenDefaultOptions() [Fact] public void FillsForEachACharacterWhenBrushSet() { - this.operations.DrawText(new TextGraphicsOptions(true), "123", this.Font, Brushes.Solid(Color.Red), Vector2.Zero); + this.operations.DrawText(new TextGraphicsOptions { Antialias = true }, "123", this.Font, Brushes.Solid(Color.Red), Vector2.Zero); this.Verify(0); } @@ -64,7 +64,7 @@ public void FillsForEachACharacterWhenBrushSetDefaultOptions() [Fact] public void FillsForEachACharacterWhenColorSet() { - this.operations.DrawText(new TextGraphicsOptions(true), "123", this.Font, Color.Red, Vector2.Zero); + this.operations.DrawText(new TextGraphicsOptions { Antialias = true }, "123", this.Font, Color.Red, Vector2.Zero); var processor = this.Verify(0); @@ -87,7 +87,7 @@ public void FillsForEachACharacterWhenColorSetDefaultOptions() public void DrawForEachACharacterWhenPenSetAndNotBrush() { this.operations.DrawText( - new TextGraphicsOptions(true), + new TextGraphicsOptions { Antialias = true }, "123", this.Font, null, @@ -108,7 +108,7 @@ public void DrawForEachACharacterWhenPenSetAndNotBrushDefaultOptions() [Fact] public void DrawForEachACharacterWhenPenSet() { - this.operations.DrawText(new TextGraphicsOptions(true), "123", this.Font, Pens.Dash(Color.Red, 1), Vector2.Zero); + this.operations.DrawText(new TextGraphicsOptions { Antialias = true }, "123", this.Font, Pens.Dash(Color.Red, 1), Vector2.Zero); this.Verify(0); } @@ -132,7 +132,7 @@ public void DrawForEachACharacterWhenPenSetDefaultOptions() public void DrawForEachACharacterWhenPenSetAndFillFroEachWhenBrushSet() { this.operations.DrawText( - new TextGraphicsOptions(true), + new TextGraphicsOptions { Antialias = true }, "123", this.Font, Brushes.Solid(Color.Red), diff --git a/tests/ImageSharp.Tests/Drawing/Text/DrawTextOnImageTests.cs b/tests/ImageSharp.Tests/Drawing/Text/DrawTextOnImageTests.cs index a767a686ed..281a516509 100644 --- a/tests/ImageSharp.Tests/Drawing/Text/DrawTextOnImageTests.cs +++ b/tests/ImageSharp.Tests/Drawing/Text/DrawTextOnImageTests.cs @@ -55,8 +55,9 @@ public void DoesntThrowExceptionWhenOverlappingRightEdge_Issue688(TestIm var scaledFont = new Font(font, scalingFactor * font.Size); var center = new PointF(img.Width / 2, img.Height / 2); - var textGraphicOptions = new TextGraphicsOptions(true) + var textGraphicOptions = new TextGraphicsOptions { + Antialias = true, HorizontalAlignment = HorizontalAlignment.Center, VerticalAlignment = VerticalAlignment.Center }; @@ -222,7 +223,11 @@ public void TextPositioningIsRobust(TestImageProvider provider, string text = Repeat("Beware the Jabberwock, my son! The jaws that bite, the claws that catch! Beware the Jubjub bird, and shun The frumious Bandersnatch!\n", 20); - var textOptions = new TextGraphicsOptions(true) { WrapTextWidth = 1000 }; + var textOptions = new TextGraphicsOptions + { + Antialias = true, + WrapTextWidth = 1000 + }; string details = fontName.Replace(" ", ""); diff --git a/tests/ImageSharp.Tests/Drawing/Text/TextGraphicsOptionsTests.cs b/tests/ImageSharp.Tests/Drawing/Text/TextGraphicsOptionsTests.cs index 0885611c67..d15b717bb6 100644 --- a/tests/ImageSharp.Tests/Drawing/Text/TextGraphicsOptionsTests.cs +++ b/tests/ImageSharp.Tests/Drawing/Text/TextGraphicsOptionsTests.cs @@ -1,6 +1,8 @@ -// Copyright (c) Six Labors and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. +using SixLabors.Fonts; +using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Processing; using Xunit; @@ -9,16 +11,129 @@ namespace SixLabors.ImageSharp.Tests.Drawing.Text { public class TextGraphicsOptionsTests { + private readonly TextGraphicsOptions newTextGraphicsOptions = new TextGraphicsOptions(); + private readonly TextGraphicsOptions defaultTextGraphicsOptions = TextGraphicsOptions.Default; + private readonly TextGraphicsOptions cloneTextGraphicsOptions = TextGraphicsOptions.Default.Clone(); + + [Fact] + public void DefaultTextGraphicsOptionsIsNotNull() => Assert.True(this.defaultTextGraphicsOptions != null); + + [Fact] + public void DefaultTextGraphicsOptionsAntialias() + { + Assert.True(this.newTextGraphicsOptions.Antialias); + Assert.True(this.defaultTextGraphicsOptions.Antialias); + Assert.True(this.cloneTextGraphicsOptions.Antialias); + } + + [Fact] + public void DefaultTextGraphicsOptionsAntialiasSuppixelDepth() + { + const int Expected = 16; + Assert.Equal(Expected, this.newTextGraphicsOptions.AntialiasSubpixelDepth); + Assert.Equal(Expected, this.defaultTextGraphicsOptions.AntialiasSubpixelDepth); + Assert.Equal(Expected, this.cloneTextGraphicsOptions.AntialiasSubpixelDepth); + } + + [Fact] + public void DefaultTextGraphicsOptionsBlendPercentage() + { + const float Expected = 1F; + Assert.Equal(Expected, this.newTextGraphicsOptions.BlendPercentage); + Assert.Equal(Expected, this.defaultTextGraphicsOptions.BlendPercentage); + Assert.Equal(Expected, this.cloneTextGraphicsOptions.BlendPercentage); + } + + [Fact] + public void DefaultTextGraphicsOptionsColorBlendingMode() + { + const PixelColorBlendingMode Expected = PixelColorBlendingMode.Normal; + Assert.Equal(Expected, this.newTextGraphicsOptions.ColorBlendingMode); + Assert.Equal(Expected, this.defaultTextGraphicsOptions.ColorBlendingMode); + Assert.Equal(Expected, this.cloneTextGraphicsOptions.ColorBlendingMode); + } + + [Fact] + public void DefaultTextGraphicsOptionsAlphaCompositionMode() + { + const PixelAlphaCompositionMode Expected = PixelAlphaCompositionMode.SrcOver; + Assert.Equal(Expected, this.newTextGraphicsOptions.AlphaCompositionMode); + Assert.Equal(Expected, this.defaultTextGraphicsOptions.AlphaCompositionMode); + Assert.Equal(Expected, this.cloneTextGraphicsOptions.AlphaCompositionMode); + } + + [Fact] + public void DefaultTextGraphicsOptionsApplyKerning() + { + const bool Expected = true; + Assert.Equal(Expected, this.newTextGraphicsOptions.ApplyKerning); + Assert.Equal(Expected, this.defaultTextGraphicsOptions.ApplyKerning); + Assert.Equal(Expected, this.cloneTextGraphicsOptions.ApplyKerning); + } + + [Fact] + public void DefaultTextGraphicsOptionsHorizontalAlignment() + { + const HorizontalAlignment Expected = HorizontalAlignment.Left; + Assert.Equal(Expected, this.newTextGraphicsOptions.HorizontalAlignment); + Assert.Equal(Expected, this.defaultTextGraphicsOptions.HorizontalAlignment); + Assert.Equal(Expected, this.cloneTextGraphicsOptions.HorizontalAlignment); + } + + [Fact] + public void DefaultTextGraphicsOptionsVerticalAlignment() + { + const VerticalAlignment Expected = VerticalAlignment.Top; + Assert.Equal(Expected, this.newTextGraphicsOptions.VerticalAlignment); + Assert.Equal(Expected, this.defaultTextGraphicsOptions.VerticalAlignment); + Assert.Equal(Expected, this.cloneTextGraphicsOptions.VerticalAlignment); + } + + [Fact] + public void DefaultTextGraphicsOptionsDpiX() + { + const float Expected = 72F; + Assert.Equal(Expected, this.newTextGraphicsOptions.DpiX); + Assert.Equal(Expected, this.defaultTextGraphicsOptions.DpiX); + Assert.Equal(Expected, this.cloneTextGraphicsOptions.DpiX); + } + + [Fact] + public void DefaultTextGraphicsOptionsDpiY() + { + const float Expected = 72F; + Assert.Equal(Expected, this.newTextGraphicsOptions.DpiY); + Assert.Equal(Expected, this.defaultTextGraphicsOptions.DpiY); + Assert.Equal(Expected, this.cloneTextGraphicsOptions.DpiY); + } + + [Fact] + public void DefaultTextGraphicsOptionsTabWidth() + { + const float Expected = 4F; + Assert.Equal(Expected, this.newTextGraphicsOptions.TabWidth); + Assert.Equal(Expected, this.defaultTextGraphicsOptions.TabWidth); + Assert.Equal(Expected, this.cloneTextGraphicsOptions.TabWidth); + } + + [Fact] + public void DefaultTextGraphicsOptionsWrapTextWidth() + { + const float Expected = 0F; + Assert.Equal(Expected, this.newTextGraphicsOptions.WrapTextWidth); + Assert.Equal(Expected, this.defaultTextGraphicsOptions.WrapTextWidth); + Assert.Equal(Expected, this.cloneTextGraphicsOptions.WrapTextWidth); + } + [Fact] public void ExplicitCastOfGraphicsOptions() { - var opt = new GraphicsOptions(false) + TextGraphicsOptions textOptions = new GraphicsOptions { + Antialias = false, AntialiasSubpixelDepth = 99 }; - TextGraphicsOptions textOptions = opt; - Assert.False(textOptions.Antialias); Assert.Equal(99, textOptions.AntialiasSubpixelDepth); } @@ -26,8 +141,9 @@ public void ExplicitCastOfGraphicsOptions() [Fact] public void ImplicitCastToGraphicsOptions() { - var textOptions = new TextGraphicsOptions(false) + var textOptions = new TextGraphicsOptions { + Antialias = false, AntialiasSubpixelDepth = 99 }; @@ -37,4 +153,4 @@ public void ImplicitCastToGraphicsOptions() Assert.Equal(99, opt.AntialiasSubpixelDepth); } } -} \ No newline at end of file +} diff --git a/tests/ImageSharp.Tests/GraphicsOptionsTests.cs b/tests/ImageSharp.Tests/GraphicsOptionsTests.cs index 6ff38626d6..4e23b17663 100644 --- a/tests/ImageSharp.Tests/GraphicsOptionsTests.cs +++ b/tests/ImageSharp.Tests/GraphicsOptionsTests.cs @@ -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.PixelFormats; @@ -8,14 +8,65 @@ namespace SixLabors.ImageSharp.Tests { public class GraphicsOptionsTests { + private readonly GraphicsOptions newGraphicsOptions = new GraphicsOptions(); + private readonly GraphicsOptions defaultGraphicsOptions = GraphicsOptions.Default; + private readonly GraphicsOptions cloneGraphicsOptions = GraphicsOptions.Default.Clone(); + + [Fact] + public void DefaultGraphicsOptionsIsNotNull() => Assert.True(this.defaultGraphicsOptions != null); + + [Fact] + public void DefaultGraphicsOptionsAntialias() + { + Assert.True(this.newGraphicsOptions.Antialias); + Assert.True(this.defaultGraphicsOptions.Antialias); + Assert.True(this.cloneGraphicsOptions.Antialias); + } + + [Fact] + public void DefaultGraphicsOptionsAntialiasSuppixelDepth() + { + const int Expected = 16; + Assert.Equal(Expected, this.newGraphicsOptions.AntialiasSubpixelDepth); + Assert.Equal(Expected, this.defaultGraphicsOptions.AntialiasSubpixelDepth); + Assert.Equal(Expected, this.cloneGraphicsOptions.AntialiasSubpixelDepth); + } + + [Fact] + public void DefaultGraphicsOptionsBlendPercentage() + { + const float Expected = 1F; + Assert.Equal(Expected, this.newGraphicsOptions.BlendPercentage); + Assert.Equal(Expected, this.defaultGraphicsOptions.BlendPercentage); + Assert.Equal(Expected, this.cloneGraphicsOptions.BlendPercentage); + } + + [Fact] + public void DefaultGraphicsOptionsColorBlendingMode() + { + const PixelColorBlendingMode Expected = PixelColorBlendingMode.Normal; + Assert.Equal(Expected, this.newGraphicsOptions.ColorBlendingMode); + Assert.Equal(Expected, this.defaultGraphicsOptions.ColorBlendingMode); + Assert.Equal(Expected, this.cloneGraphicsOptions.ColorBlendingMode); + } + + [Fact] + public void DefaultGraphicsOptionsAlphaCompositionMode() + { + const PixelAlphaCompositionMode Expected = PixelAlphaCompositionMode.SrcOver; + Assert.Equal(Expected, this.newGraphicsOptions.AlphaCompositionMode); + Assert.Equal(Expected, this.defaultGraphicsOptions.AlphaCompositionMode); + Assert.Equal(Expected, this.cloneGraphicsOptions.AlphaCompositionMode); + } + [Fact] public void IsOpaqueColor() { - Assert.True(new GraphicsOptions(true).IsOpaqueColorWithoutBlending(Rgba32.Red)); - Assert.False(new GraphicsOptions(true, 0.5f).IsOpaqueColorWithoutBlending(Rgba32.Red)); - Assert.False(new GraphicsOptions(true).IsOpaqueColorWithoutBlending(Rgba32.Transparent)); - Assert.False(new GraphicsOptions(true, PixelColorBlendingMode.Lighten, 1).IsOpaqueColorWithoutBlending(Rgba32.Red)); - Assert.False(new GraphicsOptions(true, PixelColorBlendingMode.Normal, PixelAlphaCompositionMode.DestOver, 1).IsOpaqueColorWithoutBlending(Rgba32.Red)); + Assert.True(new GraphicsOptions().IsOpaqueColorWithoutBlending(Rgba32.Red)); + Assert.False(new GraphicsOptions { BlendPercentage = .5F }.IsOpaqueColorWithoutBlending(Rgba32.Red)); + Assert.False(new GraphicsOptions().IsOpaqueColorWithoutBlending(Rgba32.Transparent)); + Assert.False(new GraphicsOptions { ColorBlendingMode = PixelColorBlendingMode.Lighten, BlendPercentage = 1F }.IsOpaqueColorWithoutBlending(Rgba32.Red)); + Assert.False(new GraphicsOptions { ColorBlendingMode = PixelColorBlendingMode.Normal, AlphaCompositionMode = PixelAlphaCompositionMode.DestOver, BlendPercentage = 1f }.IsOpaqueColorWithoutBlending(Rgba32.Red)); } } -} \ No newline at end of file +} diff --git a/tests/ImageSharp.Tests/Issues/Issue412.cs b/tests/ImageSharp.Tests/Issues/Issue412.cs index 5a590018e5..53c65b643a 100644 --- a/tests/ImageSharp.Tests/Issues/Issue412.cs +++ b/tests/ImageSharp.Tests/Issues/Issue412.cs @@ -20,14 +20,14 @@ public void AllPixelsExpectedToBeRedWhenAntialiasedDisabled(TestImagePro for (var i = 0; i < 40; ++i) { context.DrawLines( - new GraphicsOptions(false), + new GraphicsOptions { Antialias = false }, Color.Black, 1, new PointF(i, 0.1066f), new PointF(i, 10.1066f)); context.DrawLines( - new GraphicsOptions(false), + new GraphicsOptions { Antialias = false }, Color.Red, 1, new PointF(i, 15.1066f), diff --git a/tests/ImageSharp.Tests/Processing/BaseImageOperationsExtensionTest.cs b/tests/ImageSharp.Tests/Processing/BaseImageOperationsExtensionTest.cs index 140af9563a..cfac8645ff 100644 --- a/tests/ImageSharp.Tests/Processing/BaseImageOperationsExtensionTest.cs +++ b/tests/ImageSharp.Tests/Processing/BaseImageOperationsExtensionTest.cs @@ -21,7 +21,7 @@ public abstract class BaseImageOperationsExtensionTest public BaseImageOperationsExtensionTest() { - this.options = new GraphicsOptions(false); + this.options = new GraphicsOptions { Antialias = false }; this.source = new Image(91 + 324, 123 + 56); this.rect = new Rectangle(91, 123, 324, 56); // make this random? this.internalOperations = new FakeImageOperationsProvider.FakeImageOperations(this.source, false); From f20666a4d6260baac0d58027b836ee761785f653 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Sun, 10 Nov 2019 20:29:03 +1100 Subject: [PATCH 12/16] Update GraphicsOptions.cs --- src/ImageSharp/GraphicsOptions.cs | 103 +++++++++--------------------- 1 file changed, 29 insertions(+), 74 deletions(-) diff --git a/src/ImageSharp/GraphicsOptions.cs b/src/ImageSharp/GraphicsOptions.cs index 1e18edb4ae..1673057b86 100644 --- a/src/ImageSharp/GraphicsOptions.cs +++ b/src/ImageSharp/GraphicsOptions.cs @@ -11,83 +11,23 @@ namespace SixLabors.ImageSharp /// public class GraphicsOptions { - private static readonly Lazy Lazy = new Lazy(); - private int antialiasSubpixelDepth; - private float blendPercentage; - - /// - /// Initializes a new instance of the class. - /// - public GraphicsOptions() - : this(true) - { - } - - /// - /// Initializes a new instance of the class. - /// - /// If set to true [enable antialiasing]. - public GraphicsOptions(bool enableAntialiasing) - : this(enableAntialiasing, 1F) - { - } - - /// - /// Initializes a new instance of the class. - /// - /// If set to true [enable antialiasing]. - /// The blending percentage to apply to the drawing operation - public GraphicsOptions(bool enableAntialiasing, float blendPercentage) - : this(enableAntialiasing, PixelColorBlendingMode.Normal, blendPercentage) - { - } - - /// - /// Initializes a new instance of the class. - /// - /// If set to true [enable antialiasing]. - /// The color blending mode to apply to the drawing operation - /// The blending percentage to apply to the drawing operation - public GraphicsOptions( - bool enableAntialiasing, - PixelColorBlendingMode blending, - float blendPercentage) - : this(enableAntialiasing, blending, PixelAlphaCompositionMode.SrcOver, blendPercentage) - { - } - - /// - /// Initializes a new instance of the class. - /// - /// If set to true [enable antialiasing]. - /// The color blending mode to apply to the drawing operation - /// The alpha composition mode to apply to the drawing operation - /// The blending percentage to apply to the drawing operation - public GraphicsOptions( - bool enableAntialiasing, - PixelColorBlendingMode blending, - PixelAlphaCompositionMode composition, - float blendPercentage) - { - this.ColorBlendingMode = blending; - this.AlphaCompositionMode = composition; - this.BlendPercentage = blendPercentage; - this.AntialiasSubpixelDepth = 16; - this.Antialias = enableAntialiasing; - } + private int antialiasSubpixelDepth = 16; + private float blendPercentage = 1F; /// /// Gets the default instance. /// - public static GraphicsOptions Default { get; } = Lazy.Value; + public static GraphicsOptions Default { get; } = new GraphicsOptions(); /// /// Gets or sets a value indicating whether antialiasing should be applied. + /// Defaults to true. /// - public bool Antialias { get; set; } + public bool Antialias { get; set; } = true; /// /// Gets or sets a value indicating the number of subpixels to use while rendering with antialiasing enabled. + /// Defaults to 16. /// public int AntialiasSubpixelDepth { @@ -104,7 +44,8 @@ public int AntialiasSubpixelDepth } /// - /// Gets or sets a value indicating the blending percentage to apply to the drawing operation. + /// Gets or sets a value between indicating the blending percentage to apply to the drawing operation. + /// Range 0..1; Defaults to 1. /// public float BlendPercentage { @@ -120,18 +61,32 @@ public float BlendPercentage } } - // In the future we could expose a PixelBlender directly on here - // or some forms of PixelBlender factory for each pixel type. Will need - // some API thought post V1. - /// - /// Gets or sets a value indicating the color blending mode to apply to the drawing operation + /// Gets or sets a value indicating the color blending mode to apply to the drawing operation. + /// Defaults to . /// - public PixelColorBlendingMode ColorBlendingMode { get; set; } + public PixelColorBlendingMode ColorBlendingMode { get; set; } = PixelColorBlendingMode.Normal; /// /// Gets or sets a value indicating the alpha composition mode to apply to the drawing operation + /// Defaults to . + /// + public PixelAlphaCompositionMode AlphaCompositionMode { get; set; } = PixelAlphaCompositionMode.SrcOver; + + /// + /// Creates a shallow copy of the . /// - public PixelAlphaCompositionMode AlphaCompositionMode { get; set; } + /// A new options instance. + public GraphicsOptions Clone() + { + return new GraphicsOptions + { + AlphaCompositionMode = this.AlphaCompositionMode, + Antialias = this.Antialias, + AntialiasSubpixelDepth = this.AntialiasSubpixelDepth, + BlendPercentage = this.BlendPercentage, + ColorBlendingMode = this.ColorBlendingMode + }; + } } } From 56e5575158f599949ddecbf2e0b6c90e9abce48d Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Mon, 11 Nov 2019 12:12:18 +1100 Subject: [PATCH 13/16] Drop Default, use DeepClone + tests --- .../Extensions/DrawImageExtensions.cs | 12 +-- .../DrawPathCollectionExtensions.cs | 2 +- .../Extensions/DrawPathExtensions.cs | 2 +- .../Extensions/DrawPolygonExtensions.cs | 2 +- .../Extensions/DrawRectangleExtensions.cs | 2 +- .../Extensions/DrawTextExtensions.cs | 8 +- .../Extensions/FillPathBuilderExtensions.cs | 2 +- .../FillPathCollectionExtensions.cs | 2 +- .../Extensions/FillPathExtensions.cs | 2 +- .../Extensions/FillRegionExtensions.cs | 4 +- .../Processing/TextGraphicsOptions.cs | 50 +++++------ src/ImageSharp/GraphicsOptions.cs | 36 ++++---- .../Extensions/BackgroundColorExtensions.cs | 8 +- .../Processing/Extensions/GlowExtensions.cs | 10 +-- .../Extensions/VignetteExtensions.cs | 10 +-- .../Processors/Overlays/GlowProcessor.cs | 2 +- .../Processors/Overlays/VignetteProcessor.cs | 2 +- .../Drawing/DrawImageTests.cs | 2 +- .../Drawing/Paths/DrawPathCollection.cs | 17 ++-- .../Drawing/Paths/FillPath.cs | 17 ++-- .../Drawing/Paths/FillPathCollection.cs | 17 ++-- .../Drawing/Paths/FillPolygon.cs | 17 ++-- .../Drawing/Paths/FillRectangle.cs | 24 +++--- .../Drawing/Text/TextGraphicsOptionsTests.cs | 85 +++++++++++++++---- .../ImageSharp.Tests/GraphicsOptionsTests.cs | 44 ++++++++-- .../Processing/Effects/BackgroundColorTest.cs | 24 +++--- .../Processing/Overlays/GlowTest.cs | 23 ++--- .../Processing/Overlays/VignetteTest.cs | 23 ++--- .../TestUtilities/GraphicsOptionsComparer.cs | 21 +++++ 29 files changed, 300 insertions(+), 170 deletions(-) create mode 100644 tests/ImageSharp.Tests/TestUtilities/GraphicsOptionsComparer.cs diff --git a/src/ImageSharp.Drawing/Processing/Extensions/DrawImageExtensions.cs b/src/ImageSharp.Drawing/Processing/Extensions/DrawImageExtensions.cs index 981cf1bef4..6c694ab73b 100644 --- a/src/ImageSharp.Drawing/Processing/Extensions/DrawImageExtensions.cs +++ b/src/ImageSharp.Drawing/Processing/Extensions/DrawImageExtensions.cs @@ -27,8 +27,8 @@ public static IImageProcessingContext DrawImage( new DrawImageProcessor( image, Point.Empty, - GraphicsOptions.Default.ColorBlendingMode, - GraphicsOptions.Default.AlphaCompositionMode, + new GraphicsOptions().ColorBlendingMode, + new GraphicsOptions().AlphaCompositionMode, opacity)); /// @@ -49,7 +49,7 @@ public static IImageProcessingContext DrawImage( image, Point.Empty, colorBlending, - GraphicsOptions.Default.AlphaCompositionMode, + new GraphicsOptions().AlphaCompositionMode, opacity)); /// @@ -105,8 +105,8 @@ public static IImageProcessingContext DrawImage( new DrawImageProcessor( image, location, - GraphicsOptions.Default.ColorBlendingMode, - GraphicsOptions.Default.AlphaCompositionMode, + new GraphicsOptions().ColorBlendingMode, + new GraphicsOptions().AlphaCompositionMode, opacity)); /// @@ -129,7 +129,7 @@ public static IImageProcessingContext DrawImage( image, location, colorBlending, - GraphicsOptions.Default.AlphaCompositionMode, + new GraphicsOptions().AlphaCompositionMode, opacity)); /// diff --git a/src/ImageSharp.Drawing/Processing/Extensions/DrawPathCollectionExtensions.cs b/src/ImageSharp.Drawing/Processing/Extensions/DrawPathCollectionExtensions.cs index a68b69a444..90b8c68ac2 100644 --- a/src/ImageSharp.Drawing/Processing/Extensions/DrawPathCollectionExtensions.cs +++ b/src/ImageSharp.Drawing/Processing/Extensions/DrawPathCollectionExtensions.cs @@ -41,7 +41,7 @@ public static IImageProcessingContext Draw( /// The . public static IImageProcessingContext Draw(this IImageProcessingContext source, IPen pen, IPathCollection paths) => - source.Draw(GraphicsOptions.Default, pen, paths); + source.Draw(new GraphicsOptions(), pen, paths); /// /// Draws the outline of the polygon with the provided brush at the provided thickness. diff --git a/src/ImageSharp.Drawing/Processing/Extensions/DrawPathExtensions.cs b/src/ImageSharp.Drawing/Processing/Extensions/DrawPathExtensions.cs index dfe30f6a3c..822375ca97 100644 --- a/src/ImageSharp.Drawing/Processing/Extensions/DrawPathExtensions.cs +++ b/src/ImageSharp.Drawing/Processing/Extensions/DrawPathExtensions.cs @@ -34,7 +34,7 @@ public static IImageProcessingContext Draw( /// The path. /// The . public static IImageProcessingContext Draw(this IImageProcessingContext source, IPen pen, IPath path) => - source.Draw(GraphicsOptions.Default, pen, path); + source.Draw(new GraphicsOptions(), pen, path); /// /// Draws the outline of the polygon with the provided brush at the provided thickness. diff --git a/src/ImageSharp.Drawing/Processing/Extensions/DrawPolygonExtensions.cs b/src/ImageSharp.Drawing/Processing/Extensions/DrawPolygonExtensions.cs index 86d8e9e2e2..d51e586452 100644 --- a/src/ImageSharp.Drawing/Processing/Extensions/DrawPolygonExtensions.cs +++ b/src/ImageSharp.Drawing/Processing/Extensions/DrawPolygonExtensions.cs @@ -86,7 +86,7 @@ public static IImageProcessingContext DrawPolygon( this IImageProcessingContext source, IPen pen, params PointF[] points) => - source.Draw(GraphicsOptions.Default, pen, new Polygon(new LinearLineSegment(points))); + source.Draw(new GraphicsOptions(), pen, new Polygon(new LinearLineSegment(points))); /// /// Draws the provided Points as a closed Linear Polygon with the provided Pen. diff --git a/src/ImageSharp.Drawing/Processing/Extensions/DrawRectangleExtensions.cs b/src/ImageSharp.Drawing/Processing/Extensions/DrawRectangleExtensions.cs index da78ab2ecc..b3b5dd76a5 100644 --- a/src/ImageSharp.Drawing/Processing/Extensions/DrawRectangleExtensions.cs +++ b/src/ImageSharp.Drawing/Processing/Extensions/DrawRectangleExtensions.cs @@ -34,7 +34,7 @@ public static IImageProcessingContext Draw( /// The shape. /// The . public static IImageProcessingContext Draw(this IImageProcessingContext source, IPen pen, RectangleF shape) => - source.Draw(GraphicsOptions.Default, pen, shape); + source.Draw(new GraphicsOptions(), pen, shape); /// /// Draws the outline of the rectangle with the provided brush at the provided thickness. diff --git a/src/ImageSharp.Drawing/Processing/Extensions/DrawTextExtensions.cs b/src/ImageSharp.Drawing/Processing/Extensions/DrawTextExtensions.cs index 05cd3a1ae6..82dbb8d97e 100644 --- a/src/ImageSharp.Drawing/Processing/Extensions/DrawTextExtensions.cs +++ b/src/ImageSharp.Drawing/Processing/Extensions/DrawTextExtensions.cs @@ -29,7 +29,7 @@ public static IImageProcessingContext DrawText( Font font, Color color, PointF location) => - source.DrawText(TextGraphicsOptions.Default, text, font, color, location); + source.DrawText(new TextGraphicsOptions(), text, font, color, location); /// /// Draws the text onto the the image filled via the brush. @@ -69,7 +69,7 @@ public static IImageProcessingContext DrawText( Font font, IBrush brush, PointF location) => - source.DrawText(TextGraphicsOptions.Default, text, font, brush, location); + source.DrawText(new TextGraphicsOptions(), text, font, brush, location); /// /// Draws the text onto the the image filled via the brush. @@ -109,7 +109,7 @@ public static IImageProcessingContext DrawText( Font font, IPen pen, PointF location) => - source.DrawText(TextGraphicsOptions.Default, text, font, pen, location); + source.DrawText(new TextGraphicsOptions(), text, font, pen, location); /// /// Draws the text onto the the image outlined via the pen. @@ -151,7 +151,7 @@ public static IImageProcessingContext DrawText( IBrush brush, IPen pen, PointF location) => - source.DrawText(TextGraphicsOptions.Default, text, font, brush, pen, location); + source.DrawText(new TextGraphicsOptions(), text, font, brush, pen, location); /// /// Draws the text using the default resolution of 72dpi onto the the image filled via the brush then outlined via the pen. diff --git a/src/ImageSharp.Drawing/Processing/Extensions/FillPathBuilderExtensions.cs b/src/ImageSharp.Drawing/Processing/Extensions/FillPathBuilderExtensions.cs index 5de9c6d4ed..030fe6ff1f 100644 --- a/src/ImageSharp.Drawing/Processing/Extensions/FillPathBuilderExtensions.cs +++ b/src/ImageSharp.Drawing/Processing/Extensions/FillPathBuilderExtensions.cs @@ -43,7 +43,7 @@ public static IImageProcessingContext Fill( this IImageProcessingContext source, IBrush brush, Action path) => - source.Fill(GraphicsOptions.Default, brush, path); + source.Fill(new GraphicsOptions(), brush, path); /// /// Flood fills the image in the shape of the provided polygon with the specified brush. diff --git a/src/ImageSharp.Drawing/Processing/Extensions/FillPathCollectionExtensions.cs b/src/ImageSharp.Drawing/Processing/Extensions/FillPathCollectionExtensions.cs index 776e1f7e4e..5d8aaf3071 100644 --- a/src/ImageSharp.Drawing/Processing/Extensions/FillPathCollectionExtensions.cs +++ b/src/ImageSharp.Drawing/Processing/Extensions/FillPathCollectionExtensions.cs @@ -43,7 +43,7 @@ public static IImageProcessingContext Fill( this IImageProcessingContext source, IBrush brush, IPathCollection paths) => - source.Fill(GraphicsOptions.Default, brush, paths); + source.Fill(new GraphicsOptions(), brush, paths); /// /// Flood fills the image in the shape of the provided polygon with the specified brush. diff --git a/src/ImageSharp.Drawing/Processing/Extensions/FillPathExtensions.cs b/src/ImageSharp.Drawing/Processing/Extensions/FillPathExtensions.cs index 718016a9e6..4d262aa5fb 100644 --- a/src/ImageSharp.Drawing/Processing/Extensions/FillPathExtensions.cs +++ b/src/ImageSharp.Drawing/Processing/Extensions/FillPathExtensions.cs @@ -34,7 +34,7 @@ public static IImageProcessingContext Fill( /// The path. /// The . public static IImageProcessingContext Fill(this IImageProcessingContext source, IBrush brush, IPath path) => - source.Fill(GraphicsOptions.Default, brush, new ShapeRegion(path)); + source.Fill(new GraphicsOptions(), brush, new ShapeRegion(path)); /// /// Flood fills the image in the shape of the provided polygon with the specified brush.. diff --git a/src/ImageSharp.Drawing/Processing/Extensions/FillRegionExtensions.cs b/src/ImageSharp.Drawing/Processing/Extensions/FillRegionExtensions.cs index 294e575140..f5dd76318c 100644 --- a/src/ImageSharp.Drawing/Processing/Extensions/FillRegionExtensions.cs +++ b/src/ImageSharp.Drawing/Processing/Extensions/FillRegionExtensions.cs @@ -18,7 +18,7 @@ public static class FillRegionExtensions /// The details how to fill the region of interest. /// The . public static IImageProcessingContext Fill(this IImageProcessingContext source, IBrush brush) => - source.Fill(GraphicsOptions.Default, brush); + source.Fill(new GraphicsOptions(), brush); /// /// Flood fills the image with the specified color. @@ -37,7 +37,7 @@ public static IImageProcessingContext Fill(this IImageProcessingContext source, /// The region. /// The . public static IImageProcessingContext Fill(this IImageProcessingContext source, IBrush brush, Region region) => - source.Fill(GraphicsOptions.Default, brush, region); + source.Fill(new GraphicsOptions(), brush, region); /// /// Flood fills the image with in the region with the specified color. diff --git a/src/ImageSharp.Drawing/Processing/TextGraphicsOptions.cs b/src/ImageSharp.Drawing/Processing/TextGraphicsOptions.cs index 60a48a31fa..185fa1f74c 100644 --- a/src/ImageSharp.Drawing/Processing/TextGraphicsOptions.cs +++ b/src/ImageSharp.Drawing/Processing/TextGraphicsOptions.cs @@ -1,7 +1,6 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. -using System; using SixLabors.Fonts; using SixLabors.ImageSharp.PixelFormats; @@ -10,7 +9,7 @@ namespace SixLabors.ImageSharp.Processing /// /// Options for influencing the drawing functions. /// - public class TextGraphicsOptions + public class TextGraphicsOptions : IDeepCloneable { private int antialiasSubpixelDepth = 16; private float blendPercentage = 1F; @@ -18,6 +17,29 @@ public class TextGraphicsOptions private float dpiX = 72F; private float dpiY = 72F; + /// + /// Initializes a new instance of the class. + /// + public TextGraphicsOptions() + { + } + + private TextGraphicsOptions(TextGraphicsOptions source) + { + this.AlphaCompositionMode = source.AlphaCompositionMode; + this.Antialias = source.Antialias; + this.AntialiasSubpixelDepth = source.AntialiasSubpixelDepth; + this.ApplyKerning = source.ApplyKerning; + this.BlendPercentage = source.BlendPercentage; + this.ColorBlendingMode = source.ColorBlendingMode; + this.DpiX = source.DpiX; + this.DpiY = source.DpiY; + this.HorizontalAlignment = source.HorizontalAlignment; + this.TabWidth = source.TabWidth; + this.WrapTextWidth = source.WrapTextWidth; + this.VerticalAlignment = source.VerticalAlignment; + } + /// /// Gets the default instance. /// @@ -194,27 +216,7 @@ public static explicit operator GraphicsOptions(TextGraphicsOptions options) }; } - /// - /// Creates a shallow copy of the . - /// - /// A new options instance. - public TextGraphicsOptions Clone() - { - return new TextGraphicsOptions - { - AlphaCompositionMode = this.AlphaCompositionMode, - Antialias = this.Antialias, - AntialiasSubpixelDepth = this.AntialiasSubpixelDepth, - ApplyKerning = this.ApplyKerning, - BlendPercentage = this.BlendPercentage, - ColorBlendingMode = this.ColorBlendingMode, - DpiX = this.DpiX, - DpiY = this.DpiY, - HorizontalAlignment = this.HorizontalAlignment, - TabWidth = this.TabWidth, - WrapTextWidth = this.WrapTextWidth, - VerticalAlignment = this.VerticalAlignment - }; - } + /// + public TextGraphicsOptions DeepClone() => new TextGraphicsOptions(this); } } diff --git a/src/ImageSharp/GraphicsOptions.cs b/src/ImageSharp/GraphicsOptions.cs index 1673057b86..9c62d23371 100644 --- a/src/ImageSharp/GraphicsOptions.cs +++ b/src/ImageSharp/GraphicsOptions.cs @@ -1,7 +1,6 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. -using System; using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp @@ -9,11 +8,27 @@ namespace SixLabors.ImageSharp /// /// Options for influencing the drawing functions. /// - public class GraphicsOptions + public class GraphicsOptions : IDeepCloneable { private int antialiasSubpixelDepth = 16; private float blendPercentage = 1F; + /// + /// Initializes a new instance of the class. + /// + public GraphicsOptions() + { + } + + private GraphicsOptions(GraphicsOptions source) + { + this.AlphaCompositionMode = source.AlphaCompositionMode; + this.Antialias = source.Antialias; + this.AntialiasSubpixelDepth = source.AntialiasSubpixelDepth; + this.BlendPercentage = source.BlendPercentage; + this.ColorBlendingMode = source.ColorBlendingMode; + } + /// /// Gets the default instance. /// @@ -73,20 +88,7 @@ public float BlendPercentage /// public PixelAlphaCompositionMode AlphaCompositionMode { get; set; } = PixelAlphaCompositionMode.SrcOver; - /// - /// Creates a shallow copy of the . - /// - /// A new options instance. - public GraphicsOptions Clone() - { - return new GraphicsOptions - { - AlphaCompositionMode = this.AlphaCompositionMode, - Antialias = this.Antialias, - AntialiasSubpixelDepth = this.AntialiasSubpixelDepth, - BlendPercentage = this.BlendPercentage, - ColorBlendingMode = this.ColorBlendingMode - }; - } + /// + public GraphicsOptions DeepClone() => new GraphicsOptions(this); } } diff --git a/src/ImageSharp/Processing/Extensions/BackgroundColorExtensions.cs b/src/ImageSharp/Processing/Extensions/BackgroundColorExtensions.cs index dd1cc1ed24..cc2fb25120 100644 --- a/src/ImageSharp/Processing/Extensions/BackgroundColorExtensions.cs +++ b/src/ImageSharp/Processing/Extensions/BackgroundColorExtensions.cs @@ -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.Overlays; @@ -19,7 +19,7 @@ public static class BackgroundColorExtensions /// The color to set as the background. /// The to allow chaining of operations. public static IImageProcessingContext BackgroundColor(this IImageProcessingContext source, Color color) => - BackgroundColor(source, GraphicsOptions.Default, color); + BackgroundColor(source, new GraphicsOptions(), color); /// /// Replaces the background color of image with the given one. @@ -34,7 +34,7 @@ public static IImageProcessingContext BackgroundColor( this IImageProcessingContext source, Color color, Rectangle rectangle) => - BackgroundColor(source, GraphicsOptions.Default, color, rectangle); + BackgroundColor(source, new GraphicsOptions(), color, rectangle); /// /// Replaces the background color of image with the given one. @@ -66,4 +66,4 @@ public static IImageProcessingContext BackgroundColor( Rectangle rectangle) => source.ApplyProcessor(new BackgroundColorProcessor(color, options), rectangle); } -} \ No newline at end of file +} diff --git a/src/ImageSharp/Processing/Extensions/GlowExtensions.cs b/src/ImageSharp/Processing/Extensions/GlowExtensions.cs index 39734882b0..90b73794ba 100644 --- a/src/ImageSharp/Processing/Extensions/GlowExtensions.cs +++ b/src/ImageSharp/Processing/Extensions/GlowExtensions.cs @@ -19,7 +19,7 @@ public static class GlowExtensions /// The image this method extends. /// The to allow chaining of operations. public static IImageProcessingContext Glow(this IImageProcessingContext source) => - Glow(source, GraphicsOptions.Default); + Glow(source, new GraphicsOptions()); /// /// Applies a radial glow effect to an image. @@ -29,7 +29,7 @@ public static IImageProcessingContext Glow(this IImageProcessingContext source) /// The to allow chaining of operations. public static IImageProcessingContext Glow(this IImageProcessingContext source, Color color) { - return Glow(source, GraphicsOptions.Default, color); + return Glow(source, new GraphicsOptions(), color); } /// @@ -39,7 +39,7 @@ public static IImageProcessingContext Glow(this IImageProcessingContext source, /// The the radius. /// The to allow chaining of operations. public static IImageProcessingContext Glow(this IImageProcessingContext source, float radius) => - Glow(source, GraphicsOptions.Default, radius); + Glow(source, new GraphicsOptions(), radius); /// /// Applies a radial glow effect to an image. @@ -50,7 +50,7 @@ public static IImageProcessingContext Glow(this IImageProcessingContext source, /// /// The to allow chaining of operations. public static IImageProcessingContext Glow(this IImageProcessingContext source, Rectangle rectangle) => - source.Glow(GraphicsOptions.Default, rectangle); + source.Glow(new GraphicsOptions(), rectangle); /// /// Applies a radial glow effect to an image. @@ -67,7 +67,7 @@ public static IImageProcessingContext Glow( Color color, float radius, Rectangle rectangle) => - source.Glow(GraphicsOptions.Default, color, ValueSize.Absolute(radius), rectangle); + source.Glow(new GraphicsOptions(), color, ValueSize.Absolute(radius), rectangle); /// /// Applies a radial glow effect to an image. diff --git a/src/ImageSharp/Processing/Extensions/VignetteExtensions.cs b/src/ImageSharp/Processing/Extensions/VignetteExtensions.cs index 74a59d3e13..ffab8e2bf9 100644 --- a/src/ImageSharp/Processing/Extensions/VignetteExtensions.cs +++ b/src/ImageSharp/Processing/Extensions/VignetteExtensions.cs @@ -19,7 +19,7 @@ public static class VignetteExtensions /// The image this method extends. /// The to allow chaining of operations. public static IImageProcessingContext Vignette(this IImageProcessingContext source) => - Vignette(source, GraphicsOptions.Default); + Vignette(source, new GraphicsOptions()); /// /// Applies a radial vignette effect to an image. @@ -28,7 +28,7 @@ public static IImageProcessingContext Vignette(this IImageProcessingContext sour /// The color to set as the vignette. /// The to allow chaining of operations. public static IImageProcessingContext Vignette(this IImageProcessingContext source, Color color) => - Vignette(source, GraphicsOptions.Default, color); + Vignette(source, new GraphicsOptions(), color); /// /// Applies a radial vignette effect to an image. @@ -41,7 +41,7 @@ public static IImageProcessingContext Vignette( this IImageProcessingContext source, float radiusX, float radiusY) => - Vignette(source, GraphicsOptions.Default, radiusX, radiusY); + Vignette(source, new GraphicsOptions(), radiusX, radiusY); /// /// Applies a radial vignette effect to an image. @@ -52,7 +52,7 @@ public static IImageProcessingContext Vignette( /// /// The to allow chaining of operations. public static IImageProcessingContext Vignette(this IImageProcessingContext source, Rectangle rectangle) => - Vignette(source, GraphicsOptions.Default, rectangle); + Vignette(source, new GraphicsOptions(), rectangle); /// /// Applies a radial vignette effect to an image. @@ -71,7 +71,7 @@ public static IImageProcessingContext Vignette( float radiusX, float radiusY, Rectangle rectangle) => - source.Vignette(GraphicsOptions.Default, color, radiusX, radiusY, rectangle); + source.Vignette(new GraphicsOptions(), color, radiusX, radiusY, rectangle); /// /// Applies a radial vignette effect to an image. diff --git a/src/ImageSharp/Processing/Processors/Overlays/GlowProcessor.cs b/src/ImageSharp/Processing/Processors/Overlays/GlowProcessor.cs index 0958e3aa9e..1a60b79aca 100644 --- a/src/ImageSharp/Processing/Processors/Overlays/GlowProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Overlays/GlowProcessor.cs @@ -37,7 +37,7 @@ public GlowProcessor(Color color, GraphicsOptions options) /// The color or the glow. /// The radius of the glow. internal GlowProcessor(Color color, ValueSize radius) - : this(color, radius, GraphicsOptions.Default) + : this(color, radius, new GraphicsOptions()) { } diff --git a/src/ImageSharp/Processing/Processors/Overlays/VignetteProcessor.cs b/src/ImageSharp/Processing/Processors/Overlays/VignetteProcessor.cs index 2365318f3d..e1c836ff56 100644 --- a/src/ImageSharp/Processing/Processors/Overlays/VignetteProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Overlays/VignetteProcessor.cs @@ -17,7 +17,7 @@ public sealed class VignetteProcessor : IImageProcessor /// /// The color of the vignette. public VignetteProcessor(Color color) - : this(color, GraphicsOptions.Default) + : this(color, new GraphicsOptions()) { } diff --git a/tests/ImageSharp.Tests/Drawing/DrawImageTests.cs b/tests/ImageSharp.Tests/Drawing/DrawImageTests.cs index 86c1c28504..61b45729d3 100644 --- a/tests/ImageSharp.Tests/Drawing/DrawImageTests.cs +++ b/tests/ImageSharp.Tests/Drawing/DrawImageTests.cs @@ -190,7 +190,7 @@ public void NonOverlappingImageThrows(TestImageProvider provider, int x, void Test() { - background.Mutate(context => context.DrawImage(overlay, new Point(x, y), GraphicsOptions.Default)); + background.Mutate(context => context.DrawImage(overlay, new Point(x, y), new GraphicsOptions())); } } } diff --git a/tests/ImageSharp.Tests/Drawing/Paths/DrawPathCollection.cs b/tests/ImageSharp.Tests/Drawing/Paths/DrawPathCollection.cs index f6d9c7fe5c..36c11035c6 100644 --- a/tests/ImageSharp.Tests/Drawing/Paths/DrawPathCollection.cs +++ b/tests/ImageSharp.Tests/Drawing/Paths/DrawPathCollection.cs @@ -7,6 +7,7 @@ using SixLabors.ImageSharp.Processing; using SixLabors.ImageSharp.Processing.Processors.Drawing; using SixLabors.ImageSharp.Tests.Processing; +using SixLabors.ImageSharp.Tests.TestUtilities; using SixLabors.Shapes; using Xunit; @@ -14,7 +15,9 @@ namespace SixLabors.ImageSharp.Tests.Drawing.Paths { public class DrawPathCollection : BaseImageOperationsExtensionTest { - GraphicsOptions noneDefault = new GraphicsOptions { Antialias = false }; + private static readonly GraphicsOptionsComparer graphicsOptionsComparer = new GraphicsOptionsComparer(); + + GraphicsOptions nonDefault = new GraphicsOptions { Antialias = false }; Color color = Color.HotPink; Pen pen = Pens.Solid(Rgba32.HotPink, 1); IPath path1 = new Path(new LinearLineSegment(new SixLabors.Primitives.PointF[] { @@ -46,7 +49,7 @@ public void CorrectlySetsBrushAndPath() { FillRegionProcessor processor = this.Verify(i); - Assert.Equal(GraphicsOptions.Default, processor.Options); + Assert.Equal(new GraphicsOptions(), processor.Options, graphicsOptionsComparer); ShapePath region = Assert.IsType(processor.Region); @@ -60,13 +63,13 @@ public void CorrectlySetsBrushAndPath() [Fact] public void CorrectlySetsBrushPathOptions() { - this.operations.Draw(this.noneDefault, this.pen, this.pathCollection); + this.operations.Draw(this.nonDefault, this.pen, this.pathCollection); for (int i = 0; i < 2; i++) { FillRegionProcessor processor = this.Verify(i); - Assert.Equal(this.noneDefault, processor.Options); + Assert.Equal(this.nonDefault, processor.Options, graphicsOptionsComparer); ShapePath region = Assert.IsType(processor.Region); Assert.IsType(region.Shape); @@ -84,7 +87,7 @@ public void CorrectlySetsColorAndPath() { FillRegionProcessor processor = this.Verify(i); - Assert.Equal(GraphicsOptions.Default, processor.Options); + Assert.Equal(new GraphicsOptions(), processor.Options, graphicsOptionsComparer); ShapePath region = Assert.IsType(processor.Region); Assert.IsType(region.Shape); @@ -97,13 +100,13 @@ public void CorrectlySetsColorAndPath() [Fact] public void CorrectlySetsColorPathAndOptions() { - this.operations.Draw(this.noneDefault, this.color, 1, this.pathCollection); + this.operations.Draw(this.nonDefault, this.color, 1, this.pathCollection); for (int i = 0; i < 2; i++) { FillRegionProcessor processor = this.Verify(i); - Assert.Equal(this.noneDefault, processor.Options); + Assert.Equal(this.nonDefault, processor.Options, graphicsOptionsComparer); ShapePath region = Assert.IsType(processor.Region); Assert.IsType(region.Shape); diff --git a/tests/ImageSharp.Tests/Drawing/Paths/FillPath.cs b/tests/ImageSharp.Tests/Drawing/Paths/FillPath.cs index fa1949e673..cea59e15e5 100644 --- a/tests/ImageSharp.Tests/Drawing/Paths/FillPath.cs +++ b/tests/ImageSharp.Tests/Drawing/Paths/FillPath.cs @@ -7,6 +7,7 @@ using SixLabors.ImageSharp.Processing; using SixLabors.ImageSharp.Processing.Processors.Drawing; using SixLabors.ImageSharp.Tests.Processing; +using SixLabors.ImageSharp.Tests.TestUtilities; using SixLabors.Shapes; using Xunit; @@ -14,7 +15,9 @@ namespace SixLabors.ImageSharp.Tests.Drawing.Paths { public class FillPath : BaseImageOperationsExtensionTest { - GraphicsOptions noneDefault = new GraphicsOptions { Antialias = false }; + private static readonly GraphicsOptionsComparer graphicsOptionsComparer = new GraphicsOptionsComparer(); + + GraphicsOptions nonDefault = new GraphicsOptions { Antialias = false }; Color color = Color.HotPink; SolidBrush brush = Brushes.Solid(Rgba32.HotPink); IPath path = new Path(new LinearLineSegment(new SixLabors.Primitives.PointF[] { @@ -30,7 +33,7 @@ public void CorrectlySetsBrushAndPath() this.operations.Fill(this.brush, this.path); var processor = this.Verify(); - Assert.Equal(GraphicsOptions.Default, processor.Options); + Assert.Equal(new GraphicsOptions(), processor.Options, graphicsOptionsComparer); ShapeRegion region = Assert.IsType(processor.Region); @@ -44,10 +47,10 @@ public void CorrectlySetsBrushAndPath() [Fact] public void CorrectlySetsBrushPathOptions() { - this.operations.Fill(this.noneDefault, this.brush, this.path); + this.operations.Fill(this.nonDefault, this.brush, this.path); var processor = this.Verify(); - Assert.Equal(this.noneDefault, processor.Options); + Assert.Equal(this.nonDefault, processor.Options, graphicsOptionsComparer); ShapeRegion region = Assert.IsType(processor.Region); Polygon polygon = Assert.IsType(region.Shape); @@ -62,7 +65,7 @@ public void CorrectlySetsColorAndPath() this.operations.Fill(this.color, this.path); var processor = this.Verify(); - Assert.Equal(GraphicsOptions.Default, processor.Options); + Assert.Equal(new GraphicsOptions(), processor.Options, graphicsOptionsComparer); ShapeRegion region = Assert.IsType(processor.Region); Polygon polygon = Assert.IsType(region.Shape); @@ -75,10 +78,10 @@ public void CorrectlySetsColorAndPath() [Fact] public void CorrectlySetsColorPathAndOptions() { - this.operations.Fill(this.noneDefault, this.color, this.path); + this.operations.Fill(this.nonDefault, this.color, this.path); var processor = this.Verify(); - Assert.Equal(this.noneDefault, processor.Options); + Assert.Equal(this.nonDefault, processor.Options); ShapeRegion region = Assert.IsType(processor.Region); Polygon polygon = Assert.IsType(region.Shape); diff --git a/tests/ImageSharp.Tests/Drawing/Paths/FillPathCollection.cs b/tests/ImageSharp.Tests/Drawing/Paths/FillPathCollection.cs index 39e2fc2f97..2a9c04a89f 100644 --- a/tests/ImageSharp.Tests/Drawing/Paths/FillPathCollection.cs +++ b/tests/ImageSharp.Tests/Drawing/Paths/FillPathCollection.cs @@ -7,6 +7,7 @@ using SixLabors.ImageSharp.Processing; using SixLabors.ImageSharp.Processing.Processors.Drawing; using SixLabors.ImageSharp.Tests.Processing; +using SixLabors.ImageSharp.Tests.TestUtilities; using SixLabors.Shapes; using Xunit; @@ -14,7 +15,9 @@ namespace SixLabors.ImageSharp.Tests.Drawing.Paths { public class FillPathCollection : BaseImageOperationsExtensionTest { - GraphicsOptions noneDefault = new GraphicsOptions { Antialias = false }; + private static readonly GraphicsOptionsComparer graphicsOptionsComparer = new GraphicsOptionsComparer(); + + GraphicsOptions nonDefault = new GraphicsOptions { Antialias = false }; Color color = Color.HotPink; SolidBrush brush = Brushes.Solid(Rgba32.HotPink); IPath path1 = new Path(new LinearLineSegment(new SixLabors.Primitives.PointF[] { @@ -46,7 +49,7 @@ public void CorrectlySetsBrushAndPath() { FillRegionProcessor processor = this.Verify(i); - Assert.Equal(GraphicsOptions.Default, processor.Options); + Assert.Equal(new GraphicsOptions(), processor.Options, graphicsOptionsComparer); ShapeRegion region = Assert.IsType(processor.Region); @@ -61,13 +64,13 @@ public void CorrectlySetsBrushAndPath() [Fact] public void CorrectlySetsBrushPathOptions() { - this.operations.Fill(this.noneDefault, this.brush, this.pathCollection); + this.operations.Fill(this.nonDefault, this.brush, this.pathCollection); for (int i = 0; i < 2; i++) { FillRegionProcessor processor = this.Verify(i); - Assert.Equal(this.noneDefault, processor.Options); + Assert.Equal(this.nonDefault, processor.Options, graphicsOptionsComparer); ShapeRegion region = Assert.IsType(processor.Region); Polygon polygon = Assert.IsType(region.Shape); @@ -86,7 +89,7 @@ public void CorrectlySetsColorAndPath() { FillRegionProcessor processor = this.Verify(i); - Assert.Equal(GraphicsOptions.Default, processor.Options); + Assert.Equal(new GraphicsOptions(), processor.Options, graphicsOptionsComparer); ShapeRegion region = Assert.IsType(processor.Region); Polygon polygon = Assert.IsType(region.Shape); @@ -100,13 +103,13 @@ public void CorrectlySetsColorAndPath() [Fact] public void CorrectlySetsColorPathAndOptions() { - this.operations.Fill(this.noneDefault, this.color, this.pathCollection); + this.operations.Fill(this.nonDefault, this.color, this.pathCollection); for (int i = 0; i < 2; i++) { FillRegionProcessor processor = this.Verify(i); - Assert.Equal(this.noneDefault, processor.Options); + Assert.Equal(this.nonDefault, processor.Options, graphicsOptionsComparer); ShapeRegion region = Assert.IsType(processor.Region); Polygon polygon = Assert.IsType(region.Shape); diff --git a/tests/ImageSharp.Tests/Drawing/Paths/FillPolygon.cs b/tests/ImageSharp.Tests/Drawing/Paths/FillPolygon.cs index 03a827a6a9..8dacd1e7f6 100644 --- a/tests/ImageSharp.Tests/Drawing/Paths/FillPolygon.cs +++ b/tests/ImageSharp.Tests/Drawing/Paths/FillPolygon.cs @@ -7,6 +7,7 @@ using SixLabors.ImageSharp.Processing; using SixLabors.ImageSharp.Processing.Processors.Drawing; using SixLabors.ImageSharp.Tests.Processing; +using SixLabors.ImageSharp.Tests.TestUtilities; using SixLabors.Shapes; using Xunit; @@ -14,7 +15,9 @@ namespace SixLabors.ImageSharp.Tests.Drawing.Paths { public class FillPolygon : BaseImageOperationsExtensionTest { - GraphicsOptions noneDefault = new GraphicsOptions { Antialias = false }; + private static readonly GraphicsOptionsComparer graphicsOptionsComparer = new GraphicsOptionsComparer(); + + GraphicsOptions nonDefault = new GraphicsOptions { Antialias = false }; Color color = Color.HotPink; SolidBrush brush = Brushes.Solid(Rgba32.HotPink); SixLabors.Primitives.PointF[] path = { @@ -32,7 +35,7 @@ public void CorrectlySetsBrushAndPath() FillRegionProcessor processor = this.Verify(); - Assert.Equal(GraphicsOptions.Default, processor.Options); + Assert.Equal(new GraphicsOptions(), processor.Options, graphicsOptionsComparer); ShapeRegion region = Assert.IsType(processor.Region); Polygon polygon = Assert.IsType(region.Shape); @@ -44,10 +47,10 @@ public void CorrectlySetsBrushAndPath() [Fact] public void CorrectlySetsBrushPathAndOptions() { - this.operations.FillPolygon(this.noneDefault, this.brush, this.path); + this.operations.FillPolygon(this.nonDefault, this.brush, this.path); FillRegionProcessor processor = this.Verify(); - Assert.Equal(this.noneDefault, processor.Options); + Assert.Equal(this.nonDefault, processor.Options, graphicsOptionsComparer); ShapeRegion region = Assert.IsType(processor.Region); Polygon polygon = Assert.IsType(region.Shape); @@ -63,7 +66,7 @@ public void CorrectlySetsColorAndPath() FillRegionProcessor processor = this.Verify(); - Assert.Equal(GraphicsOptions.Default, processor.Options); + Assert.Equal(new GraphicsOptions(), processor.Options, graphicsOptionsComparer); ShapeRegion region = Assert.IsType(processor.Region); Polygon polygon = Assert.IsType(region.Shape); @@ -76,10 +79,10 @@ public void CorrectlySetsColorAndPath() [Fact] public void CorrectlySetsColorPathAndOptions() { - this.operations.FillPolygon(this.noneDefault, this.color, this.path); + this.operations.FillPolygon(this.nonDefault, this.color, this.path); FillRegionProcessor processor = this.Verify(); - Assert.Equal(this.noneDefault, processor.Options); + Assert.Equal(this.nonDefault, processor.Options, graphicsOptionsComparer); ShapeRegion region = Assert.IsType(processor.Region); Polygon polygon = Assert.IsType(region.Shape); diff --git a/tests/ImageSharp.Tests/Drawing/Paths/FillRectangle.cs b/tests/ImageSharp.Tests/Drawing/Paths/FillRectangle.cs index cc108fb54e..6b08323b68 100644 --- a/tests/ImageSharp.Tests/Drawing/Paths/FillRectangle.cs +++ b/tests/ImageSharp.Tests/Drawing/Paths/FillRectangle.cs @@ -6,17 +6,19 @@ using SixLabors.ImageSharp.Processing; using SixLabors.ImageSharp.Processing.Processors.Drawing; using SixLabors.ImageSharp.Tests.Processing; - +using SixLabors.ImageSharp.Tests.TestUtilities; using Xunit; namespace SixLabors.ImageSharp.Tests.Drawing.Paths { public class FillRectangle : BaseImageOperationsExtensionTest { - GraphicsOptions noneDefault = new GraphicsOptions { Antialias = false }; - Color color = Color.HotPink; - SolidBrush brush = Brushes.Solid(Rgba32.HotPink); - SixLabors.Primitives.Rectangle rectangle = new SixLabors.Primitives.Rectangle(10, 10, 77, 76); + private static readonly GraphicsOptionsComparer graphicsOptionsComparer = new GraphicsOptionsComparer(); + + private GraphicsOptions nonDefault = new GraphicsOptions { Antialias = false }; + private Color color = Color.HotPink; + private SolidBrush brush = Brushes.Solid(Rgba32.HotPink); + private SixLabors.Primitives.Rectangle rectangle = new SixLabors.Primitives.Rectangle(10, 10, 77, 76); [Fact] public void CorrectlySetsBrushAndRectangle() @@ -24,7 +26,7 @@ public void CorrectlySetsBrushAndRectangle() this.operations.Fill(this.brush, this.rectangle); FillRegionProcessor processor = this.Verify(); - Assert.Equal(GraphicsOptions.Default, processor.Options); + Assert.Equal(new GraphicsOptions(), processor.Options, graphicsOptionsComparer); ShapeRegion region = Assert.IsType(processor.Region); Shapes.RectangularPolygon rect = Assert.IsType(region.Shape); @@ -39,10 +41,10 @@ public void CorrectlySetsBrushAndRectangle() [Fact] public void CorrectlySetsBrushRectangleAndOptions() { - this.operations.Fill(this.noneDefault, this.brush, this.rectangle); + this.operations.Fill(this.nonDefault, this.brush, this.rectangle); FillRegionProcessor processor = this.Verify(); - Assert.Equal(this.noneDefault, processor.Options); + Assert.Equal(this.nonDefault, processor.Options, graphicsOptionsComparer); ShapeRegion region = Assert.IsType(processor.Region); Shapes.RectangularPolygon rect = Assert.IsType(region.Shape); @@ -60,7 +62,7 @@ public void CorrectlySetsColorAndRectangle() this.operations.Fill(this.color, this.rectangle); FillRegionProcessor processor = this.Verify(); - Assert.Equal(GraphicsOptions.Default, processor.Options); + Assert.Equal(new GraphicsOptions(), processor.Options, graphicsOptionsComparer); ShapeRegion region = Assert.IsType(processor.Region); Shapes.RectangularPolygon rect = Assert.IsType(region.Shape); @@ -76,10 +78,10 @@ public void CorrectlySetsColorAndRectangle() [Fact] public void CorrectlySetsColorRectangleAndOptions() { - this.operations.Fill(this.noneDefault, this.color, this.rectangle); + this.operations.Fill(this.nonDefault, this.color, this.rectangle); FillRegionProcessor processor = this.Verify(); - Assert.Equal(this.noneDefault, processor.Options); + Assert.Equal(this.nonDefault, processor.Options, graphicsOptionsComparer); ShapeRegion region = Assert.IsType(processor.Region); Shapes.RectangularPolygon rect = Assert.IsType(region.Shape); diff --git a/tests/ImageSharp.Tests/Drawing/Text/TextGraphicsOptionsTests.cs b/tests/ImageSharp.Tests/Drawing/Text/TextGraphicsOptionsTests.cs index d15b717bb6..a59afb271d 100644 --- a/tests/ImageSharp.Tests/Drawing/Text/TextGraphicsOptionsTests.cs +++ b/tests/ImageSharp.Tests/Drawing/Text/TextGraphicsOptionsTests.cs @@ -12,17 +12,15 @@ namespace SixLabors.ImageSharp.Tests.Drawing.Text public class TextGraphicsOptionsTests { private readonly TextGraphicsOptions newTextGraphicsOptions = new TextGraphicsOptions(); - private readonly TextGraphicsOptions defaultTextGraphicsOptions = TextGraphicsOptions.Default; - private readonly TextGraphicsOptions cloneTextGraphicsOptions = TextGraphicsOptions.Default.Clone(); + private readonly TextGraphicsOptions cloneTextGraphicsOptions = new TextGraphicsOptions().DeepClone(); [Fact] - public void DefaultTextGraphicsOptionsIsNotNull() => Assert.True(this.defaultTextGraphicsOptions != null); + public void CloneTextGraphicsOptionsIsNotNull() => Assert.True(this.cloneTextGraphicsOptions != null); [Fact] public void DefaultTextGraphicsOptionsAntialias() { Assert.True(this.newTextGraphicsOptions.Antialias); - Assert.True(this.defaultTextGraphicsOptions.Antialias); Assert.True(this.cloneTextGraphicsOptions.Antialias); } @@ -31,7 +29,6 @@ public void DefaultTextGraphicsOptionsAntialiasSuppixelDepth() { const int Expected = 16; Assert.Equal(Expected, this.newTextGraphicsOptions.AntialiasSubpixelDepth); - Assert.Equal(Expected, this.defaultTextGraphicsOptions.AntialiasSubpixelDepth); Assert.Equal(Expected, this.cloneTextGraphicsOptions.AntialiasSubpixelDepth); } @@ -40,7 +37,6 @@ public void DefaultTextGraphicsOptionsBlendPercentage() { const float Expected = 1F; Assert.Equal(Expected, this.newTextGraphicsOptions.BlendPercentage); - Assert.Equal(Expected, this.defaultTextGraphicsOptions.BlendPercentage); Assert.Equal(Expected, this.cloneTextGraphicsOptions.BlendPercentage); } @@ -49,7 +45,6 @@ public void DefaultTextGraphicsOptionsColorBlendingMode() { const PixelColorBlendingMode Expected = PixelColorBlendingMode.Normal; Assert.Equal(Expected, this.newTextGraphicsOptions.ColorBlendingMode); - Assert.Equal(Expected, this.defaultTextGraphicsOptions.ColorBlendingMode); Assert.Equal(Expected, this.cloneTextGraphicsOptions.ColorBlendingMode); } @@ -58,7 +53,6 @@ public void DefaultTextGraphicsOptionsAlphaCompositionMode() { const PixelAlphaCompositionMode Expected = PixelAlphaCompositionMode.SrcOver; Assert.Equal(Expected, this.newTextGraphicsOptions.AlphaCompositionMode); - Assert.Equal(Expected, this.defaultTextGraphicsOptions.AlphaCompositionMode); Assert.Equal(Expected, this.cloneTextGraphicsOptions.AlphaCompositionMode); } @@ -67,7 +61,6 @@ public void DefaultTextGraphicsOptionsApplyKerning() { const bool Expected = true; Assert.Equal(Expected, this.newTextGraphicsOptions.ApplyKerning); - Assert.Equal(Expected, this.defaultTextGraphicsOptions.ApplyKerning); Assert.Equal(Expected, this.cloneTextGraphicsOptions.ApplyKerning); } @@ -76,7 +69,6 @@ public void DefaultTextGraphicsOptionsHorizontalAlignment() { const HorizontalAlignment Expected = HorizontalAlignment.Left; Assert.Equal(Expected, this.newTextGraphicsOptions.HorizontalAlignment); - Assert.Equal(Expected, this.defaultTextGraphicsOptions.HorizontalAlignment); Assert.Equal(Expected, this.cloneTextGraphicsOptions.HorizontalAlignment); } @@ -85,7 +77,6 @@ public void DefaultTextGraphicsOptionsVerticalAlignment() { const VerticalAlignment Expected = VerticalAlignment.Top; Assert.Equal(Expected, this.newTextGraphicsOptions.VerticalAlignment); - Assert.Equal(Expected, this.defaultTextGraphicsOptions.VerticalAlignment); Assert.Equal(Expected, this.cloneTextGraphicsOptions.VerticalAlignment); } @@ -94,7 +85,6 @@ public void DefaultTextGraphicsOptionsDpiX() { const float Expected = 72F; Assert.Equal(Expected, this.newTextGraphicsOptions.DpiX); - Assert.Equal(Expected, this.defaultTextGraphicsOptions.DpiX); Assert.Equal(Expected, this.cloneTextGraphicsOptions.DpiX); } @@ -103,7 +93,6 @@ public void DefaultTextGraphicsOptionsDpiY() { const float Expected = 72F; Assert.Equal(Expected, this.newTextGraphicsOptions.DpiY); - Assert.Equal(Expected, this.defaultTextGraphicsOptions.DpiY); Assert.Equal(Expected, this.cloneTextGraphicsOptions.DpiY); } @@ -112,7 +101,6 @@ public void DefaultTextGraphicsOptionsTabWidth() { const float Expected = 4F; Assert.Equal(Expected, this.newTextGraphicsOptions.TabWidth); - Assert.Equal(Expected, this.defaultTextGraphicsOptions.TabWidth); Assert.Equal(Expected, this.cloneTextGraphicsOptions.TabWidth); } @@ -121,10 +109,77 @@ public void DefaultTextGraphicsOptionsWrapTextWidth() { const float Expected = 0F; Assert.Equal(Expected, this.newTextGraphicsOptions.WrapTextWidth); - Assert.Equal(Expected, this.defaultTextGraphicsOptions.WrapTextWidth); Assert.Equal(Expected, this.cloneTextGraphicsOptions.WrapTextWidth); } + [Fact] + public void NonDefaultClone() + { + var expected = new TextGraphicsOptions + { + AlphaCompositionMode = PixelAlphaCompositionMode.DestAtop, + Antialias = false, + AntialiasSubpixelDepth = 23, + ApplyKerning = false, + BlendPercentage = .25F, + ColorBlendingMode = PixelColorBlendingMode.HardLight, + DpiX = 46F, + DpiY = 52F, + HorizontalAlignment = HorizontalAlignment.Center, + TabWidth = 3F, + VerticalAlignment = VerticalAlignment.Bottom, + WrapTextWidth = 42F + }; + + TextGraphicsOptions actual = expected.DeepClone(); + + Assert.Equal(expected.AlphaCompositionMode, actual.AlphaCompositionMode); + Assert.Equal(expected.Antialias, actual.Antialias); + Assert.Equal(expected.AntialiasSubpixelDepth, actual.AntialiasSubpixelDepth); + Assert.Equal(expected.ApplyKerning, actual.ApplyKerning); + Assert.Equal(expected.BlendPercentage, actual.BlendPercentage); + Assert.Equal(expected.ColorBlendingMode, actual.ColorBlendingMode); + Assert.Equal(expected.DpiX, actual.DpiX); + Assert.Equal(expected.DpiY, actual.DpiY); + Assert.Equal(expected.HorizontalAlignment, actual.HorizontalAlignment); + Assert.Equal(expected.TabWidth, actual.TabWidth); + Assert.Equal(expected.VerticalAlignment, actual.VerticalAlignment); + Assert.Equal(expected.WrapTextWidth, actual.WrapTextWidth); + } + + [Fact] + public void CloneIsDeep() + { + var expected = new TextGraphicsOptions(); + TextGraphicsOptions actual = expected.DeepClone(); + + actual.AlphaCompositionMode = PixelAlphaCompositionMode.DestAtop; + actual.Antialias = false; + actual.AntialiasSubpixelDepth = 23; + actual.ApplyKerning = false; + actual.BlendPercentage = .25F; + actual.ColorBlendingMode = PixelColorBlendingMode.HardLight; + actual.DpiX = 46F; + actual.DpiY = 52F; + actual.HorizontalAlignment = HorizontalAlignment.Center; + actual.TabWidth = 3F; + actual.VerticalAlignment = VerticalAlignment.Bottom; + actual.WrapTextWidth = 42F; + + Assert.NotEqual(expected.AlphaCompositionMode, actual.AlphaCompositionMode); + Assert.NotEqual(expected.Antialias, actual.Antialias); + Assert.NotEqual(expected.AntialiasSubpixelDepth, actual.AntialiasSubpixelDepth); + Assert.NotEqual(expected.ApplyKerning, actual.ApplyKerning); + Assert.NotEqual(expected.BlendPercentage, actual.BlendPercentage); + Assert.NotEqual(expected.ColorBlendingMode, actual.ColorBlendingMode); + Assert.NotEqual(expected.DpiX, actual.DpiX); + Assert.NotEqual(expected.DpiY, actual.DpiY); + Assert.NotEqual(expected.HorizontalAlignment, actual.HorizontalAlignment); + Assert.NotEqual(expected.TabWidth, actual.TabWidth); + Assert.NotEqual(expected.VerticalAlignment, actual.VerticalAlignment); + Assert.NotEqual(expected.WrapTextWidth, actual.WrapTextWidth); + } + [Fact] public void ExplicitCastOfGraphicsOptions() { diff --git a/tests/ImageSharp.Tests/GraphicsOptionsTests.cs b/tests/ImageSharp.Tests/GraphicsOptionsTests.cs index 4e23b17663..69f904f1cb 100644 --- a/tests/ImageSharp.Tests/GraphicsOptionsTests.cs +++ b/tests/ImageSharp.Tests/GraphicsOptionsTests.cs @@ -2,24 +2,24 @@ // Licensed under the Apache License, Version 2.0. using SixLabors.ImageSharp.PixelFormats; +using SixLabors.ImageSharp.Tests.TestUtilities; using Xunit; namespace SixLabors.ImageSharp.Tests { public class GraphicsOptionsTests { + private static readonly GraphicsOptionsComparer graphicsOptionsComparer = new GraphicsOptionsComparer(); private readonly GraphicsOptions newGraphicsOptions = new GraphicsOptions(); - private readonly GraphicsOptions defaultGraphicsOptions = GraphicsOptions.Default; - private readonly GraphicsOptions cloneGraphicsOptions = GraphicsOptions.Default.Clone(); + private readonly GraphicsOptions cloneGraphicsOptions = new GraphicsOptions().DeepClone(); [Fact] - public void DefaultGraphicsOptionsIsNotNull() => Assert.True(this.defaultGraphicsOptions != null); + public void CloneGraphicsOptionsIsNotNull() => Assert.True(this.cloneGraphicsOptions != null); [Fact] public void DefaultGraphicsOptionsAntialias() { Assert.True(this.newGraphicsOptions.Antialias); - Assert.True(this.defaultGraphicsOptions.Antialias); Assert.True(this.cloneGraphicsOptions.Antialias); } @@ -28,7 +28,6 @@ public void DefaultGraphicsOptionsAntialiasSuppixelDepth() { const int Expected = 16; Assert.Equal(Expected, this.newGraphicsOptions.AntialiasSubpixelDepth); - Assert.Equal(Expected, this.defaultGraphicsOptions.AntialiasSubpixelDepth); Assert.Equal(Expected, this.cloneGraphicsOptions.AntialiasSubpixelDepth); } @@ -37,7 +36,6 @@ public void DefaultGraphicsOptionsBlendPercentage() { const float Expected = 1F; Assert.Equal(Expected, this.newGraphicsOptions.BlendPercentage); - Assert.Equal(Expected, this.defaultGraphicsOptions.BlendPercentage); Assert.Equal(Expected, this.cloneGraphicsOptions.BlendPercentage); } @@ -46,7 +44,6 @@ public void DefaultGraphicsOptionsColorBlendingMode() { const PixelColorBlendingMode Expected = PixelColorBlendingMode.Normal; Assert.Equal(Expected, this.newGraphicsOptions.ColorBlendingMode); - Assert.Equal(Expected, this.defaultGraphicsOptions.ColorBlendingMode); Assert.Equal(Expected, this.cloneGraphicsOptions.ColorBlendingMode); } @@ -55,10 +52,41 @@ public void DefaultGraphicsOptionsAlphaCompositionMode() { const PixelAlphaCompositionMode Expected = PixelAlphaCompositionMode.SrcOver; Assert.Equal(Expected, this.newGraphicsOptions.AlphaCompositionMode); - Assert.Equal(Expected, this.defaultGraphicsOptions.AlphaCompositionMode); Assert.Equal(Expected, this.cloneGraphicsOptions.AlphaCompositionMode); } + [Fact] + public void NonDefaultClone() + { + var expected = new GraphicsOptions + { + AlphaCompositionMode = PixelAlphaCompositionMode.DestAtop, + Antialias = false, + AntialiasSubpixelDepth = 23, + BlendPercentage = .25F, + ColorBlendingMode = PixelColorBlendingMode.HardLight, + }; + + GraphicsOptions actual = expected.DeepClone(); + + Assert.Equal(expected, actual, graphicsOptionsComparer); + } + + [Fact] + public void CloneIsDeep() + { + var expected = new GraphicsOptions(); + GraphicsOptions actual = expected.DeepClone(); + + actual.AlphaCompositionMode = PixelAlphaCompositionMode.DestAtop; + actual.Antialias = false; + actual.AntialiasSubpixelDepth = 23; + actual.BlendPercentage = .25F; + actual.ColorBlendingMode = PixelColorBlendingMode.HardLight; + + Assert.NotEqual(expected, actual, graphicsOptionsComparer); + } + [Fact] public void IsOpaqueColor() { diff --git a/tests/ImageSharp.Tests/Processing/Effects/BackgroundColorTest.cs b/tests/ImageSharp.Tests/Processing/Effects/BackgroundColorTest.cs index 1b5bd656dc..a137a9f438 100644 --- a/tests/ImageSharp.Tests/Processing/Effects/BackgroundColorTest.cs +++ b/tests/ImageSharp.Tests/Processing/Effects/BackgroundColorTest.cs @@ -1,22 +1,24 @@ -// Copyright (c) Six Labors and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. using SixLabors.ImageSharp.Processing; using SixLabors.ImageSharp.Processing.Processors.Overlays; - +using SixLabors.ImageSharp.Tests.TestUtilities; using Xunit; namespace SixLabors.ImageSharp.Tests.Processing.Effects { public class BackgroundColorTest : BaseImageOperationsExtensionTest { + private static readonly GraphicsOptionsComparer graphicsOptionsComparer = new GraphicsOptionsComparer(); + [Fact] public void BackgroundColor_amount_BackgroundColorProcessorDefaultsSet() { this.operations.BackgroundColor(Color.BlanchedAlmond); - var processor = this.Verify(); + BackgroundColorProcessor processor = this.Verify(); - Assert.Equal(GraphicsOptions.Default, processor.GraphicsOptions); + Assert.Equal(new GraphicsOptions(), processor.GraphicsOptions, graphicsOptionsComparer); Assert.Equal(Color.BlanchedAlmond, processor.Color); } @@ -24,9 +26,9 @@ public void BackgroundColor_amount_BackgroundColorProcessorDefaultsSet() public void BackgroundColor_amount_rect_BackgroundColorProcessorDefaultsSet() { this.operations.BackgroundColor(Color.BlanchedAlmond, this.rect); - var processor = this.Verify(this.rect); + BackgroundColorProcessor processor = this.Verify(this.rect); - Assert.Equal(GraphicsOptions.Default, processor.GraphicsOptions); + Assert.Equal(new GraphicsOptions(), processor.GraphicsOptions, graphicsOptionsComparer); Assert.Equal(Color.BlanchedAlmond, processor.Color); } @@ -34,9 +36,9 @@ public void BackgroundColor_amount_rect_BackgroundColorProcessorDefaultsSet() public void BackgroundColor_amount_options_BackgroundColorProcessorDefaultsSet() { this.operations.BackgroundColor(this.options, Color.BlanchedAlmond); - var processor = this.Verify(); + BackgroundColorProcessor processor = this.Verify(); - Assert.Equal(this.options, processor.GraphicsOptions); + Assert.Equal(this.options, processor.GraphicsOptions, graphicsOptionsComparer); Assert.Equal(Color.BlanchedAlmond, processor.Color); } @@ -44,10 +46,10 @@ public void BackgroundColor_amount_options_BackgroundColorProcessorDefaultsSet() public void BackgroundColor_amount_rect_options_BackgroundColorProcessorDefaultsSet() { this.operations.BackgroundColor(this.options, Color.BlanchedAlmond, this.rect); - var processor = this.Verify(this.rect); + BackgroundColorProcessor processor = this.Verify(this.rect); - Assert.Equal(this.options, processor.GraphicsOptions); + Assert.Equal(this.options, processor.GraphicsOptions, graphicsOptionsComparer); Assert.Equal(Color.BlanchedAlmond, processor.Color); } } -} \ No newline at end of file +} diff --git a/tests/ImageSharp.Tests/Processing/Overlays/GlowTest.cs b/tests/ImageSharp.Tests/Processing/Overlays/GlowTest.cs index 978fd416bc..32c4c6fe74 100644 --- a/tests/ImageSharp.Tests/Processing/Overlays/GlowTest.cs +++ b/tests/ImageSharp.Tests/Processing/Overlays/GlowTest.cs @@ -1,10 +1,11 @@ -// Copyright (c) Six Labors and contributors. +// 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; using SixLabors.ImageSharp.Processing.Processors.Overlays; +using SixLabors.ImageSharp.Tests.TestUtilities; using SixLabors.Primitives; using Xunit; @@ -12,13 +13,15 @@ namespace SixLabors.ImageSharp.Tests.Processing.Overlays { public class GlowTest : BaseImageOperationsExtensionTest { + private static readonly GraphicsOptionsComparer graphicsOptionsComparer = new GraphicsOptionsComparer(); + [Fact] public void Glow_GlowProcessorWithDefaultValues() { this.operations.Glow(); - var p = this.Verify(); + GlowProcessor p = this.Verify(); - Assert.Equal(GraphicsOptions.Default, p.GraphicsOptions); + Assert.Equal(new GraphicsOptions(), p.GraphicsOptions, graphicsOptionsComparer); Assert.Equal(Color.Black, p.GlowColor); Assert.Equal(ValueSize.PercentageOfWidth(.5f), p.Radius); } @@ -27,9 +30,9 @@ public void Glow_GlowProcessorWithDefaultValues() public void Glow_Color_GlowProcessorWithDefaultValues() { this.operations.Glow(Rgba32.Aquamarine); - var p = this.Verify(); + GlowProcessor p = this.Verify(); - Assert.Equal(GraphicsOptions.Default, p.GraphicsOptions); + Assert.Equal(new GraphicsOptions(), p.GraphicsOptions, graphicsOptionsComparer); Assert.Equal(Color.Aquamarine, p.GlowColor); Assert.Equal(ValueSize.PercentageOfWidth(.5f), p.Radius); } @@ -38,9 +41,9 @@ public void Glow_Color_GlowProcessorWithDefaultValues() public void Glow_Radux_GlowProcessorWithDefaultValues() { this.operations.Glow(3.5f); - var p = this.Verify(); + GlowProcessor p = this.Verify(); - Assert.Equal(GraphicsOptions.Default, p.GraphicsOptions); + Assert.Equal(new GraphicsOptions(), p.GraphicsOptions, graphicsOptionsComparer); Assert.Equal(Color.Black, p.GlowColor); Assert.Equal(ValueSize.Absolute(3.5f), p.Radius); } @@ -50,11 +53,11 @@ public void Glow_Rect_GlowProcessorWithDefaultValues() { var rect = new Rectangle(12, 123, 43, 65); this.operations.Glow(rect); - var p = this.Verify(rect); + GlowProcessor p = this.Verify(rect); - Assert.Equal(GraphicsOptions.Default, p.GraphicsOptions); + Assert.Equal(new GraphicsOptions(), p.GraphicsOptions, graphicsOptionsComparer); Assert.Equal(Color.Black, p.GlowColor); Assert.Equal(ValueSize.PercentageOfWidth(.5f), p.Radius); } } -} \ No newline at end of file +} diff --git a/tests/ImageSharp.Tests/Processing/Overlays/VignetteTest.cs b/tests/ImageSharp.Tests/Processing/Overlays/VignetteTest.cs index 2484cf0cb8..ebf4fee317 100644 --- a/tests/ImageSharp.Tests/Processing/Overlays/VignetteTest.cs +++ b/tests/ImageSharp.Tests/Processing/Overlays/VignetteTest.cs @@ -1,9 +1,10 @@ -// Copyright (c) Six Labors and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. using SixLabors.ImageSharp.Primitives; using SixLabors.ImageSharp.Processing; using SixLabors.ImageSharp.Processing.Processors.Overlays; +using SixLabors.ImageSharp.Tests.TestUtilities; using SixLabors.Primitives; using Xunit; @@ -11,13 +12,15 @@ namespace SixLabors.ImageSharp.Tests.Processing.Overlays { public class VignetteTest : BaseImageOperationsExtensionTest { + private static readonly GraphicsOptionsComparer graphicsOptionsComparer = new GraphicsOptionsComparer(); + [Fact] public void Vignette_VignetteProcessorWithDefaultValues() { this.operations.Vignette(); - var p = this.Verify(); + VignetteProcessor p = this.Verify(); - Assert.Equal(GraphicsOptions.Default, p.GraphicsOptions); + Assert.Equal(new GraphicsOptions(), p.GraphicsOptions, graphicsOptionsComparer); Assert.Equal(Color.Black, p.VignetteColor); Assert.Equal(ValueSize.PercentageOfWidth(.5f), p.RadiusX); Assert.Equal(ValueSize.PercentageOfHeight(.5f), p.RadiusY); @@ -27,9 +30,9 @@ public void Vignette_VignetteProcessorWithDefaultValues() public void Vignette_Color_VignetteProcessorWithDefaultValues() { this.operations.Vignette(Color.Aquamarine); - var p = this.Verify(); + VignetteProcessor p = this.Verify(); - Assert.Equal(GraphicsOptions.Default, p.GraphicsOptions); + Assert.Equal(new GraphicsOptions(), p.GraphicsOptions, graphicsOptionsComparer); Assert.Equal(Color.Aquamarine, p.VignetteColor); Assert.Equal(ValueSize.PercentageOfWidth(.5f), p.RadiusX); Assert.Equal(ValueSize.PercentageOfHeight(.5f), p.RadiusY); @@ -39,9 +42,9 @@ public void Vignette_Color_VignetteProcessorWithDefaultValues() public void Vignette_Radux_VignetteProcessorWithDefaultValues() { this.operations.Vignette(3.5f, 12123f); - var p = this.Verify(); + VignetteProcessor p = this.Verify(); - Assert.Equal(GraphicsOptions.Default, p.GraphicsOptions); + Assert.Equal(new GraphicsOptions(), p.GraphicsOptions, graphicsOptionsComparer); Assert.Equal(Color.Black, p.VignetteColor); Assert.Equal(ValueSize.Absolute(3.5f), p.RadiusX); Assert.Equal(ValueSize.Absolute(12123f), p.RadiusY); @@ -52,12 +55,12 @@ public void Vignette_Rect_VignetteProcessorWithDefaultValues() { var rect = new Rectangle(12, 123, 43, 65); this.operations.Vignette(rect); - var p = this.Verify(rect); + VignetteProcessor p = this.Verify(rect); - Assert.Equal(GraphicsOptions.Default, p.GraphicsOptions); + Assert.Equal(new GraphicsOptions(), p.GraphicsOptions, graphicsOptionsComparer); Assert.Equal(Color.Black, p.VignetteColor); Assert.Equal(ValueSize.PercentageOfWidth(.5f), p.RadiusX); Assert.Equal(ValueSize.PercentageOfHeight(.5f), p.RadiusY); } } -} \ No newline at end of file +} diff --git a/tests/ImageSharp.Tests/TestUtilities/GraphicsOptionsComparer.cs b/tests/ImageSharp.Tests/TestUtilities/GraphicsOptionsComparer.cs new file mode 100644 index 0000000000..248755ea36 --- /dev/null +++ b/tests/ImageSharp.Tests/TestUtilities/GraphicsOptionsComparer.cs @@ -0,0 +1,21 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System.Collections.Generic; + +namespace SixLabors.ImageSharp.Tests.TestUtilities +{ + public class GraphicsOptionsComparer : IEqualityComparer + { + public bool Equals(GraphicsOptions x, GraphicsOptions y) + { + return x.AlphaCompositionMode == y.AlphaCompositionMode + && x.Antialias == y.Antialias + && x.AntialiasSubpixelDepth == y.AntialiasSubpixelDepth + && x.BlendPercentage == y.BlendPercentage + && x.ColorBlendingMode == y.ColorBlendingMode; + } + + public int GetHashCode(GraphicsOptions obj) => obj.GetHashCode(); + } +} From 05bc8c8828c159f58c7c2cad5cd397926b6b1d76 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Mon, 11 Nov 2019 12:48:09 +1100 Subject: [PATCH 14/16] Normalize GraphicsOptions parameter position --- .../Processing/BrushApplicator.cs | 4 ++-- .../Processing/EllipticGradientBrush.cs | 14 +++++------ .../Extensions/FillRegionExtensions.cs | 8 +++---- .../Processing/GradientBrush.cs | 12 +++++----- src/ImageSharp.Drawing/Processing/IBrush.cs | 6 ++--- .../Processing/ImageBrush.cs | 16 ++++++------- .../Processing/LinearGradientBrush.cs | 24 +++++++++---------- .../Processing/PathGradientBrush.cs | 14 +++++------ .../Processing/PatternBrush.cs | 16 ++++++------- .../Processors/Drawing/FillProcessor.cs | 4 ++-- .../Drawing/FillProcessor{TPixel}.cs | 4 ++-- .../Processors/Drawing/FillRegionProcessor.cs | 4 ++-- .../Drawing/FillRegionProcessor{TPixel}.cs | 2 +- .../Text/DrawTextProcessor{TPixel}.cs | 2 +- .../Processing/RadialGradientBrush.cs | 16 ++++++------- .../Processing/RecolorBrush.cs | 16 ++++++------- .../Processing/SolidBrush.cs | 14 +++++------ .../Extensions/BackgroundColorExtensions.cs | 4 ++-- .../Processing/Extensions/GlowExtensions.cs | 8 +++---- .../Extensions/VignetteExtensions.cs | 8 +++---- .../Overlays/BackgroundColorProcessor.cs | 4 ++-- .../Processors/Overlays/GlowProcessor.cs | 14 +++++------ .../Processors/Overlays/VignetteProcessor.cs | 10 ++++---- .../Drawing/FillRegionProcessorTests.cs | 6 ++--- 24 files changed, 115 insertions(+), 115 deletions(-) diff --git a/src/ImageSharp.Drawing/Processing/BrushApplicator.cs b/src/ImageSharp.Drawing/Processing/BrushApplicator.cs index 2b02c14fe1..a9df07ced3 100644 --- a/src/ImageSharp.Drawing/Processing/BrushApplicator.cs +++ b/src/ImageSharp.Drawing/Processing/BrushApplicator.cs @@ -21,9 +21,9 @@ public abstract class BrushApplicator : IDisposable /// Initializes a new instance of the class. /// /// The configuration instance to use when performing operations. + /// The graphics options. /// The target. - /// The options. - internal BrushApplicator(Configuration configuration, ImageFrame target, GraphicsOptions options) + internal BrushApplicator(Configuration configuration, GraphicsOptions options, ImageFrame target) { this.Configuration = configuration; this.Target = target; diff --git a/src/ImageSharp.Drawing/Processing/EllipticGradientBrush.cs b/src/ImageSharp.Drawing/Processing/EllipticGradientBrush.cs index 7810c3c6d5..30902e4117 100644 --- a/src/ImageSharp.Drawing/Processing/EllipticGradientBrush.cs +++ b/src/ImageSharp.Drawing/Processing/EllipticGradientBrush.cs @@ -48,18 +48,18 @@ public EllipticGradientBrush( /// public override BrushApplicator CreateApplicator( Configuration configuration, + GraphicsOptions options, ImageFrame source, - RectangleF region, - GraphicsOptions options) => + RectangleF region) => new RadialGradientBrushApplicator( configuration, + options, source, this.center, this.referenceAxisEnd, this.axisRatio, this.ColorStops, - this.RepetitionMode, - options); + this.RepetitionMode); /// private sealed class RadialGradientBrushApplicator : GradientBrushApplicator @@ -100,14 +100,14 @@ private sealed class RadialGradientBrushApplicator : GradientBrushApplic /// The graphics options. public RadialGradientBrushApplicator( Configuration configuration, + GraphicsOptions options, ImageFrame target, PointF center, PointF referenceAxisEnd, float axisRatio, ColorStop[] colorStops, - GradientRepetitionMode repetitionMode, - GraphicsOptions options) - : base(configuration, target, colorStops, repetitionMode, options) + GradientRepetitionMode repetitionMode) + : base(configuration, options, target, colorStops, repetitionMode) { this.center = center; this.referenceAxisEnd = referenceAxisEnd; diff --git a/src/ImageSharp.Drawing/Processing/Extensions/FillRegionExtensions.cs b/src/ImageSharp.Drawing/Processing/Extensions/FillRegionExtensions.cs index f5dd76318c..fbb6dbda56 100644 --- a/src/ImageSharp.Drawing/Processing/Extensions/FillRegionExtensions.cs +++ b/src/ImageSharp.Drawing/Processing/Extensions/FillRegionExtensions.cs @@ -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.Primitives; @@ -77,7 +77,7 @@ public static IImageProcessingContext Fill( GraphicsOptions options, IBrush brush, Region region) => - source.ApplyProcessor(new FillRegionProcessor(brush, region, options)); + source.ApplyProcessor(new FillRegionProcessor(options, brush, region)); /// /// Flood fills the image with the specified brush. @@ -90,6 +90,6 @@ public static IImageProcessingContext Fill( this IImageProcessingContext source, GraphicsOptions options, IBrush brush) => - source.ApplyProcessor(new FillProcessor(brush, options)); + source.ApplyProcessor(new FillProcessor(options, brush)); } -} \ No newline at end of file +} diff --git a/src/ImageSharp.Drawing/Processing/GradientBrush.cs b/src/ImageSharp.Drawing/Processing/GradientBrush.cs index f17adf6335..3be56c0424 100644 --- a/src/ImageSharp.Drawing/Processing/GradientBrush.cs +++ b/src/ImageSharp.Drawing/Processing/GradientBrush.cs @@ -37,9 +37,9 @@ protected GradientBrush( /// public abstract BrushApplicator CreateApplicator( Configuration configuration, + GraphicsOptions options, ImageFrame source, - RectangleF region, - GraphicsOptions options) + RectangleF region) where TPixel : struct, IPixel; /// @@ -58,17 +58,17 @@ internal abstract class GradientBrushApplicator : BrushApplicator class. /// /// The configuration instance to use when performing operations. + /// The graphics options. /// The target image. /// An array of color stops sorted by their position. /// Defines if and how the gradient should be repeated. - /// The graphics options. protected GradientBrushApplicator( Configuration configuration, + GraphicsOptions options, ImageFrame target, ColorStop[] colorStops, - GradientRepetitionMode repetitionMode, - GraphicsOptions options) - : base(configuration, target, options) + GradientRepetitionMode repetitionMode) + : base(configuration, options, target) { this.colorStops = colorStops; // TODO: requires colorStops to be sorted by position - should that be checked? this.repetitionMode = repetitionMode; diff --git a/src/ImageSharp.Drawing/Processing/IBrush.cs b/src/ImageSharp.Drawing/Processing/IBrush.cs index f2fdc32f05..f4c7ef7cbb 100644 --- a/src/ImageSharp.Drawing/Processing/IBrush.cs +++ b/src/ImageSharp.Drawing/Processing/IBrush.cs @@ -20,9 +20,9 @@ public interface IBrush /// /// The pixel type. /// The configuration instance to use when performing operations. + /// The graphic options. /// The source image. /// The region the brush will be applied to. - /// The graphic options /// /// The for this brush. /// @@ -32,9 +32,9 @@ public interface IBrush /// BrushApplicator CreateApplicator( Configuration configuration, + GraphicsOptions options, ImageFrame source, - RectangleF region, - GraphicsOptions options) + RectangleF region) where TPixel : struct, IPixel; } } diff --git a/src/ImageSharp.Drawing/Processing/ImageBrush.cs b/src/ImageSharp.Drawing/Processing/ImageBrush.cs index f23fb1f18d..e38614070f 100644 --- a/src/ImageSharp.Drawing/Processing/ImageBrush.cs +++ b/src/ImageSharp.Drawing/Processing/ImageBrush.cs @@ -32,19 +32,19 @@ public ImageBrush(Image image) /// public BrushApplicator CreateApplicator( Configuration configuration, + GraphicsOptions options, ImageFrame source, - RectangleF region, - GraphicsOptions options) + RectangleF region) where TPixel : struct, IPixel { if (this.image is Image specificImage) { - return new ImageBrushApplicator(configuration, source, specificImage, region, false, options); + return new ImageBrushApplicator(configuration, options, source, specificImage, region, false); } specificImage = this.image.CloneAs(); - return new ImageBrushApplicator(configuration, source, specificImage, region, true, options); + return new ImageBrushApplicator(configuration, options, source, specificImage, region, true); } /// @@ -85,19 +85,19 @@ private class ImageBrushApplicator : BrushApplicator /// Initializes a new instance of the class. /// /// The configuration instance to use when performing operations. + /// The graphics options. /// The target image. /// The image. /// The region. /// Whether to dispose the image on disposal of the applicator. - /// The graphics options. public ImageBrushApplicator( Configuration configuration, + GraphicsOptions options, ImageFrame target, Image image, RectangleF region, - bool shouldDisposeImage, - GraphicsOptions options) - : base(configuration, target, options) + bool shouldDisposeImage) + : base(configuration, options, target) { this.sourceImage = image; this.sourceFrame = image.Frames.RootFrame; diff --git a/src/ImageSharp.Drawing/Processing/LinearGradientBrush.cs b/src/ImageSharp.Drawing/Processing/LinearGradientBrush.cs index bf6a6356ac..044bee72c5 100644 --- a/src/ImageSharp.Drawing/Processing/LinearGradientBrush.cs +++ b/src/ImageSharp.Drawing/Processing/LinearGradientBrush.cs @@ -40,17 +40,17 @@ public LinearGradientBrush( /// public override BrushApplicator CreateApplicator( Configuration configuration, + GraphicsOptions options, ImageFrame source, - RectangleF region, - GraphicsOptions options) => + RectangleF region) => new LinearGradientBrushApplicator( configuration, + options, source, this.p1, this.p2, this.ColorStops, - this.RepetitionMode, - options); + this.RepetitionMode); /// /// The linear gradient brush applicator. @@ -96,21 +96,21 @@ private sealed class LinearGradientBrushApplicator : GradientBrushApplic /// Initializes a new instance of the class. /// /// The configuration instance to use when performing operations. + /// The graphics options. /// The source image. - /// start point of the gradient. - /// end point of the gradient. - /// tuple list of colors and their respective position between 0 and 1 on the line. - /// defines how the gradient colors are repeated. - /// the graphics options. + /// The start point of the gradient. + /// The end point of the gradient. + /// A tuple list of colors and their respective position between 0 and 1 on the line. + /// Defines how the gradient colors are repeated. public LinearGradientBrushApplicator( Configuration configuration, + GraphicsOptions options, ImageFrame source, PointF start, PointF end, ColorStop[] colorStops, - GradientRepetitionMode repetitionMode, - GraphicsOptions options) - : base(configuration, source, colorStops, repetitionMode, options) + GradientRepetitionMode repetitionMode) + : base(configuration, options, source, colorStops, repetitionMode) { this.start = start; this.end = end; diff --git a/src/ImageSharp.Drawing/Processing/PathGradientBrush.cs b/src/ImageSharp.Drawing/Processing/PathGradientBrush.cs index be1af50118..9e354120e6 100644 --- a/src/ImageSharp.Drawing/Processing/PathGradientBrush.cs +++ b/src/ImageSharp.Drawing/Processing/PathGradientBrush.cs @@ -84,12 +84,12 @@ public PathGradientBrush(PointF[] points, Color[] colors) /// public BrushApplicator CreateApplicator( Configuration configuration, + GraphicsOptions options, ImageFrame source, - RectangleF region, - GraphicsOptions options) + RectangleF region) where TPixel : struct, IPixel { - return new PathGradientBrushApplicator(configuration, source, this.edges, this.centerColor, options); + return new PathGradientBrushApplicator(configuration, options, source, this.edges, this.centerColor); } private static Color CalculateCenterColor(Color[] colors) @@ -201,17 +201,17 @@ private class PathGradientBrushApplicator : BrushApplicator /// Initializes a new instance of the class. /// /// The configuration instance to use when performing operations. + /// The graphics options. /// The source image. /// Edges of the polygon. /// Color at the center of the gradient area to which the other colors converge. - /// The graphics options. public PathGradientBrushApplicator( Configuration configuration, + GraphicsOptions options, ImageFrame source, IList edges, - Color centerColor, - GraphicsOptions options) - : base(configuration, source, options) + Color centerColor) + : base(configuration, options, source) { this.edges = edges; diff --git a/src/ImageSharp.Drawing/Processing/PatternBrush.cs b/src/ImageSharp.Drawing/Processing/PatternBrush.cs index 9024036d02..726df5a797 100644 --- a/src/ImageSharp.Drawing/Processing/PatternBrush.cs +++ b/src/ImageSharp.Drawing/Processing/PatternBrush.cs @@ -93,15 +93,15 @@ internal PatternBrush(PatternBrush brush) /// public BrushApplicator CreateApplicator( Configuration configuration, + GraphicsOptions options, ImageFrame source, - RectangleF region, - GraphicsOptions options) + RectangleF region) where TPixel : struct, IPixel => new PatternBrushApplicator( configuration, + options, source, - this.pattern.ToPixelMatrix(configuration), - options); + this.pattern.ToPixelMatrix(configuration)); /// /// The pattern brush applicator. @@ -118,15 +118,15 @@ private class PatternBrushApplicator : BrushApplicator /// Initializes a new instance of the class. /// /// The configuration instance to use when performing operations. + /// The graphics options. /// The source image. /// The pattern. - /// The graphics options. public PatternBrushApplicator( Configuration configuration, + GraphicsOptions options, ImageFrame source, - in DenseMatrix pattern, - GraphicsOptions options) - : base(configuration, source, options) + in DenseMatrix pattern) + : base(configuration, options, source) { this.pattern = pattern; } diff --git a/src/ImageSharp.Drawing/Processing/Processors/Drawing/FillProcessor.cs b/src/ImageSharp.Drawing/Processing/Processors/Drawing/FillProcessor.cs index 1d3cf35576..3963f99a5c 100644 --- a/src/ImageSharp.Drawing/Processing/Processors/Drawing/FillProcessor.cs +++ b/src/ImageSharp.Drawing/Processing/Processors/Drawing/FillProcessor.cs @@ -15,9 +15,9 @@ public class FillProcessor : IImageProcessor /// /// Initializes a new instance of the class. /// - /// The brush to use for filling. /// The defining how to blend the brush pixels over the image pixels. - public FillProcessor(IBrush brush, GraphicsOptions options) + /// The brush to use for filling. + public FillProcessor(GraphicsOptions options, IBrush brush) { this.Brush = brush; this.Options = options; diff --git a/src/ImageSharp.Drawing/Processing/Processors/Drawing/FillProcessor{TPixel}.cs b/src/ImageSharp.Drawing/Processing/Processors/Drawing/FillProcessor{TPixel}.cs index 0309c561aa..fc94826187 100644 --- a/src/ImageSharp.Drawing/Processing/Processors/Drawing/FillProcessor{TPixel}.cs +++ b/src/ImageSharp.Drawing/Processing/Processors/Drawing/FillProcessor{TPixel}.cs @@ -85,9 +85,9 @@ protected override void OnFrameApply(ImageFrame source) using (IMemoryOwner amount = source.MemoryAllocator.Allocate(width)) using (BrushApplicator applicator = brush.CreateApplicator( configuration, + options, source, - sourceRectangle, - options)) + sourceRectangle)) { amount.Memory.Span.Fill(1f); diff --git a/src/ImageSharp.Drawing/Processing/Processors/Drawing/FillRegionProcessor.cs b/src/ImageSharp.Drawing/Processing/Processors/Drawing/FillRegionProcessor.cs index 2318f3168b..7d51be1c51 100644 --- a/src/ImageSharp.Drawing/Processing/Processors/Drawing/FillRegionProcessor.cs +++ b/src/ImageSharp.Drawing/Processing/Processors/Drawing/FillRegionProcessor.cs @@ -16,10 +16,10 @@ public class FillRegionProcessor : IImageProcessor /// /// Initializes a new instance of the class. /// + /// The graphics options. /// The details how to fill the region of interest. /// The region of interest to be filled. - /// The configuration options. - public FillRegionProcessor(IBrush brush, Region region, GraphicsOptions options) + public FillRegionProcessor(GraphicsOptions options, IBrush brush, Region region) { this.Region = region; this.Brush = brush; diff --git a/src/ImageSharp.Drawing/Processing/Processors/Drawing/FillRegionProcessor{TPixel}.cs b/src/ImageSharp.Drawing/Processing/Processors/Drawing/FillRegionProcessor{TPixel}.cs index 8c665826fe..4744a4e920 100644 --- a/src/ImageSharp.Drawing/Processing/Processors/Drawing/FillRegionProcessor{TPixel}.cs +++ b/src/ImageSharp.Drawing/Processing/Processors/Drawing/FillRegionProcessor{TPixel}.cs @@ -71,7 +71,7 @@ protected override void OnFrameApply(ImageFrame source) } } - using (BrushApplicator applicator = brush.CreateApplicator(configuration, source, rect, options)) + using (BrushApplicator applicator = brush.CreateApplicator(configuration, options, source, rect)) { int scanlineWidth = maxX - minX; using (IMemoryOwner bBuffer = source.MemoryAllocator.Allocate(maxIntersections)) diff --git a/src/ImageSharp.Drawing/Processing/Processors/Text/DrawTextProcessor{TPixel}.cs b/src/ImageSharp.Drawing/Processing/Processors/Text/DrawTextProcessor{TPixel}.cs index 244e18b81c..64d32efb80 100644 --- a/src/ImageSharp.Drawing/Processing/Processors/Text/DrawTextProcessor{TPixel}.cs +++ b/src/ImageSharp.Drawing/Processing/Processors/Text/DrawTextProcessor{TPixel}.cs @@ -83,7 +83,7 @@ void Draw(List operations, IBrush brush) { if (operations?.Count > 0) { - using (BrushApplicator app = brush.CreateApplicator(this.Configuration, source, this.SourceRectangle, this.textRenderer.Options)) + using (BrushApplicator app = brush.CreateApplicator(this.Configuration, this.textRenderer.Options, source, this.SourceRectangle)) { foreach (DrawingOperation operation in operations) { diff --git a/src/ImageSharp.Drawing/Processing/RadialGradientBrush.cs b/src/ImageSharp.Drawing/Processing/RadialGradientBrush.cs index 7f1fa818eb..2b1b6913f8 100644 --- a/src/ImageSharp.Drawing/Processing/RadialGradientBrush.cs +++ b/src/ImageSharp.Drawing/Processing/RadialGradientBrush.cs @@ -36,17 +36,17 @@ public RadialGradientBrush( /// public override BrushApplicator CreateApplicator( Configuration configuration, + GraphicsOptions options, ImageFrame source, - RectangleF region, - GraphicsOptions options) => + RectangleF region) => new RadialGradientBrushApplicator( configuration, + options, source, this.center, this.radius, this.ColorStops, - this.RepetitionMode, - options); + this.RepetitionMode); /// private sealed class RadialGradientBrushApplicator : GradientBrushApplicator @@ -60,21 +60,21 @@ private sealed class RadialGradientBrushApplicator : GradientBrushApplic /// Initializes a new instance of the class. /// /// The configuration instance to use when performing operations. + /// The graphics options. /// The target image. /// Center point of the gradient. /// Radius of the gradient. /// Definition of colors. /// How the colors are repeated beyond the first gradient. - /// The graphics options. public RadialGradientBrushApplicator( Configuration configuration, + GraphicsOptions options, ImageFrame target, PointF center, float radius, ColorStop[] colorStops, - GradientRepetitionMode repetitionMode, - GraphicsOptions options) - : base(configuration, target, colorStops, repetitionMode, options) + GradientRepetitionMode repetitionMode) + : base(configuration, options, target, colorStops, repetitionMode) { this.center = center; this.radius = radius; diff --git a/src/ImageSharp.Drawing/Processing/RecolorBrush.cs b/src/ImageSharp.Drawing/Processing/RecolorBrush.cs index 1ad613bf82..e0e43cf780 100644 --- a/src/ImageSharp.Drawing/Processing/RecolorBrush.cs +++ b/src/ImageSharp.Drawing/Processing/RecolorBrush.cs @@ -47,18 +47,18 @@ public RecolorBrush(Color sourceColor, Color targetColor, float threshold) /// public BrushApplicator CreateApplicator( Configuration configuration, + GraphicsOptions options, ImageFrame source, - RectangleF region, - GraphicsOptions options) + RectangleF region) where TPixel : struct, IPixel { return new RecolorBrushApplicator( configuration, + options, source, this.SourceColor.ToPixel(), this.TargetColor.ToPixel(), - this.Threshold, - options); + this.Threshold); } /// @@ -83,19 +83,19 @@ private class RecolorBrushApplicator : BrushApplicator /// Initializes a new instance of the class. /// /// The configuration instance to use when performing operations. + /// The options /// The source image. /// Color of the source. /// Color of the target. /// The threshold . - /// The options public RecolorBrushApplicator( Configuration configuration, + GraphicsOptions options, ImageFrame source, TPixel sourceColor, TPixel targetColor, - float threshold, - GraphicsOptions options) - : base(configuration, source, options) + float threshold) + : base(configuration, options, source) { this.sourceColor = sourceColor.ToVector4(); this.targetColorPixel = targetColor; diff --git a/src/ImageSharp.Drawing/Processing/SolidBrush.cs b/src/ImageSharp.Drawing/Processing/SolidBrush.cs index a2be775daa..c297ede211 100644 --- a/src/ImageSharp.Drawing/Processing/SolidBrush.cs +++ b/src/ImageSharp.Drawing/Processing/SolidBrush.cs @@ -33,12 +33,12 @@ public SolidBrush(Color color) /// public BrushApplicator CreateApplicator( Configuration configuration, + GraphicsOptions options, ImageFrame source, - RectangleF region, - GraphicsOptions options) + RectangleF region) where TPixel : struct, IPixel { - return new SolidBrushApplicator(configuration, source, this.Color.ToPixel(), options); + return new SolidBrushApplicator(configuration, options, source, this.Color.ToPixel()); } /// @@ -53,15 +53,15 @@ private class SolidBrushApplicator : BrushApplicator /// Initializes a new instance of the class. /// /// The configuration instance to use when performing operations. + /// The graphics options. /// The source image. /// The color. - /// The graphics options. public SolidBrushApplicator( Configuration configuration, + GraphicsOptions options, ImageFrame source, - TPixel color, - GraphicsOptions options) - : base(configuration, source, options) + TPixel color) + : base(configuration, options, source) { this.Colors = source.MemoryAllocator.Allocate(source.Width); this.Colors.Memory.Span.Fill(color); diff --git a/src/ImageSharp/Processing/Extensions/BackgroundColorExtensions.cs b/src/ImageSharp/Processing/Extensions/BackgroundColorExtensions.cs index cc2fb25120..4241721f46 100644 --- a/src/ImageSharp/Processing/Extensions/BackgroundColorExtensions.cs +++ b/src/ImageSharp/Processing/Extensions/BackgroundColorExtensions.cs @@ -47,7 +47,7 @@ public static IImageProcessingContext BackgroundColor( this IImageProcessingContext source, GraphicsOptions options, Color color) => - source.ApplyProcessor(new BackgroundColorProcessor(color, options)); + source.ApplyProcessor(new BackgroundColorProcessor(options, color)); /// /// Replaces the background color of image with the given one. @@ -64,6 +64,6 @@ public static IImageProcessingContext BackgroundColor( GraphicsOptions options, Color color, Rectangle rectangle) => - source.ApplyProcessor(new BackgroundColorProcessor(color, options), rectangle); + source.ApplyProcessor(new BackgroundColorProcessor(options, color), rectangle); } } diff --git a/src/ImageSharp/Processing/Extensions/GlowExtensions.cs b/src/ImageSharp/Processing/Extensions/GlowExtensions.cs index 90b73794ba..48ecb5108f 100644 --- a/src/ImageSharp/Processing/Extensions/GlowExtensions.cs +++ b/src/ImageSharp/Processing/Extensions/GlowExtensions.cs @@ -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.Primitives; @@ -155,7 +155,7 @@ private static IImageProcessingContext Glow( Color color, ValueSize radius, Rectangle rectangle) => - source.ApplyProcessor(new GlowProcessor(color, radius, options), rectangle); + source.ApplyProcessor(new GlowProcessor(options, color, radius), rectangle); /// /// Applies a radial glow effect to an image. @@ -170,6 +170,6 @@ private static IImageProcessingContext Glow( GraphicsOptions options, Color color, ValueSize radius) => - source.ApplyProcessor(new GlowProcessor(color, radius, options)); + source.ApplyProcessor(new GlowProcessor(options, color, radius)); } -} \ No newline at end of file +} diff --git a/src/ImageSharp/Processing/Extensions/VignetteExtensions.cs b/src/ImageSharp/Processing/Extensions/VignetteExtensions.cs index ffab8e2bf9..a1f3a6e8a0 100644 --- a/src/ImageSharp/Processing/Extensions/VignetteExtensions.cs +++ b/src/ImageSharp/Processing/Extensions/VignetteExtensions.cs @@ -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.Primitives; @@ -166,7 +166,7 @@ private static IImageProcessingContext VignetteInternal( ValueSize radiusX, ValueSize radiusY, Rectangle rectangle) => - source.ApplyProcessor(new VignetteProcessor(color, radiusX, radiusY, options), rectangle); + source.ApplyProcessor(new VignetteProcessor(options, color, radiusX, radiusY), rectangle); private static IImageProcessingContext VignetteInternal( this IImageProcessingContext source, @@ -174,6 +174,6 @@ private static IImageProcessingContext VignetteInternal( Color color, ValueSize radiusX, ValueSize radiusY) => - source.ApplyProcessor(new VignetteProcessor(color, radiusX, radiusY, options)); + source.ApplyProcessor(new VignetteProcessor(options, color, radiusX, radiusY)); } -} \ No newline at end of file +} diff --git a/src/ImageSharp/Processing/Processors/Overlays/BackgroundColorProcessor.cs b/src/ImageSharp/Processing/Processors/Overlays/BackgroundColorProcessor.cs index 4b4c537277..e78f7e5e75 100644 --- a/src/ImageSharp/Processing/Processors/Overlays/BackgroundColorProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Overlays/BackgroundColorProcessor.cs @@ -14,9 +14,9 @@ public sealed class BackgroundColorProcessor : IImageProcessor /// /// Initializes a new instance of the class. /// - /// The to set the background color to. /// The options defining blending algorithm and amount. - public BackgroundColorProcessor(Color color, GraphicsOptions options) + /// The to set the background color to. + public BackgroundColorProcessor(GraphicsOptions options, Color color) { this.Color = color; this.GraphicsOptions = options; diff --git a/src/ImageSharp/Processing/Processors/Overlays/GlowProcessor.cs b/src/ImageSharp/Processing/Processors/Overlays/GlowProcessor.cs index 1a60b79aca..4b9a23eff1 100644 --- a/src/ImageSharp/Processing/Processors/Overlays/GlowProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Overlays/GlowProcessor.cs @@ -24,10 +24,10 @@ public GlowProcessor(Color color) /// /// Initializes a new instance of the class. /// - /// The color or the glow. /// The options effecting blending and composition. - public GlowProcessor(Color color, GraphicsOptions options) - : this(color, 0, options) + /// The color or the glow. + public GlowProcessor(GraphicsOptions options, Color color) + : this(options, color, 0) { } @@ -37,17 +37,17 @@ public GlowProcessor(Color color, GraphicsOptions options) /// The color or the glow. /// The radius of the glow. internal GlowProcessor(Color color, ValueSize radius) - : this(color, radius, new GraphicsOptions()) + : this(new GraphicsOptions(), color, radius) { } /// /// Initializes a new instance of the class. /// + /// The options effecting blending and composition. /// The color or the glow. /// The radius of the glow. - /// The options effecting blending and composition. - internal GlowProcessor(Color color, ValueSize radius, GraphicsOptions options) + internal GlowProcessor(GraphicsOptions options, Color color, ValueSize radius) { this.GlowColor = color; this.Radius = radius; @@ -67,7 +67,7 @@ internal GlowProcessor(Color color, ValueSize radius, GraphicsOptions options) /// /// Gets the the radius. /// - internal ValueSize Radius { get; } + internal ValueSize Radius { get; } /// public IImageProcessor CreatePixelSpecificProcessor(Image source, Rectangle sourceRectangle) diff --git a/src/ImageSharp/Processing/Processors/Overlays/VignetteProcessor.cs b/src/ImageSharp/Processing/Processors/Overlays/VignetteProcessor.cs index e1c836ff56..3cf48e5a40 100644 --- a/src/ImageSharp/Processing/Processors/Overlays/VignetteProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Overlays/VignetteProcessor.cs @@ -17,16 +17,16 @@ public sealed class VignetteProcessor : IImageProcessor /// /// The color of the vignette. public VignetteProcessor(Color color) - : this(color, new GraphicsOptions()) + : this(new GraphicsOptions(), color) { } /// /// Initializes a new instance of the class. /// - /// The color of the vignette. /// The options effecting blending and composition. - public VignetteProcessor(Color color, GraphicsOptions options) + /// The color of the vignette. + public VignetteProcessor(GraphicsOptions options, Color color) { this.VignetteColor = color; this.GraphicsOptions = options; @@ -35,11 +35,11 @@ public VignetteProcessor(Color color, GraphicsOptions options) /// /// Initializes a new instance of the class. /// + /// The options effecting blending and composition. /// The color of the vignette. /// The x-radius. /// The y-radius. - /// The options effecting blending and composition. - internal VignetteProcessor(Color color, ValueSize radiusX, ValueSize radiusY, GraphicsOptions options) + internal VignetteProcessor(GraphicsOptions options, Color color, ValueSize radiusX, ValueSize radiusY) { this.VignetteColor = color; this.RadiusX = radiusX; diff --git a/tests/ImageSharp.Tests/Drawing/FillRegionProcessorTests.cs b/tests/ImageSharp.Tests/Drawing/FillRegionProcessorTests.cs index 6230d52a17..e259d29d9c 100644 --- a/tests/ImageSharp.Tests/Drawing/FillRegionProcessorTests.cs +++ b/tests/ImageSharp.Tests/Drawing/FillRegionProcessorTests.cs @@ -38,7 +38,7 @@ public void MinimumAntialiasSubpixelDepth(bool antialias, int antialiasSubpixelD Antialias = antialias, AntialiasSubpixelDepth = 1 }; - var processor = new FillRegionProcessor(brush.Object, region, options); + var processor = new FillRegionProcessor(options, brush.Object, region); var img = new Image(1, 1); processor.Execute(img, bounds); @@ -51,7 +51,7 @@ public void FillOffCanvas() var bounds = new Rectangle(-100, -10, 10, 10); var brush = new Mock(); var options = new GraphicsOptions { Antialias = true }; - var processor = new FillRegionProcessor(brush.Object, new MockRegion1(), options); + var processor = new FillRegionProcessor(options, brush.Object, new MockRegion1()); var img = new Image(10, 10); processor.Execute(img, bounds); } @@ -72,7 +72,7 @@ public void DrawOffCanvas() public void DoesNotThrowForIssue928() { var rectText = new RectangleF(0, 0, 2000, 2000); - using (Image img = new Image((int)rectText.Width, (int)rectText.Height)) + using (var img = new Image((int)rectText.Width, (int)rectText.Height)) { img.Mutate(x => x.Fill(Rgba32.Transparent)); From 50e5cdc94e83fa1552ece62cc5cb0d597e1a9bee Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Mon, 11 Nov 2019 12:50:55 +1100 Subject: [PATCH 15/16] Remove unused properties. --- src/ImageSharp.Drawing/Processing/TextGraphicsOptions.cs | 5 ----- src/ImageSharp/GraphicsOptions.cs | 5 ----- 2 files changed, 10 deletions(-) diff --git a/src/ImageSharp.Drawing/Processing/TextGraphicsOptions.cs b/src/ImageSharp.Drawing/Processing/TextGraphicsOptions.cs index 185fa1f74c..63730d1bf7 100644 --- a/src/ImageSharp.Drawing/Processing/TextGraphicsOptions.cs +++ b/src/ImageSharp.Drawing/Processing/TextGraphicsOptions.cs @@ -40,11 +40,6 @@ private TextGraphicsOptions(TextGraphicsOptions source) this.VerticalAlignment = source.VerticalAlignment; } - /// - /// Gets the default instance. - /// - public static TextGraphicsOptions Default { get; } = new TextGraphicsOptions(); - /// /// Gets or sets a value indicating whether antialiasing should be applied. /// Defaults to true. diff --git a/src/ImageSharp/GraphicsOptions.cs b/src/ImageSharp/GraphicsOptions.cs index 9c62d23371..47b930e654 100644 --- a/src/ImageSharp/GraphicsOptions.cs +++ b/src/ImageSharp/GraphicsOptions.cs @@ -29,11 +29,6 @@ private GraphicsOptions(GraphicsOptions source) this.ColorBlendingMode = source.ColorBlendingMode; } - /// - /// Gets the default instance. - /// - public static GraphicsOptions Default { get; } = new GraphicsOptions(); - /// /// Gets or sets a value indicating whether antialiasing should be applied. /// Defaults to true. From 1f28f0c41f7d30e0257c721654a627f4d7b1ae08 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Mon, 11 Nov 2019 13:02:13 +1100 Subject: [PATCH 16/16] Prevent duplicate ctr in extensions --- .../Processing/EllipticGradientBrush.cs | 2 +- .../Extensions/DrawImageExtensions.cs | 36 +++++++++++-------- 2 files changed, 22 insertions(+), 16 deletions(-) diff --git a/src/ImageSharp.Drawing/Processing/EllipticGradientBrush.cs b/src/ImageSharp.Drawing/Processing/EllipticGradientBrush.cs index 30902e4117..fbab3605d2 100644 --- a/src/ImageSharp.Drawing/Processing/EllipticGradientBrush.cs +++ b/src/ImageSharp.Drawing/Processing/EllipticGradientBrush.cs @@ -89,6 +89,7 @@ private sealed class RadialGradientBrushApplicator : GradientBrushApplic /// Initializes a new instance of the class. /// /// The configuration instance to use when performing operations. + /// The graphics options. /// The target image. /// Center of the ellipse. /// Point on one angular points of the ellipse. @@ -97,7 +98,6 @@ private sealed class RadialGradientBrushApplicator : GradientBrushApplic /// the first is defined by and . /// Definition of colors. /// Defines how the gradient colors are repeated. - /// The graphics options. public RadialGradientBrushApplicator( Configuration configuration, GraphicsOptions options, diff --git a/src/ImageSharp.Drawing/Processing/Extensions/DrawImageExtensions.cs b/src/ImageSharp.Drawing/Processing/Extensions/DrawImageExtensions.cs index 6c694ab73b..6c79984378 100644 --- a/src/ImageSharp.Drawing/Processing/Extensions/DrawImageExtensions.cs +++ b/src/ImageSharp.Drawing/Processing/Extensions/DrawImageExtensions.cs @@ -22,14 +22,17 @@ public static class DrawImageExtensions public static IImageProcessingContext DrawImage( this IImageProcessingContext source, Image image, - float opacity) => - source.ApplyProcessor( + float opacity) + { + var options = new GraphicsOptions(); + return source.ApplyProcessor( new DrawImageProcessor( - image, - Point.Empty, - new GraphicsOptions().ColorBlendingMode, - new GraphicsOptions().AlphaCompositionMode, - opacity)); + image, + Point.Empty, + options.ColorBlendingMode, + options.AlphaCompositionMode, + opacity)); + } /// /// Draws the given image together with the current one by blending their pixels. @@ -100,14 +103,17 @@ public static IImageProcessingContext DrawImage( this IImageProcessingContext source, Image image, Point location, - float opacity) => - source.ApplyProcessor( + float opacity) + { + var options = new GraphicsOptions(); + return source.ApplyProcessor( new DrawImageProcessor( - image, - location, - new GraphicsOptions().ColorBlendingMode, - new GraphicsOptions().AlphaCompositionMode, - opacity)); + image, + location, + options.ColorBlendingMode, + options.AlphaCompositionMode, + opacity)); + } /// /// Draws the given image together with the current one by blending their pixels. @@ -172,4 +178,4 @@ public static IImageProcessingContext DrawImage( options.AlphaCompositionMode, options.BlendPercentage)); } -} \ No newline at end of file +}