diff --git a/src/ImageSharp/Advanced/IRowIntervalOperation.cs b/src/ImageSharp/Advanced/IRowIntervalOperation.cs
new file mode 100644
index 0000000000..3e1b086218
--- /dev/null
+++ b/src/ImageSharp/Advanced/IRowIntervalOperation.cs
@@ -0,0 +1,21 @@
+// Copyright (c) Six Labors and contributors.
+// Licensed under the Apache License, Version 2.0.
+
+using System;
+using System.Runtime.CompilerServices;
+using SixLabors.ImageSharp.Memory;
+
+namespace SixLabors.ImageSharp.Advanced
+{
+ ///
+ /// Defines the contract for an action that operates on a row interval.
+ ///
+ public interface IRowIntervalOperation
+ {
+ ///
+ /// Invokes the method passing the row interval.
+ ///
+ /// The row interval.
+ void Invoke(in RowInterval rows);
+ }
+}
diff --git a/src/ImageSharp/Advanced/IRowIntervalOperation{TBuffer}.cs b/src/ImageSharp/Advanced/IRowIntervalOperation{TBuffer}.cs
new file mode 100644
index 0000000000..c18842a92c
--- /dev/null
+++ b/src/ImageSharp/Advanced/IRowIntervalOperation{TBuffer}.cs
@@ -0,0 +1,25 @@
+// Copyright (c) Six Labors and contributors.
+// Licensed under the Apache License, Version 2.0.
+
+using System;
+using System.Buffers;
+using System.Runtime.CompilerServices;
+using SixLabors.ImageSharp.Memory;
+
+namespace SixLabors.ImageSharp.Advanced
+{
+ ///
+ /// Defines the contract for an action that operates on a row interval with a temporary buffer.
+ ///
+ /// The type of buffer elements.
+ public interface IRowIntervalOperation
+ where TBuffer : unmanaged
+ {
+ ///
+ /// Invokes the method passing the row interval and a buffer.
+ ///
+ /// The row interval.
+ /// The contiguous region of memory.
+ void Invoke(in RowInterval rows, Span span);
+ }
+}
diff --git a/src/ImageSharp/Advanced/ParallelUtils/ParallelExecutionSettings.cs b/src/ImageSharp/Advanced/ParallelExecutionSettings.cs
similarity index 95%
rename from src/ImageSharp/Advanced/ParallelUtils/ParallelExecutionSettings.cs
rename to src/ImageSharp/Advanced/ParallelExecutionSettings.cs
index f17d70a2a0..54ee069184 100644
--- a/src/ImageSharp/Advanced/ParallelUtils/ParallelExecutionSettings.cs
+++ b/src/ImageSharp/Advanced/ParallelExecutionSettings.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;
@@ -6,10 +6,10 @@ using System.Threading.Tasks;
using SixLabors.ImageSharp.Memory;
-namespace SixLabors.ImageSharp.Advanced.ParallelUtils
+namespace SixLabors.ImageSharp.Advanced
{
///
- /// Defines execution settings for methods in .
+ /// Defines execution settings for methods in .
///
public readonly struct ParallelExecutionSettings
{
@@ -89,7 +89,7 @@ namespace SixLabors.ImageSharp.Advanced.ParallelUtils
}
///
- /// Get the default for a
+ /// Get the default for a
///
/// The .
/// The .
diff --git a/src/ImageSharp/Advanced/ParallelRowIterator.Wrappers.cs b/src/ImageSharp/Advanced/ParallelRowIterator.Wrappers.cs
new file mode 100644
index 0000000000..adbad0d662
--- /dev/null
+++ b/src/ImageSharp/Advanced/ParallelRowIterator.Wrappers.cs
@@ -0,0 +1,110 @@
+// Copyright (c) Six Labors and contributors.
+// Licensed under the Apache License, Version 2.0.
+
+using System;
+using System.Buffers;
+using System.Runtime.CompilerServices;
+using System.Threading.Tasks;
+using SixLabors.ImageSharp.Memory;
+
+namespace SixLabors.ImageSharp.Advanced
+{
+ ///
+ /// Utility methods for batched processing of pixel row intervals.
+ /// Parallel execution is optimized for image processing based on values defined
+ /// or .
+ /// Using this class is preferred over direct usage of utility methods.
+ ///
+ public static partial class ParallelRowIterator
+ {
+ private readonly struct IterationParameters
+ {
+ public readonly int MinY;
+ public readonly int MaxY;
+ public readonly int StepY;
+ public readonly int Width;
+
+ public IterationParameters(int minY, int maxY, int stepY)
+ : this(minY, maxY, stepY, 0)
+ {
+ }
+
+ public IterationParameters(int minY, int maxY, int stepY, int width)
+ {
+ this.MinY = minY;
+ this.MaxY = maxY;
+ this.StepY = stepY;
+ this.Width = width;
+ }
+ }
+
+ private readonly struct RowIntervalOperationWrapper
+ where T : struct, IRowIntervalOperation
+ {
+ private readonly IterationParameters info;
+ private readonly T operation;
+
+ [MethodImpl(InliningOptions.ShortMethod)]
+ public RowIntervalOperationWrapper(in IterationParameters info, in T operation)
+ {
+ this.info = info;
+ this.operation = operation;
+ }
+
+ [MethodImpl(InliningOptions.ShortMethod)]
+ public void Invoke(int i)
+ {
+ int yMin = this.info.MinY + (i * this.info.StepY);
+
+ if (yMin >= this.info.MaxY)
+ {
+ return;
+ }
+
+ int yMax = Math.Min(yMin + this.info.StepY, this.info.MaxY);
+ var rows = new RowInterval(yMin, yMax);
+
+ // Skip the safety copy when invoking a potentially impure method on a readonly field
+ Unsafe.AsRef(in this.operation).Invoke(in rows);
+ }
+ }
+
+ private readonly struct RowIntervalOperationWrapper
+ where T : struct, IRowIntervalOperation
+ where TBuffer : unmanaged
+ {
+ private readonly IterationParameters info;
+ private readonly MemoryAllocator allocator;
+ private readonly T operation;
+
+ [MethodImpl(InliningOptions.ShortMethod)]
+ public RowIntervalOperationWrapper(
+ in IterationParameters info,
+ MemoryAllocator allocator,
+ in T operation)
+ {
+ this.info = info;
+ this.allocator = allocator;
+ this.operation = operation;
+ }
+
+ [MethodImpl(InliningOptions.ShortMethod)]
+ public void Invoke(int i)
+ {
+ int yMin = this.info.MinY + (i * this.info.StepY);
+
+ if (yMin >= this.info.MaxY)
+ {
+ return;
+ }
+
+ int yMax = Math.Min(yMin + this.info.StepY, this.info.MaxY);
+ var rows = new RowInterval(yMin, yMax);
+
+ using IMemoryOwner buffer = this.allocator.Allocate(this.info.Width);
+
+ Unsafe.AsRef(in this.operation).Invoke(in rows, buffer.Memory.Span);
+ }
+ }
+ }
+}
diff --git a/src/ImageSharp/Advanced/ParallelRowIterator.cs b/src/ImageSharp/Advanced/ParallelRowIterator.cs
new file mode 100644
index 0000000000..123784c57f
--- /dev/null
+++ b/src/ImageSharp/Advanced/ParallelRowIterator.cs
@@ -0,0 +1,162 @@
+// Copyright (c) Six Labors and contributors.
+// Licensed under the Apache License, Version 2.0.
+
+using System;
+using System.Buffers;
+using System.Runtime.CompilerServices;
+using System.Threading.Tasks;
+using SixLabors.ImageSharp.Memory;
+
+namespace SixLabors.ImageSharp.Advanced
+{
+ ///
+ /// Utility methods for batched processing of pixel row intervals.
+ /// Parallel execution is optimized for image processing based on values defined
+ /// or .
+ /// Using this class is preferred over direct usage of utility methods.
+ ///
+ public static partial class ParallelRowIterator
+ {
+ ///
+ /// Iterate through the rows of a rectangle in optimized batches defined by -s.
+ ///
+ /// The type of row operation to perform.
+ /// The to get the parallel settings from.
+ /// The .
+ /// The operation defining the iteration logic on a single .
+ [MethodImpl(InliningOptions.ShortMethod)]
+ public static void IterateRows(Configuration configuration, Rectangle rectangle, in T operation)
+ where T : struct, IRowIntervalOperation
+ {
+ var parallelSettings = ParallelExecutionSettings.FromConfiguration(configuration);
+ IterateRows(rectangle, in parallelSettings, in operation);
+ }
+
+ ///
+ /// Iterate through the rows of a rectangle in optimized batches defined by -s.
+ ///
+ /// The type of row operation to perform.
+ /// The .
+ /// The .
+ /// The operation defining the iteration logic on a single .
+ public static void IterateRows(
+ Rectangle rectangle,
+ in ParallelExecutionSettings parallelSettings,
+ in T operation)
+ where T : struct, IRowIntervalOperation
+ {
+ ValidateRectangle(rectangle);
+
+ int top = rectangle.Top;
+ int bottom = rectangle.Bottom;
+ int width = rectangle.Width;
+ int height = rectangle.Height;
+
+ int maxSteps = DivideCeil(width * height, parallelSettings.MinimumPixelsProcessedPerTask);
+ int numOfSteps = Math.Min(parallelSettings.MaxDegreeOfParallelism, maxSteps);
+
+ // Avoid TPL overhead in this trivial case:
+ if (numOfSteps == 1)
+ {
+ var rows = new RowInterval(top, bottom);
+ Unsafe.AsRef(in operation).Invoke(in rows);
+ return;
+ }
+
+ int verticalStep = DivideCeil(rectangle.Height, numOfSteps);
+ var parallelOptions = new ParallelOptions { MaxDegreeOfParallelism = numOfSteps };
+ var info = new IterationParameters(top, bottom, verticalStep);
+ var wrappingOperation = new RowIntervalOperationWrapper(in info, in operation);
+
+ Parallel.For(
+ 0,
+ numOfSteps,
+ parallelOptions,
+ wrappingOperation.Invoke);
+ }
+
+ ///
+ /// Iterate through the rows of a rectangle in optimized batches defined by -s
+ /// instantiating a temporary buffer for each invocation.
+ ///
+ /// The type of row operation to perform.
+ /// The type of buffer elements.
+ /// The to get the parallel settings from.
+ /// The .
+ /// The operation defining the iteration logic on a single .
+ public static void IterateRows(Configuration configuration, Rectangle rectangle, in T operation)
+ where T : struct, IRowIntervalOperation
+ where TBuffer : unmanaged
+ {
+ var parallelSettings = ParallelExecutionSettings.FromConfiguration(configuration);
+ IterateRows(rectangle, in parallelSettings, in operation);
+ }
+
+ ///
+ /// Iterate through the rows of a rectangle in optimized batches defined by -s
+ /// instantiating a temporary buffer for each invocation.
+ ///
+ /// The type of row operation to perform.
+ /// The type of buffer elements.
+ /// The .
+ /// The .
+ /// The operation defining the iteration logic on a single .
+ public static void IterateRows(
+ Rectangle rectangle,
+ in ParallelExecutionSettings parallelSettings,
+ in T operation)
+ where T : struct, IRowIntervalOperation
+ where TBuffer : unmanaged
+ {
+ ValidateRectangle(rectangle);
+
+ int top = rectangle.Top;
+ int bottom = rectangle.Bottom;
+ int width = rectangle.Width;
+ int height = rectangle.Height;
+
+ int maxSteps = DivideCeil(width * height, parallelSettings.MinimumPixelsProcessedPerTask);
+ int numOfSteps = Math.Min(parallelSettings.MaxDegreeOfParallelism, maxSteps);
+ MemoryAllocator allocator = parallelSettings.MemoryAllocator;
+
+ // Avoid TPL overhead in this trivial case:
+ if (numOfSteps == 1)
+ {
+ var rows = new RowInterval(top, bottom);
+ using (IMemoryOwner buffer = allocator.Allocate(width))
+ {
+ Unsafe.AsRef(operation).Invoke(in rows, buffer.Memory.Span);
+ }
+
+ return;
+ }
+
+ int verticalStep = DivideCeil(height, numOfSteps);
+ var parallelOptions = new ParallelOptions { MaxDegreeOfParallelism = numOfSteps };
+ var info = new IterationParameters(top, bottom, verticalStep, width);
+ var wrappingOperation = new RowIntervalOperationWrapper(in info, allocator, in operation);
+
+ Parallel.For(
+ 0,
+ numOfSteps,
+ parallelOptions,
+ wrappingOperation.Invoke);
+ }
+
+ [MethodImpl(InliningOptions.ShortMethod)]
+ private static int DivideCeil(int dividend, int divisor) => 1 + ((dividend - 1) / divisor);
+
+ private static void ValidateRectangle(Rectangle rectangle)
+ {
+ Guard.MustBeGreaterThan(
+ rectangle.Width,
+ 0,
+ $"{nameof(rectangle)}.{nameof(rectangle.Width)}");
+
+ Guard.MustBeGreaterThan(
+ rectangle.Height,
+ 0,
+ $"{nameof(rectangle)}.{nameof(rectangle.Height)}");
+ }
+ }
+}
diff --git a/src/ImageSharp/Advanced/ParallelUtils/ParallelHelper.cs b/src/ImageSharp/Advanced/ParallelUtils/ParallelHelper.cs
deleted file mode 100644
index ecefadb08d..0000000000
--- a/src/ImageSharp/Advanced/ParallelUtils/ParallelHelper.cs
+++ /dev/null
@@ -1,160 +0,0 @@
-// Copyright (c) Six Labors and contributors.
-// Licensed under the Apache License, Version 2.0.
-
-using System;
-using System.Buffers;
-using System.Runtime.CompilerServices;
-using System.Threading.Tasks;
-
-using SixLabors.ImageSharp.Memory;
-
-namespace SixLabors.ImageSharp.Advanced.ParallelUtils
-{
- ///
- /// Utility methods for batched processing of pixel row intervals.
- /// Parallel execution is optimized for image processing based on values defined
- /// or .
- /// Using this class is preferred over direct usage of utility methods.
- ///
- public static class ParallelHelper
- {
- ///
- /// Iterate through the rows of a rectangle in optimized batches defined by -s.
- ///
- /// The .
- /// The to get the parallel settings from.
- /// The method body defining the iteration logic on a single .
- public static void IterateRows(Rectangle rectangle, Configuration configuration, Action body)
- {
- var parallelSettings = ParallelExecutionSettings.FromConfiguration(configuration);
-
- IterateRows(rectangle, parallelSettings, body);
- }
-
- ///
- /// Iterate through the rows of a rectangle in optimized batches defined by -s.
- ///
- /// The .
- /// The .
- /// The method body defining the iteration logic on a single .
- public static void IterateRows(
- Rectangle rectangle,
- in ParallelExecutionSettings parallelSettings,
- Action body)
- {
- ValidateRectangle(rectangle);
-
- int maxSteps = DivideCeil(
- rectangle.Width * rectangle.Height,
- parallelSettings.MinimumPixelsProcessedPerTask);
-
- int numOfSteps = Math.Min(parallelSettings.MaxDegreeOfParallelism, maxSteps);
-
- // Avoid TPL overhead in this trivial case:
- if (numOfSteps == 1)
- {
- var rows = new RowInterval(rectangle.Top, rectangle.Bottom);
- body(rows);
- return;
- }
-
- int verticalStep = DivideCeil(rectangle.Height, numOfSteps);
-
- var parallelOptions = new ParallelOptions { MaxDegreeOfParallelism = numOfSteps };
-
- Parallel.For(
- 0,
- numOfSteps,
- parallelOptions,
- i =>
- {
- int yMin = rectangle.Top + (i * verticalStep);
- int yMax = Math.Min(yMin + verticalStep, rectangle.Bottom);
-
- var rows = new RowInterval(yMin, yMax);
- body(rows);
- });
- }
-
- ///
- /// Iterate through the rows of a rectangle in optimized batches defined by -s
- /// instantiating a temporary buffer for each invocation.
- ///
- internal static void IterateRowsWithTempBuffer(
- Rectangle rectangle,
- in ParallelExecutionSettings parallelSettings,
- Action> body)
- where T : unmanaged
- {
- ValidateRectangle(rectangle);
-
- int maxSteps = DivideCeil(rectangle.Width * rectangle.Height, parallelSettings.MinimumPixelsProcessedPerTask);
-
- int numOfSteps = Math.Min(parallelSettings.MaxDegreeOfParallelism, maxSteps);
-
- MemoryAllocator memoryAllocator = parallelSettings.MemoryAllocator;
-
- // Avoid TPL overhead in this trivial case:
- if (numOfSteps == 1)
- {
- var rows = new RowInterval(rectangle.Top, rectangle.Bottom);
- using (IMemoryOwner buffer = memoryAllocator.Allocate(rectangle.Width))
- {
- body(rows, buffer.Memory);
- }
-
- return;
- }
-
- int verticalStep = DivideCeil(rectangle.Height, numOfSteps);
-
- var parallelOptions = new ParallelOptions { MaxDegreeOfParallelism = numOfSteps };
-
- Parallel.For(
- 0,
- numOfSteps,
- parallelOptions,
- i =>
- {
- int yMin = rectangle.Top + (i * verticalStep);
- int yMax = Math.Min(yMin + verticalStep, rectangle.Bottom);
-
- var rows = new RowInterval(yMin, yMax);
-
- using (IMemoryOwner buffer = memoryAllocator.Allocate(rectangle.Width))
- {
- body(rows, buffer.Memory);
- }
- });
- }
-
- ///
- /// Iterate through the rows of a rectangle in optimized batches defined by -s
- /// instantiating a temporary buffer for each invocation.
- ///
- internal static void IterateRowsWithTempBuffer(
- Rectangle rectangle,
- Configuration configuration,
- Action> body)
- where T : unmanaged
- {
- IterateRowsWithTempBuffer(rectangle, ParallelExecutionSettings.FromConfiguration(configuration), body);
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- private static int DivideCeil(int dividend, int divisor) => 1 + ((dividend - 1) / divisor);
-
- private static void ValidateRectangle(Rectangle rectangle)
- {
- Guard.MustBeGreaterThan(
- rectangle.Width,
- 0,
- $"{nameof(rectangle)}.{nameof(rectangle.Width)}");
-
- Guard.MustBeGreaterThan(
- rectangle.Height,
- 0,
- $"{nameof(rectangle)}.{nameof(rectangle.Height)}");
- }
- }
-}
diff --git a/src/ImageSharp/Color/Color.NamedColors.cs b/src/ImageSharp/Color/Color.NamedColors.cs
index 0575a3e99e..8eb3fbcaf7 100644
--- a/src/ImageSharp/Color/Color.NamedColors.cs
+++ b/src/ImageSharp/Color/Color.NamedColors.cs
@@ -1,6 +1,9 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
+using System;
+using System.Collections.Generic;
+
namespace SixLabors.ImageSharp
{
///
@@ -8,6 +11,8 @@ namespace SixLabors.ImageSharp
///
public readonly partial struct Color
{
+ private static readonly Lazy> NamedColorsLookupLazy = new Lazy>(CreateNamedColorsLookup, true);
+
///
/// Represents a matching the W3C definition that has an hex value of #F0F8FF.
///
@@ -111,7 +116,7 @@ namespace SixLabors.ImageSharp
///
/// Represents a matching the W3C definition that has an hex value of #00FFFF.
///
- public static readonly Color Cyan = FromRgba(0, 255, 255, 255);
+ public static readonly Color Cyan = Aqua;
///
/// Represents a matching the W3C definition that has an hex value of #00008B.
@@ -138,6 +143,11 @@ namespace SixLabors.ImageSharp
///
public static readonly Color DarkGreen = FromRgba(0, 100, 0, 255);
+ ///
+ /// Represents a matching the W3C definition that has an hex value of #A9A9A9.
+ ///
+ public static readonly Color DarkGrey = DarkGray;
+
///
/// Represents a matching the W3C definition that has an hex value of #BDB76B.
///
@@ -188,6 +198,11 @@ namespace SixLabors.ImageSharp
///
public static readonly Color DarkSlateGray = FromRgba(47, 79, 79, 255);
+ ///
+ /// Represents a matching the W3C definition that has an hex value of #2F4F4F.
+ ///
+ public static readonly Color DarkSlateGrey = DarkSlateGray;
+
///
/// Represents a matching the W3C definition that has an hex value of #00CED1.
///
@@ -213,6 +228,11 @@ namespace SixLabors.ImageSharp
///
public static readonly Color DimGray = FromRgba(105, 105, 105, 255);
+ ///
+ /// Represents a matching the W3C definition that has an hex value of #696969.
+ ///
+ public static readonly Color DimGrey = DimGray;
+
///
/// Represents a matching the W3C definition that has an hex value of #1E90FF.
///
@@ -273,6 +293,11 @@ namespace SixLabors.ImageSharp
///
public static readonly Color GreenYellow = FromRgba(173, 255, 47, 255);
+ ///
+ /// Represents a matching the W3C definition that has an hex value of #808080.
+ ///
+ public static readonly Color Grey = Gray;
+
///
/// Represents a matching the W3C definition that has an hex value of #F0FFF0.
///
@@ -353,6 +378,11 @@ namespace SixLabors.ImageSharp
///
public static readonly Color LightGreen = FromRgba(144, 238, 144, 255);
+ ///
+ /// Represents a matching the W3C definition that has an hex value of #D3D3D3.
+ ///
+ public static readonly Color LightGrey = LightGray;
+
///
/// Represents a matching the W3C definition that has an hex value of #FFB6C1.
///
@@ -378,6 +408,11 @@ namespace SixLabors.ImageSharp
///
public static readonly Color LightSlateGray = FromRgba(119, 136, 153, 255);
+ ///
+ /// Represents a matching the W3C definition that has an hex value of #778899.
+ ///
+ public static readonly Color LightSlateGrey = LightSlateGray;
+
///
/// Represents a matching the W3C definition that has an hex value of #B0C4DE.
///
@@ -406,7 +441,7 @@ namespace SixLabors.ImageSharp
///
/// Represents a matching the W3C definition that has an hex value of #FF00FF.
///
- public static readonly Color Magenta = FromRgba(255, 0, 255, 255);
+ public static readonly Color Magenta = Fuchsia;
///
/// Represents a matching the W3C definition that has an hex value of #800000.
@@ -643,6 +678,11 @@ namespace SixLabors.ImageSharp
///
public static readonly Color SlateGray = FromRgba(112, 128, 144, 255);
+ ///
+ /// Represents a matching the W3C definition that has an hex value of #708090.
+ ///
+ public static readonly Color SlateGrey = SlateGray;
+
///
/// Represents a matching the W3C definition that has an hex value of #FFFAFA.
///
@@ -717,5 +757,161 @@ namespace SixLabors.ImageSharp
/// Represents a matching the W3C definition that has an hex value of #9ACD32.
///
public static readonly Color YellowGreen = FromRgba(154, 205, 50, 255);
+
+ private static Dictionary CreateNamedColorsLookup()
+ {
+ return new Dictionary(StringComparer.OrdinalIgnoreCase)
+ {
+ { nameof(AliceBlue), AliceBlue },
+ { nameof(AntiqueWhite), AntiqueWhite },
+ { nameof(Aqua), Aqua },
+ { nameof(Aquamarine), Aquamarine },
+ { nameof(Azure), Azure },
+ { nameof(Beige), Beige },
+ { nameof(Bisque), Bisque },
+ { nameof(Black), Black },
+ { nameof(BlanchedAlmond), BlanchedAlmond },
+ { nameof(Blue), Blue },
+ { nameof(BlueViolet), BlueViolet },
+ { nameof(Brown), Brown },
+ { nameof(BurlyWood), BurlyWood },
+ { nameof(CadetBlue), CadetBlue },
+ { nameof(Chartreuse), Chartreuse },
+ { nameof(Chocolate), Chocolate },
+ { nameof(Coral), Coral },
+ { nameof(CornflowerBlue), CornflowerBlue },
+ { nameof(Cornsilk), Cornsilk },
+ { nameof(Crimson), Crimson },
+ { nameof(Cyan), Cyan },
+ { nameof(DarkBlue), DarkBlue },
+ { nameof(DarkCyan), DarkCyan },
+ { nameof(DarkGoldenrod), DarkGoldenrod },
+ { nameof(DarkGray), DarkGray },
+ { nameof(DarkGreen), DarkGreen },
+ { nameof(DarkGrey), DarkGrey },
+ { nameof(DarkKhaki), DarkKhaki },
+ { nameof(DarkMagenta), DarkMagenta },
+ { nameof(DarkOliveGreen), DarkOliveGreen },
+ { nameof(DarkOrange), DarkOrange },
+ { nameof(DarkOrchid), DarkOrchid },
+ { nameof(DarkRed), DarkRed },
+ { nameof(DarkSalmon), DarkSalmon },
+ { nameof(DarkSeaGreen), DarkSeaGreen },
+ { nameof(DarkSlateBlue), DarkSlateBlue },
+ { nameof(DarkSlateGray), DarkSlateGray },
+ { nameof(DarkSlateGrey), DarkSlateGrey },
+ { nameof(DarkTurquoise), DarkTurquoise },
+ { nameof(DarkViolet), DarkViolet },
+ { nameof(DeepPink), DeepPink },
+ { nameof(DeepSkyBlue), DeepSkyBlue },
+ { nameof(DimGray), DimGray },
+ { nameof(DimGrey), DimGrey },
+ { nameof(DodgerBlue), DodgerBlue },
+ { nameof(Firebrick), Firebrick },
+ { nameof(FloralWhite), FloralWhite },
+ { nameof(ForestGreen), ForestGreen },
+ { nameof(Fuchsia), Fuchsia },
+ { nameof(Gainsboro), Gainsboro },
+ { nameof(GhostWhite), GhostWhite },
+ { nameof(Gold), Gold },
+ { nameof(Goldenrod), Goldenrod },
+ { nameof(Gray), Gray },
+ { nameof(Green), Green },
+ { nameof(GreenYellow), GreenYellow },
+ { nameof(Grey), Grey },
+ { nameof(Honeydew), Honeydew },
+ { nameof(HotPink), HotPink },
+ { nameof(IndianRed), IndianRed },
+ { nameof(Indigo), Indigo },
+ { nameof(Ivory), Ivory },
+ { nameof(Khaki), Khaki },
+ { nameof(Lavender), Lavender },
+ { nameof(LavenderBlush), LavenderBlush },
+ { nameof(LawnGreen), LawnGreen },
+ { nameof(LemonChiffon), LemonChiffon },
+ { nameof(LightBlue), LightBlue },
+ { nameof(LightCoral), LightCoral },
+ { nameof(LightCyan), LightCyan },
+ { nameof(LightGoldenrodYellow), LightGoldenrodYellow },
+ { nameof(LightGray), LightGray },
+ { nameof(LightGreen), LightGreen },
+ { nameof(LightGrey), LightGrey },
+ { nameof(LightPink), LightPink },
+ { nameof(LightSalmon), LightSalmon },
+ { nameof(LightSeaGreen), LightSeaGreen },
+ { nameof(LightSkyBlue), LightSkyBlue },
+ { nameof(LightSlateGray), LightSlateGray },
+ { nameof(LightSlateGrey), LightSlateGrey },
+ { nameof(LightSteelBlue), LightSteelBlue },
+ { nameof(LightYellow), LightYellow },
+ { nameof(Lime), Lime },
+ { nameof(LimeGreen), LimeGreen },
+ { nameof(Linen), Linen },
+ { nameof(Magenta), Magenta },
+ { nameof(Maroon), Maroon },
+ { nameof(MediumAquamarine), MediumAquamarine },
+ { nameof(MediumBlue), MediumBlue },
+ { nameof(MediumOrchid), MediumOrchid },
+ { nameof(MediumPurple), MediumPurple },
+ { nameof(MediumSeaGreen), MediumSeaGreen },
+ { nameof(MediumSlateBlue), MediumSlateBlue },
+ { nameof(MediumSpringGreen), MediumSpringGreen },
+ { nameof(MediumTurquoise), MediumTurquoise },
+ { nameof(MediumVioletRed), MediumVioletRed },
+ { nameof(MidnightBlue), MidnightBlue },
+ { nameof(MintCream), MintCream },
+ { nameof(MistyRose), MistyRose },
+ { nameof(Moccasin), Moccasin },
+ { nameof(NavajoWhite), NavajoWhite },
+ { nameof(Navy), Navy },
+ { nameof(OldLace), OldLace },
+ { nameof(Olive), Olive },
+ { nameof(OliveDrab), OliveDrab },
+ { nameof(Orange), Orange },
+ { nameof(OrangeRed), OrangeRed },
+ { nameof(Orchid), Orchid },
+ { nameof(PaleGoldenrod), PaleGoldenrod },
+ { nameof(PaleGreen), PaleGreen },
+ { nameof(PaleTurquoise), PaleTurquoise },
+ { nameof(PaleVioletRed), PaleVioletRed },
+ { nameof(PapayaWhip), PapayaWhip },
+ { nameof(PeachPuff), PeachPuff },
+ { nameof(Peru), Peru },
+ { nameof(Pink), Pink },
+ { nameof(Plum), Plum },
+ { nameof(PowderBlue), PowderBlue },
+ { nameof(Purple), Purple },
+ { nameof(RebeccaPurple), RebeccaPurple },
+ { nameof(Red), Red },
+ { nameof(RosyBrown), RosyBrown },
+ { nameof(RoyalBlue), RoyalBlue },
+ { nameof(SaddleBrown), SaddleBrown },
+ { nameof(Salmon), Salmon },
+ { nameof(SandyBrown), SandyBrown },
+ { nameof(SeaGreen), SeaGreen },
+ { nameof(SeaShell), SeaShell },
+ { nameof(Sienna), Sienna },
+ { nameof(Silver), Silver },
+ { nameof(SkyBlue), SkyBlue },
+ { nameof(SlateBlue), SlateBlue },
+ { nameof(SlateGray), SlateGray },
+ { nameof(SlateGrey), SlateGrey },
+ { nameof(Snow), Snow },
+ { nameof(SpringGreen), SpringGreen },
+ { nameof(SteelBlue), SteelBlue },
+ { nameof(Tan), Tan },
+ { nameof(Teal), Teal },
+ { nameof(Thistle), Thistle },
+ { nameof(Tomato), Tomato },
+ { nameof(Transparent), Transparent },
+ { nameof(Turquoise), Turquoise },
+ { nameof(Violet), Violet },
+ { nameof(Wheat), Wheat },
+ { nameof(White), White },
+ { nameof(WhiteSmoke), WhiteSmoke },
+ { nameof(Yellow), Yellow },
+ { nameof(YellowGreen), YellowGreen }
+ };
+ }
}
}
diff --git a/src/ImageSharp/Color/Color.WernerPalette.cs b/src/ImageSharp/Color/Color.WernerPalette.cs
index 768fe065cd..2948b4c52c 100644
--- a/src/ImageSharp/Color/Color.WernerPalette.cs
+++ b/src/ImageSharp/Color/Color.WernerPalette.cs
@@ -20,116 +20,116 @@ namespace SixLabors.ImageSharp
private static Color[] CreateWernerPalette() => new[]
{
- FromHex("#f1e9cd"),
- FromHex("#f2e7cf"),
- FromHex("#ece6d0"),
- FromHex("#f2eacc"),
- FromHex("#f3e9ca"),
- FromHex("#f2ebcd"),
- FromHex("#e6e1c9"),
- FromHex("#e2ddc6"),
- FromHex("#cbc8b7"),
- FromHex("#bfbbb0"),
- FromHex("#bebeb3"),
- FromHex("#b7b5ac"),
- FromHex("#bab191"),
- FromHex("#9c9d9a"),
- FromHex("#8a8d84"),
- FromHex("#5b5c61"),
- FromHex("#555152"),
- FromHex("#413f44"),
- FromHex("#454445"),
- FromHex("#423937"),
- FromHex("#433635"),
- FromHex("#252024"),
- FromHex("#241f20"),
- FromHex("#281f3f"),
- FromHex("#1c1949"),
- FromHex("#4f638d"),
- FromHex("#383867"),
- FromHex("#5c6b8f"),
- FromHex("#657abb"),
- FromHex("#6f88af"),
- FromHex("#7994b5"),
- FromHex("#6fb5a8"),
- FromHex("#719ba2"),
- FromHex("#8aa1a6"),
- FromHex("#d0d5d3"),
- FromHex("#8590ae"),
- FromHex("#3a2f52"),
- FromHex("#39334a"),
- FromHex("#6c6d94"),
- FromHex("#584c77"),
- FromHex("#533552"),
- FromHex("#463759"),
- FromHex("#bfbac0"),
- FromHex("#77747f"),
- FromHex("#4a475c"),
- FromHex("#b8bfaf"),
- FromHex("#b2b599"),
- FromHex("#979c84"),
- FromHex("#5d6161"),
- FromHex("#61ac86"),
- FromHex("#a4b6a7"),
- FromHex("#adba98"),
- FromHex("#93b778"),
- FromHex("#7d8c55"),
- FromHex("#33431e"),
- FromHex("#7c8635"),
- FromHex("#8e9849"),
- FromHex("#c2c190"),
- FromHex("#67765b"),
- FromHex("#ab924b"),
- FromHex("#c8c76f"),
- FromHex("#ccc050"),
- FromHex("#ebdd99"),
- FromHex("#ab9649"),
- FromHex("#dbc364"),
- FromHex("#e6d058"),
- FromHex("#ead665"),
- FromHex("#d09b2c"),
- FromHex("#a36629"),
- FromHex("#a77d35"),
- FromHex("#f0d696"),
- FromHex("#d7c485"),
- FromHex("#f1d28c"),
- FromHex("#efcc83"),
- FromHex("#f3daa7"),
- FromHex("#dfa837"),
- FromHex("#ebbc71"),
- FromHex("#d17c3f"),
- FromHex("#92462f"),
- FromHex("#be7249"),
- FromHex("#bb603c"),
- FromHex("#c76b4a"),
- FromHex("#a75536"),
- FromHex("#b63e36"),
- FromHex("#b5493a"),
- FromHex("#cd6d57"),
- FromHex("#711518"),
- FromHex("#e9c49d"),
- FromHex("#eedac3"),
- FromHex("#eecfbf"),
- FromHex("#ce536b"),
- FromHex("#b74a70"),
- FromHex("#b7757c"),
- FromHex("#612741"),
- FromHex("#7a4848"),
- FromHex("#3f3033"),
- FromHex("#8d746f"),
- FromHex("#4d3635"),
- FromHex("#6e3b31"),
- FromHex("#864735"),
- FromHex("#553d3a"),
- FromHex("#613936"),
- FromHex("#7a4b3a"),
- FromHex("#946943"),
- FromHex("#c39e6d"),
- FromHex("#513e32"),
- FromHex("#8b7859"),
- FromHex("#9b856b"),
- FromHex("#766051"),
- FromHex("#453b32")
+ ParseHex("#f1e9cd"),
+ ParseHex("#f2e7cf"),
+ ParseHex("#ece6d0"),
+ ParseHex("#f2eacc"),
+ ParseHex("#f3e9ca"),
+ ParseHex("#f2ebcd"),
+ ParseHex("#e6e1c9"),
+ ParseHex("#e2ddc6"),
+ ParseHex("#cbc8b7"),
+ ParseHex("#bfbbb0"),
+ ParseHex("#bebeb3"),
+ ParseHex("#b7b5ac"),
+ ParseHex("#bab191"),
+ ParseHex("#9c9d9a"),
+ ParseHex("#8a8d84"),
+ ParseHex("#5b5c61"),
+ ParseHex("#555152"),
+ ParseHex("#413f44"),
+ ParseHex("#454445"),
+ ParseHex("#423937"),
+ ParseHex("#433635"),
+ ParseHex("#252024"),
+ ParseHex("#241f20"),
+ ParseHex("#281f3f"),
+ ParseHex("#1c1949"),
+ ParseHex("#4f638d"),
+ ParseHex("#383867"),
+ ParseHex("#5c6b8f"),
+ ParseHex("#657abb"),
+ ParseHex("#6f88af"),
+ ParseHex("#7994b5"),
+ ParseHex("#6fb5a8"),
+ ParseHex("#719ba2"),
+ ParseHex("#8aa1a6"),
+ ParseHex("#d0d5d3"),
+ ParseHex("#8590ae"),
+ ParseHex("#3a2f52"),
+ ParseHex("#39334a"),
+ ParseHex("#6c6d94"),
+ ParseHex("#584c77"),
+ ParseHex("#533552"),
+ ParseHex("#463759"),
+ ParseHex("#bfbac0"),
+ ParseHex("#77747f"),
+ ParseHex("#4a475c"),
+ ParseHex("#b8bfaf"),
+ ParseHex("#b2b599"),
+ ParseHex("#979c84"),
+ ParseHex("#5d6161"),
+ ParseHex("#61ac86"),
+ ParseHex("#a4b6a7"),
+ ParseHex("#adba98"),
+ ParseHex("#93b778"),
+ ParseHex("#7d8c55"),
+ ParseHex("#33431e"),
+ ParseHex("#7c8635"),
+ ParseHex("#8e9849"),
+ ParseHex("#c2c190"),
+ ParseHex("#67765b"),
+ ParseHex("#ab924b"),
+ ParseHex("#c8c76f"),
+ ParseHex("#ccc050"),
+ ParseHex("#ebdd99"),
+ ParseHex("#ab9649"),
+ ParseHex("#dbc364"),
+ ParseHex("#e6d058"),
+ ParseHex("#ead665"),
+ ParseHex("#d09b2c"),
+ ParseHex("#a36629"),
+ ParseHex("#a77d35"),
+ ParseHex("#f0d696"),
+ ParseHex("#d7c485"),
+ ParseHex("#f1d28c"),
+ ParseHex("#efcc83"),
+ ParseHex("#f3daa7"),
+ ParseHex("#dfa837"),
+ ParseHex("#ebbc71"),
+ ParseHex("#d17c3f"),
+ ParseHex("#92462f"),
+ ParseHex("#be7249"),
+ ParseHex("#bb603c"),
+ ParseHex("#c76b4a"),
+ ParseHex("#a75536"),
+ ParseHex("#b63e36"),
+ ParseHex("#b5493a"),
+ ParseHex("#cd6d57"),
+ ParseHex("#711518"),
+ ParseHex("#e9c49d"),
+ ParseHex("#eedac3"),
+ ParseHex("#eecfbf"),
+ ParseHex("#ce536b"),
+ ParseHex("#b74a70"),
+ ParseHex("#b7757c"),
+ ParseHex("#612741"),
+ ParseHex("#7a4848"),
+ ParseHex("#3f3033"),
+ ParseHex("#8d746f"),
+ ParseHex("#4d3635"),
+ ParseHex("#6e3b31"),
+ ParseHex("#864735"),
+ ParseHex("#553d3a"),
+ ParseHex("#613936"),
+ ParseHex("#7a4b3a"),
+ ParseHex("#946943"),
+ ParseHex("#c39e6d"),
+ ParseHex("#513e32"),
+ ParseHex("#8b7859"),
+ ParseHex("#9b856b"),
+ ParseHex("#766051"),
+ ParseHex("#453b32")
};
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/Color/Color.cs b/src/ImageSharp/Color/Color.cs
index 5fad7a8e39..fcf091638e 100644
--- a/src/ImageSharp/Color/Color.cs
+++ b/src/ImageSharp/Color/Color.cs
@@ -95,21 +95,102 @@ namespace SixLabors.ImageSharp
public static Color FromRgb(byte r, byte g, byte b) => new Color(r, g, b);
///
- /// Creates a new instance from the string representing a color in hexadecimal form.
+ /// Creates a new instance of the struct
+ /// from the given hexadecimal string.
///
///
/// The hexadecimal representation of the combined color components arranged
/// in rgb, rgba, rrggbb, or rrggbbaa format to match web syntax.
///
- /// Returns a that represents the color defined by the provided RGBA hex string.
+ ///
+ /// The .
+ ///
[MethodImpl(InliningOptions.ShortMethod)]
- public static Color FromHex(string hex)
+ public static Color ParseHex(string hex)
{
- var rgba = Rgba32.FromHex(hex);
+ var rgba = Rgba32.ParseHex(hex);
return new Color(rgba);
}
+ ///
+ /// Attempts to creates a new instance of the struct
+ /// from the given hexadecimal string.
+ ///
+ ///
+ /// The hexadecimal representation of the combined color components arranged
+ /// in rgb, rgba, rrggbb, or rrggbbaa format to match web syntax.
+ ///
+ /// When this method returns, contains the equivalent of the hexadecimal input.
+ ///
+ /// The .
+ ///
+ [MethodImpl(InliningOptions.ShortMethod)]
+ public static bool TryParseHex(string hex, out Color result)
+ {
+ result = default;
+
+ if (Rgba32.TryParseHex(hex, out Rgba32 rgba))
+ {
+ result = new Color(rgba);
+ return true;
+ }
+
+ return false;
+ }
+
+ ///
+ /// Creates a new instance of the struct
+ /// from the given input string.
+ ///
+ ///
+ /// The name of the color or the hexadecimal representation of the combined color components arranged
+ /// in rgb, rgba, rrggbb, or rrggbbaa format to match web syntax.
+ ///
+ ///
+ /// The .
+ ///
+ public static Color Parse(string input)
+ {
+ Guard.NotNull(input, nameof(input));
+
+ if (!TryParse(input, out Color color))
+ {
+ throw new ArgumentException("Input string is not in the correct format.", nameof(input));
+ }
+
+ return color;
+ }
+
+ ///
+ /// Attempts to creates a new instance of the struct
+ /// from the given input string.
+ ///
+ ///
+ /// The name of the color or the hexadecimal representation of the combined color components arranged
+ /// in rgb, rgba, rrggbb, or rrggbbaa format to match web syntax.
+ ///
+ /// When this method returns, contains the equivalent of the hexadecimal input.
+ ///
+ /// The .
+ ///
+ public static bool TryParse(string input, out Color result)
+ {
+ result = default;
+
+ if (string.IsNullOrWhiteSpace(input))
+ {
+ return false;
+ }
+
+ if (NamedColorsLookupLazy.Value.TryGetValue(input, out result))
+ {
+ return true;
+ }
+
+ return TryParseHex(input, out result);
+ }
+
///
/// Alters the alpha channel of the color, returning a new instance.
///
@@ -117,7 +198,7 @@ namespace SixLabors.ImageSharp
/// The color having it's alpha channel altered.
public Color WithAlpha(float alpha)
{
- Vector4 v = (Vector4)this;
+ var v = (Vector4)this;
v.W = alpha;
return new Color(v);
}
diff --git a/src/ImageSharp/Common/Extensions/EnumerableExtensions.cs b/src/ImageSharp/Common/Extensions/EnumerableExtensions.cs
index cff6e3b601..983a1eb8b3 100644
--- a/src/ImageSharp/Common/Extensions/EnumerableExtensions.cs
+++ b/src/ImageSharp/Common/Extensions/EnumerableExtensions.cs
@@ -1,10 +1,10 @@
-// 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;
-namespace SixLabors.ImageSharp.Common
+namespace SixLabors.ImageSharp
{
///
/// Encapsulates a series of time saving extension methods to the interface.
@@ -34,15 +34,11 @@ namespace SixLabors.ImageSharp.Common
///
/// Generates a sequence of integral numbers within a specified range.
///
- ///
- /// The start index, inclusive.
- ///
+ /// The start index, inclusive.
///
/// A method that has one parameter and returns a calculating the end index.
///
- ///
- /// The incremental step.
- ///
+ /// The incremental step.
///
/// The that contains a range of sequential integral numbers.
///
@@ -56,4 +52,4 @@ namespace SixLabors.ImageSharp.Common
}
}
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/ImageFrame{TPixel}.cs b/src/ImageSharp/ImageFrame{TPixel}.cs
index bc45a45fdc..0d76810848 100644
--- a/src/ImageSharp/ImageFrame{TPixel}.cs
+++ b/src/ImageSharp/ImageFrame{TPixel}.cs
@@ -4,9 +4,7 @@
using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
-
using SixLabors.ImageSharp.Advanced;
-using SixLabors.ImageSharp.Advanced.ParallelUtils;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.Metadata;
using SixLabors.ImageSharp.PixelFormats;
@@ -261,19 +259,12 @@ namespace SixLabors.ImageSharp
}
var target = new ImageFrame(configuration, this.Width, this.Height, this.Metadata.DeepClone());
+ var operation = new RowIntervalOperation(this, target, configuration);
- ParallelHelper.IterateRows(
- this.Bounds(),
+ ParallelRowIterator.IterateRows(
configuration,
- rows =>
- {
- for (int y = rows.Min; y < rows.Max; y++)
- {
- Span sourceRow = this.GetPixelRowSpan(y);
- Span targetRow = target.GetPixelRowSpan(y);
- PixelOperations.Instance.To(configuration, sourceRow, targetRow);
- }
- });
+ this.Bounds(),
+ in operation);
return target;
}
@@ -295,5 +286,39 @@ namespace SixLabors.ImageSharp
group.Fill(value);
}
}
+
+ ///
+ /// A implementing the clone logic for .
+ ///
+ private readonly struct RowIntervalOperation : IRowIntervalOperation
+ where TPixel2 : struct, IPixel
+ {
+ private readonly ImageFrame source;
+ private readonly ImageFrame target;
+ private readonly Configuration configuration;
+
+ [MethodImpl(InliningOptions.ShortMethod)]
+ public RowIntervalOperation(
+ ImageFrame source,
+ ImageFrame target,
+ Configuration configuration)
+ {
+ this.source = source;
+ this.target = target;
+ this.configuration = configuration;
+ }
+
+ ///
+ [MethodImpl(InliningOptions.ShortMethod)]
+ public void Invoke(in RowInterval rows)
+ {
+ for (int y = rows.Min; y < rows.Max; y++)
+ {
+ Span sourceRow = this.source.GetPixelRowSpan(y);
+ Span targetRow = this.target.GetPixelRowSpan(y);
+ PixelOperations.Instance.To(this.configuration, sourceRow, targetRow);
+ }
+ }
+ }
}
}
diff --git a/src/ImageSharp/PixelFormats/ColorConstants.cs b/src/ImageSharp/PixelFormats/ColorConstants.cs
deleted file mode 100644
index 14df385697..0000000000
--- a/src/ImageSharp/PixelFormats/ColorConstants.cs
+++ /dev/null
@@ -1,278 +0,0 @@
-// Copyright (c) Six Labors and contributors.
-// Licensed under the Apache License, Version 2.0.
-
-namespace SixLabors.ImageSharp.PixelFormats
-{
- ///
- /// Provides useful color definitions.
- ///
- public static class ColorConstants
- {
- ///
- /// Gets a collection of named, web safe, colors as defined in the CSS Color Module Level 4.
- ///
- public static readonly Rgba32[] WebSafeColors =
- {
- Rgba32.AliceBlue,
- Rgba32.AntiqueWhite,
- Rgba32.Aqua,
- Rgba32.Aquamarine,
- Rgba32.Azure,
- Rgba32.Beige,
- Rgba32.Bisque,
- Rgba32.Black,
- Rgba32.BlanchedAlmond,
- Rgba32.Blue,
- Rgba32.BlueViolet,
- Rgba32.Brown,
- Rgba32.BurlyWood,
- Rgba32.CadetBlue,
- Rgba32.Chartreuse,
- Rgba32.Chocolate,
- Rgba32.Coral,
- Rgba32.CornflowerBlue,
- Rgba32.Cornsilk,
- Rgba32.Crimson,
- Rgba32.Cyan,
- Rgba32.DarkBlue,
- Rgba32.DarkCyan,
- Rgba32.DarkGoldenrod,
- Rgba32.DarkGray,
- Rgba32.DarkGreen,
- Rgba32.DarkKhaki,
- Rgba32.DarkMagenta,
- Rgba32.DarkOliveGreen,
- Rgba32.DarkOrange,
- Rgba32.DarkOrchid,
- Rgba32.DarkRed,
- Rgba32.DarkSalmon,
- Rgba32.DarkSeaGreen,
- Rgba32.DarkSlateBlue,
- Rgba32.DarkSlateGray,
- Rgba32.DarkTurquoise,
- Rgba32.DarkViolet,
- Rgba32.DeepPink,
- Rgba32.DeepSkyBlue,
- Rgba32.DimGray,
- Rgba32.DodgerBlue,
- Rgba32.Firebrick,
- Rgba32.FloralWhite,
- Rgba32.ForestGreen,
- Rgba32.Fuchsia,
- Rgba32.Gainsboro,
- Rgba32.GhostWhite,
- Rgba32.Gold,
- Rgba32.Goldenrod,
- Rgba32.Gray,
- Rgba32.Green,
- Rgba32.GreenYellow,
- Rgba32.Honeydew,
- Rgba32.HotPink,
- Rgba32.IndianRed,
- Rgba32.Indigo,
- Rgba32.Ivory,
- Rgba32.Khaki,
- Rgba32.Lavender,
- Rgba32.LavenderBlush,
- Rgba32.LawnGreen,
- Rgba32.LemonChiffon,
- Rgba32.LightBlue,
- Rgba32.LightCoral,
- Rgba32.LightCyan,
- Rgba32.LightGoldenrodYellow,
- Rgba32.LightGray,
- Rgba32.LightGreen,
- Rgba32.LightPink,
- Rgba32.LightSalmon,
- Rgba32.LightSeaGreen,
- Rgba32.LightSkyBlue,
- Rgba32.LightSlateGray,
- Rgba32.LightSteelBlue,
- Rgba32.LightYellow,
- Rgba32.Lime,
- Rgba32.LimeGreen,
- Rgba32.Linen,
- Rgba32.Magenta,
- Rgba32.Maroon,
- Rgba32.MediumAquamarine,
- Rgba32.MediumBlue,
- Rgba32.MediumOrchid,
- Rgba32.MediumPurple,
- Rgba32.MediumSeaGreen,
- Rgba32.MediumSlateBlue,
- Rgba32.MediumSpringGreen,
- Rgba32.MediumTurquoise,
- Rgba32.MediumVioletRed,
- Rgba32.MidnightBlue,
- Rgba32.MintCream,
- Rgba32.MistyRose,
- Rgba32.Moccasin,
- Rgba32.NavajoWhite,
- Rgba32.Navy,
- Rgba32.OldLace,
- Rgba32.Olive,
- Rgba32.OliveDrab,
- Rgba32.Orange,
- Rgba32.OrangeRed,
- Rgba32.Orchid,
- Rgba32.PaleGoldenrod,
- Rgba32.PaleGreen,
- Rgba32.PaleTurquoise,
- Rgba32.PaleVioletRed,
- Rgba32.PapayaWhip,
- Rgba32.PeachPuff,
- Rgba32.Peru,
- Rgba32.Pink,
- Rgba32.Plum,
- Rgba32.PowderBlue,
- Rgba32.Purple,
- Rgba32.RebeccaPurple,
- Rgba32.Red,
- Rgba32.RosyBrown,
- Rgba32.RoyalBlue,
- Rgba32.SaddleBrown,
- Rgba32.Salmon,
- Rgba32.SandyBrown,
- Rgba32.SeaGreen,
- Rgba32.SeaShell,
- Rgba32.Sienna,
- Rgba32.Silver,
- Rgba32.SkyBlue,
- Rgba32.SlateBlue,
- Rgba32.SlateGray,
- Rgba32.Snow,
- Rgba32.SpringGreen,
- Rgba32.SteelBlue,
- Rgba32.Tan,
- Rgba32.Teal,
- Rgba32.Thistle,
- Rgba32.Tomato,
- Rgba32.Transparent,
- Rgba32.Turquoise,
- Rgba32.Violet,
- Rgba32.Wheat,
- Rgba32.White,
- Rgba32.WhiteSmoke,
- Rgba32.Yellow,
- Rgba32.YellowGreen
- };
-
- ///
- /// Gets a collection of colors as defined in the original second edition of Werner’s Nomenclature of Colours 1821.
- /// The hex codes were collected and defined by Nicholas Rougeux
- ///
- public static readonly Rgba32[] WernerColors =
- {
- Rgba32.FromHex("#f1e9cd"),
- Rgba32.FromHex("#f2e7cf"),
- Rgba32.FromHex("#ece6d0"),
- Rgba32.FromHex("#f2eacc"),
- Rgba32.FromHex("#f3e9ca"),
- Rgba32.FromHex("#f2ebcd"),
- Rgba32.FromHex("#e6e1c9"),
- Rgba32.FromHex("#e2ddc6"),
- Rgba32.FromHex("#cbc8b7"),
- Rgba32.FromHex("#bfbbb0"),
- Rgba32.FromHex("#bebeb3"),
- Rgba32.FromHex("#b7b5ac"),
- Rgba32.FromHex("#bab191"),
- Rgba32.FromHex("#9c9d9a"),
- Rgba32.FromHex("#8a8d84"),
- Rgba32.FromHex("#5b5c61"),
- Rgba32.FromHex("#555152"),
- Rgba32.FromHex("#413f44"),
- Rgba32.FromHex("#454445"),
- Rgba32.FromHex("#423937"),
- Rgba32.FromHex("#433635"),
- Rgba32.FromHex("#252024"),
- Rgba32.FromHex("#241f20"),
- Rgba32.FromHex("#281f3f"),
- Rgba32.FromHex("#1c1949"),
- Rgba32.FromHex("#4f638d"),
- Rgba32.FromHex("#383867"),
- Rgba32.FromHex("#5c6b8f"),
- Rgba32.FromHex("#657abb"),
- Rgba32.FromHex("#6f88af"),
- Rgba32.FromHex("#7994b5"),
- Rgba32.FromHex("#6fb5a8"),
- Rgba32.FromHex("#719ba2"),
- Rgba32.FromHex("#8aa1a6"),
- Rgba32.FromHex("#d0d5d3"),
- Rgba32.FromHex("#8590ae"),
- Rgba32.FromHex("#3a2f52"),
- Rgba32.FromHex("#39334a"),
- Rgba32.FromHex("#6c6d94"),
- Rgba32.FromHex("#584c77"),
- Rgba32.FromHex("#533552"),
- Rgba32.FromHex("#463759"),
- Rgba32.FromHex("#bfbac0"),
- Rgba32.FromHex("#77747f"),
- Rgba32.FromHex("#4a475c"),
- Rgba32.FromHex("#b8bfaf"),
- Rgba32.FromHex("#b2b599"),
- Rgba32.FromHex("#979c84"),
- Rgba32.FromHex("#5d6161"),
- Rgba32.FromHex("#61ac86"),
- Rgba32.FromHex("#a4b6a7"),
- Rgba32.FromHex("#adba98"),
- Rgba32.FromHex("#93b778"),
- Rgba32.FromHex("#7d8c55"),
- Rgba32.FromHex("#33431e"),
- Rgba32.FromHex("#7c8635"),
- Rgba32.FromHex("#8e9849"),
- Rgba32.FromHex("#c2c190"),
- Rgba32.FromHex("#67765b"),
- Rgba32.FromHex("#ab924b"),
- Rgba32.FromHex("#c8c76f"),
- Rgba32.FromHex("#ccc050"),
- Rgba32.FromHex("#ebdd99"),
- Rgba32.FromHex("#ab9649"),
- Rgba32.FromHex("#dbc364"),
- Rgba32.FromHex("#e6d058"),
- Rgba32.FromHex("#ead665"),
- Rgba32.FromHex("#d09b2c"),
- Rgba32.FromHex("#a36629"),
- Rgba32.FromHex("#a77d35"),
- Rgba32.FromHex("#f0d696"),
- Rgba32.FromHex("#d7c485"),
- Rgba32.FromHex("#f1d28c"),
- Rgba32.FromHex("#efcc83"),
- Rgba32.FromHex("#f3daa7"),
- Rgba32.FromHex("#dfa837"),
- Rgba32.FromHex("#ebbc71"),
- Rgba32.FromHex("#d17c3f"),
- Rgba32.FromHex("#92462f"),
- Rgba32.FromHex("#be7249"),
- Rgba32.FromHex("#bb603c"),
- Rgba32.FromHex("#c76b4a"),
- Rgba32.FromHex("#a75536"),
- Rgba32.FromHex("#b63e36"),
- Rgba32.FromHex("#b5493a"),
- Rgba32.FromHex("#cd6d57"),
- Rgba32.FromHex("#711518"),
- Rgba32.FromHex("#e9c49d"),
- Rgba32.FromHex("#eedac3"),
- Rgba32.FromHex("#eecfbf"),
- Rgba32.FromHex("#ce536b"),
- Rgba32.FromHex("#b74a70"),
- Rgba32.FromHex("#b7757c"),
- Rgba32.FromHex("#612741"),
- Rgba32.FromHex("#7a4848"),
- Rgba32.FromHex("#3f3033"),
- Rgba32.FromHex("#8d746f"),
- Rgba32.FromHex("#4d3635"),
- Rgba32.FromHex("#6e3b31"),
- Rgba32.FromHex("#864735"),
- Rgba32.FromHex("#553d3a"),
- Rgba32.FromHex("#613936"),
- Rgba32.FromHex("#7a4b3a"),
- Rgba32.FromHex("#946943"),
- Rgba32.FromHex("#c39e6d"),
- Rgba32.FromHex("#513e32"),
- Rgba32.FromHex("#8b7859"),
- Rgba32.FromHex("#9b856b"),
- Rgba32.FromHex("#766051"),
- Rgba32.FromHex("#453b32")
- };
- }
-}
\ No newline at end of file
diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.Definitions.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.Definitions.cs
deleted file mode 100644
index f9cc3256cd..0000000000
--- a/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.Definitions.cs
+++ /dev/null
@@ -1,721 +0,0 @@
-// Copyright (c) Six Labors and contributors.
-// Licensed under the Apache License, Version 2.0.
-
-namespace SixLabors.ImageSharp.PixelFormats
-{
- ///
- /// Provides standardized definitions for named colors.
- ///
- public partial struct Rgba32
- {
- ///
- /// Represents a matching the W3C definition that has an hex value of #F0F8FF.
- ///
- public static readonly Rgba32 AliceBlue = Color.AliceBlue;
-
- ///
- /// Represents a matching the W3C definition that has an hex value of #FAEBD7.
- ///
- public static readonly Rgba32 AntiqueWhite = Color.AntiqueWhite;
-
- ///
- /// Represents a matching the W3C definition that has an hex value of #00FFFF.
- ///
- public static readonly Rgba32 Aqua = Color.Aqua;
-
- ///
- /// Represents a matching the W3C definition that has an hex value of #7FFFD4.
- ///
- public static readonly Rgba32 Aquamarine = Color.Aquamarine;
-
- ///
- /// Represents a matching the W3C definition that has an hex value of #F0FFFF.
- ///
- public static readonly Rgba32 Azure = Color.Azure;
-
- ///
- /// Represents a matching the W3C definition that has an hex value of #F5F5DC.
- ///
- public static readonly Rgba32 Beige = Color.Beige;
-
- ///
- /// Represents a matching the W3C definition that has an hex value of #FFE4C4.
- ///
- public static readonly Rgba32 Bisque = Color.Bisque;
-
- ///
- /// Represents a matching the W3C definition that has an hex value of #000000.
- ///
- public static readonly Rgba32 Black = Color.Black;
-
- ///
- /// Represents a matching the W3C definition that has an hex value of #FFEBCD.
- ///
- public static readonly Rgba32 BlanchedAlmond = Color.BlanchedAlmond;
-
- ///
- /// Represents a matching the W3C definition that has an hex value of #0000FF.
- ///
- public static readonly Rgba32 Blue = Color.Blue;
-
- ///
- /// Represents a matching the W3C definition that has an hex value of #8A2BE2.
- ///
- public static readonly Rgba32 BlueViolet = Color.BlueViolet;
-
- ///
- /// Represents a matching the W3C definition that has an hex value of #A52A2A.
- ///
- public static readonly Rgba32 Brown = Color.Brown;
-
- ///
- /// Represents a matching the W3C definition that has an hex value of #DEB887.
- ///
- public static readonly Rgba32 BurlyWood = Color.BurlyWood;
-
- ///
- /// Represents a matching the W3C definition that has an hex value of #5F9EA0.
- ///
- public static readonly Rgba32 CadetBlue = Color.CadetBlue;
-
- ///
- /// Represents a matching the W3C definition that has an hex value of #7FFF00.
- ///
- public static readonly Rgba32 Chartreuse = Color.Chartreuse;
-
- ///
- /// Represents a matching the W3C definition that has an hex value of #D2691E.
- ///
- public static readonly Rgba32 Chocolate = Color.Chocolate;
-
- ///
- /// Represents a matching the W3C definition that has an hex value of #FF7F50.
- ///
- public static readonly Rgba32 Coral = Color.Coral;
-
- ///
- /// Represents a matching the W3C definition that has an hex value of #6495ED.
- ///
- public static readonly Rgba32 CornflowerBlue = Color.CornflowerBlue;
-
- ///
- /// Represents a matching the W3C definition that has an hex value of #FFF8DC.
- ///
- public static readonly Rgba32 Cornsilk = Color.Cornsilk;
-
- ///
- /// Represents a matching the W3C definition that has an hex value of #DC143C.
- ///
- public static readonly Rgba32 Crimson = Color.Crimson;
-
- ///
- /// Represents a matching the W3C definition that has an hex value of #00FFFF.
- ///
- public static readonly Rgba32 Cyan = Color.Cyan;
-
- ///
- /// Represents a matching the W3C definition that has an hex value of #00008B.
- ///
- public static readonly Rgba32 DarkBlue = Color.DarkBlue;
-
- ///
- /// Represents a matching the W3C definition that has an hex value of #008B8B.
- ///
- public static readonly Rgba32 DarkCyan = Color.DarkCyan;
-
- ///
- /// Represents a matching the W3C definition that has an hex value of #B8860B.
- ///
- public static readonly Rgba32 DarkGoldenrod = Color.DarkGoldenrod;
-
- ///
- /// Represents a matching the W3C definition that has an hex value of #A9A9A9.
- ///
- public static readonly Rgba32 DarkGray = Color.DarkGray;
-
- ///
- /// Represents a matching the W3C definition that has an hex value of #006400.
- ///
- public static readonly Rgba32 DarkGreen = Color.DarkGreen;
-
- ///
- /// Represents a matching the W3C definition that has an hex value of #BDB76B.
- ///
- public static readonly Rgba32 DarkKhaki = Color.DarkKhaki;
-
- ///
- /// Represents a matching the W3C definition that has an hex value of #8B008B.
- ///
- public static readonly Rgba32 DarkMagenta = Color.DarkMagenta;
-
- ///
- /// Represents a matching the W3C definition that has an hex value of #556B2F.
- ///
- public static readonly Rgba32 DarkOliveGreen = Color.DarkOliveGreen;
-
- ///
- /// Represents a matching the W3C definition that has an hex value of #FF8C00.
- ///
- public static readonly Rgba32 DarkOrange = Color.DarkOrange;
-
- ///
- /// Represents a matching the W3C definition that has an hex value of #9932CC.
- ///
- public static readonly Rgba32 DarkOrchid = Color.DarkOrchid;
-
- ///
- /// Represents a matching the W3C definition that has an hex value of #8B0000.
- ///
- public static readonly Rgba32 DarkRed = Color.DarkRed;
-
- ///
- /// Represents a matching the W3C definition that has an hex value of #E9967A.
- ///
- public static readonly Rgba32 DarkSalmon = Color.DarkSalmon;
-
- ///
- /// Represents a matching the W3C definition that has an hex value of #8FBC8B.
- ///
- public static readonly Rgba32 DarkSeaGreen = Color.DarkSeaGreen;
-
- ///
- /// Represents a matching the W3C definition that has an hex value of #483D8B.
- ///
- public static readonly Rgba32 DarkSlateBlue = Color.DarkSlateBlue;
-
- ///
- /// Represents a matching the W3C definition that has an hex value of #2F4F4F.
- ///
- public static readonly Rgba32 DarkSlateGray = Color.DarkSlateGray;
-
- ///
- /// Represents a matching the W3C definition that has an hex value of #00CED1.
- ///
- public static readonly Rgba32 DarkTurquoise = Color.DarkTurquoise;
-
- ///
- /// Represents a matching the W3C definition that has an hex value of #9400D3.
- ///
- public static readonly Rgba32 DarkViolet = Color.DarkViolet;
-
- ///
- /// Represents a matching the W3C definition that has an hex value of #FF1493.
- ///
- public static readonly Rgba32 DeepPink = Color.DeepPink;
-
- ///
- /// Represents a matching the W3C definition that has an hex value of #00BFFF.
- ///
- public static readonly Rgba32 DeepSkyBlue = Color.DeepSkyBlue;
-
- ///
- /// Represents a matching the W3C definition that has an hex value of #696969.
- ///
- public static readonly Rgba32 DimGray = Color.DimGray;
-
- ///
- /// Represents a matching the W3C definition that has an hex value of #1E90FF.
- ///
- public static readonly Rgba32 DodgerBlue = Color.DodgerBlue;
-
- ///
- /// Represents a matching the W3C definition that has an hex value of #B22222.
- ///
- public static readonly Rgba32 Firebrick = Color.Firebrick;
-
- ///
- /// Represents a matching the W3C definition that has an hex value of #FFFAF0.
- ///
- public static readonly Rgba32 FloralWhite = Color.FloralWhite;
-
- ///
- /// Represents a matching the W3C definition that has an hex value of #228B22.
- ///
- public static readonly Rgba32 ForestGreen = Color.ForestGreen;
-
- ///
- /// Represents a matching the W3C definition that has an hex value of #FF00FF.
- ///
- public static readonly Rgba32 Fuchsia = Color.Fuchsia;
-
- ///
- /// Represents a matching the W3C definition that has an hex value of #DCDCDC.
- ///
- public static readonly Rgba32 Gainsboro = Color.Gainsboro;
-
- ///
- /// Represents a matching the W3C definition that has an hex value of #F8F8FF.
- ///
- public static readonly Rgba32 GhostWhite = Color.GhostWhite;
-
- ///
- /// Represents a matching the W3C definition that has an hex value of #FFD700.
- ///
- public static readonly Rgba32 Gold = Color.Gold;
-
- ///
- /// Represents a matching the W3C definition that has an hex value of #DAA520.
- ///
- public static readonly Rgba32 Goldenrod = Color.Goldenrod;
-
- ///
- /// Represents a matching the W3C definition that has an hex value of #808080.
- ///
- public static readonly Rgba32 Gray = Color.Gray;
-
- ///
- /// Represents a matching the W3C definition that has an hex value of #008000.
- ///
- public static readonly Rgba32 Green = Color.Green;
-
- ///
- /// Represents a matching the W3C definition that has an hex value of #ADFF2F.
- ///
- public static readonly Rgba32 GreenYellow = Color.GreenYellow;
-
- ///
- /// Represents a matching the W3C definition that has an hex value of #F0FFF0.
- ///
- public static readonly Rgba32 Honeydew = Color.Honeydew;
-
- ///
- /// Represents a matching the W3C definition that has an hex value of #FF69B4.
- ///
- public static readonly Rgba32 HotPink = Color.HotPink;
-
- ///
- /// Represents a matching the W3C definition that has an hex value of #CD5C5C.
- ///
- public static readonly Rgba32 IndianRed = Color.IndianRed;
-
- ///
- /// Represents a matching the W3C definition that has an hex value of #4B0082.
- ///
- public static readonly Rgba32 Indigo = Color.Indigo;
-
- ///
- /// Represents a matching the W3C definition that has an hex value of #FFFFF0.
- ///
- public static readonly Rgba32 Ivory = Color.Ivory;
-
- ///
- /// Represents a matching the W3C definition that has an hex value of #F0E68C.
- ///
- public static readonly Rgba32 Khaki = Color.Khaki;
-
- ///
- /// Represents a matching the W3C definition that has an hex value of #E6E6FA.
- ///
- public static readonly Rgba32 Lavender = Color.Lavender;
-
- ///
- /// Represents a matching the W3C definition that has an hex value of #FFF0F5.
- ///
- public static readonly Rgba32 LavenderBlush = Color.LavenderBlush;
-
- ///
- /// Represents a matching the W3C definition that has an hex value of #7CFC00.
- ///
- public static readonly Rgba32 LawnGreen = Color.LawnGreen;
-
- ///
- /// Represents a matching the W3C definition that has an hex value of #FFFACD.
- ///
- public static readonly Rgba32 LemonChiffon = Color.LemonChiffon;
-
- ///
- /// Represents a matching the W3C definition that has an hex value of #ADD8E6.
- ///
- public static readonly Rgba32 LightBlue = Color.LightBlue;
-
- ///
- /// Represents a matching the W3C definition that has an hex value of #F08080.
- ///
- public static readonly Rgba32 LightCoral = Color.LightCoral;
-
- ///
- /// Represents a matching the W3C definition that has an hex value of #E0FFFF.
- ///
- public static readonly Rgba32 LightCyan = Color.LightCyan;
-
- ///
- /// Represents a matching the W3C definition that has an hex value of #FAFAD2.
- ///
- public static readonly Rgba32 LightGoldenrodYellow = Color.LightGoldenrodYellow;
-
- ///
- /// Represents a matching the W3C definition that has an hex value of #D3D3D3.
- ///
- public static readonly Rgba32 LightGray = Color.LightGray;
-
- ///
- /// Represents a matching the W3C definition that has an hex value of #90EE90.
- ///
- public static readonly Rgba32 LightGreen = Color.LightGreen;
-
- ///
- /// Represents a matching the W3C definition that has an hex value of #FFB6C1.
- ///
- public static readonly Rgba32 LightPink = Color.LightPink;
-
- ///
- /// Represents a matching the W3C definition that has an hex value of #FFA07A.
- ///
- public static readonly Rgba32 LightSalmon = Color.LightSalmon;
-
- ///
- /// Represents a matching the W3C definition that has an hex value of #20B2AA.
- ///
- public static readonly Rgba32 LightSeaGreen = Color.LightSeaGreen;
-
- ///
- /// Represents a matching the W3C definition that has an hex value of #87CEFA.
- ///
- public static readonly Rgba32 LightSkyBlue = Color.LightSkyBlue;
-
- ///
- /// Represents a matching the W3C definition that has an hex value of #778899.
- ///
- public static readonly Rgba32 LightSlateGray = Color.LightSlateGray;
-
- ///
- /// Represents a matching the W3C definition that has an hex value of #B0C4DE.
- ///
- public static readonly Rgba32 LightSteelBlue = Color.LightSteelBlue;
-
- ///
- /// Represents a matching the W3C definition that has an hex value of #FFFFE0.
- ///
- public static readonly Rgba32 LightYellow = Color.LightYellow;
-
- ///
- /// Represents a matching the W3C definition that has an hex value of #00FF00.
- ///
- public static readonly Rgba32 Lime = Color.Lime;
-
- ///
- /// Represents a matching the W3C definition that has an hex value of #32CD32.
- ///
- public static readonly Rgba32 LimeGreen = Color.LimeGreen;
-
- ///
- /// Represents a matching the W3C definition that has an hex value of #FAF0E6.
- ///
- public static readonly Rgba32 Linen = Color.Linen;
-
- ///
- /// Represents a matching the W3C definition that has an hex value of #FF00FF.
- ///
- public static readonly Rgba32 Magenta = Color.Magenta;
-
- ///
- /// Represents a matching the W3C definition that has an hex value of #800000.
- ///
- public static readonly Rgba32 Maroon = Color.Maroon;
-
- ///
- /// Represents a matching the W3C definition that has an hex value of #66CDAA.
- ///
- public static readonly Rgba32 MediumAquamarine = Color.MediumAquamarine;
-
- ///
- /// Represents a matching the W3C definition that has an hex value of #0000CD.
- ///
- public static readonly Rgba32 MediumBlue = Color.MediumBlue;
-
- ///
- /// Represents a matching the W3C definition that has an hex value of #BA55D3.
- ///
- public static readonly Rgba32 MediumOrchid = Color.MediumOrchid;
-
- ///
- /// Represents a matching the W3C definition that has an hex value of #9370DB.
- ///
- public static readonly Rgba32 MediumPurple = Color.MediumPurple;
-
- ///
- /// Represents a matching the W3C definition that has an hex value of #3CB371.
- ///
- public static readonly Rgba32 MediumSeaGreen = Color.MediumSeaGreen;
-
- ///
- /// Represents a matching the W3C definition that has an hex value of #7B68EE.
- ///
- public static readonly Rgba32 MediumSlateBlue = Color.MediumSlateBlue;
-
- ///
- /// Represents a matching the W3C definition that has an hex value of #00FA9A.
- ///
- public static readonly Rgba32 MediumSpringGreen = Color.MediumSpringGreen;
-
- ///
- /// Represents a matching the W3C definition that has an hex value of #48D1CC.
- ///
- public static readonly Rgba32 MediumTurquoise = Color.MediumTurquoise;
-
- ///
- /// Represents a matching the W3C definition that has an hex value of #C71585.
- ///
- public static readonly Rgba32 MediumVioletRed = Color.MediumVioletRed;
-
- ///
- /// Represents a matching the W3C definition that has an hex value of #191970.
- ///
- public static readonly Rgba32 MidnightBlue = Color.MidnightBlue;
-
- ///
- /// Represents a matching the W3C definition that has an hex value of #F5FFFA.
- ///
- public static readonly Rgba32 MintCream = Color.MintCream;
-
- ///
- /// Represents a matching the W3C definition that has an hex value of #FFE4E1.
- ///
- public static readonly Rgba32 MistyRose = Color.MistyRose;
-
- ///
- /// Represents a matching the W3C definition that has an hex value of #FFE4B5.
- ///
- public static readonly Rgba32 Moccasin = Color.Moccasin;
-
- ///
- /// Represents a matching the W3C definition that has an hex value of #FFDEAD.
- ///
- public static readonly Rgba32 NavajoWhite = Color.NavajoWhite;
-
- ///
- /// Represents a matching the W3C definition that has an hex value of #000080.
- ///
- public static readonly Rgba32 Navy = Color.Navy;
-
- ///
- /// Represents a matching the W3C definition that has an hex value of #FDF5E6.
- ///
- public static readonly Rgba32 OldLace = Color.OldLace;
-
- ///
- /// Represents a matching the W3C definition that has an hex value of #808000.
- ///
- public static readonly Rgba32 Olive = Color.Olive;
-
- ///
- /// Represents a matching the W3C definition that has an hex value of #6B8E23.
- ///
- public static readonly Rgba32 OliveDrab = Color.OliveDrab;
-
- ///
- /// Represents a matching the W3C definition that has an hex value of #FFA500.
- ///
- public static readonly Rgba32 Orange = Color.Orange;
-
- ///
- /// Represents a matching the W3C definition that has an hex value of #FF4500.
- ///
- public static readonly Rgba32 OrangeRed = Color.OrangeRed;
-
- ///
- /// Represents a matching the W3C definition that has an hex value of #DA70D6.
- ///
- public static readonly Rgba32 Orchid = Color.Orchid;
-
- ///
- /// Represents a matching the W3C definition that has an hex value of #EEE8AA.
- ///
- public static readonly Rgba32 PaleGoldenrod = Color.PaleGoldenrod;
-
- ///
- /// Represents a matching the W3C definition that has an hex value of #98FB98.
- ///
- public static readonly Rgba32 PaleGreen = Color.PaleGreen;
-
- ///
- /// Represents a matching the W3C definition that has an hex value of #AFEEEE.
- ///
- public static readonly Rgba32 PaleTurquoise = Color.PaleTurquoise;
-
- ///
- /// Represents a matching the W3C definition that has an hex value of #DB7093.
- ///
- public static readonly Rgba32 PaleVioletRed = Color.PaleVioletRed;
-
- ///
- /// Represents a matching the W3C definition that has an hex value of #FFEFD5.
- ///
- public static readonly Rgba32 PapayaWhip = Color.PapayaWhip;
-
- ///
- /// Represents a matching the W3C definition that has an hex value of #FFDAB9.
- ///
- public static readonly Rgba32 PeachPuff = Color.PeachPuff;
-
- ///
- /// Represents a matching the W3C definition that has an hex value of #CD853F.
- ///
- public static readonly Rgba32 Peru = Color.Peru;
-
- ///
- /// Represents a matching the W3C definition that has an hex value of #FFC0CB.
- ///
- public static readonly Rgba32 Pink = Color.Pink;
-
- ///
- /// Represents a matching the W3C definition that has an hex value of #DDA0DD.
- ///
- public static readonly Rgba32 Plum = Color.Plum;
-
- ///
- /// Represents a matching the W3C definition that has an hex value of #B0E0E6.
- ///
- public static readonly Rgba32 PowderBlue = Color.PowderBlue;
-
- ///
- /// Represents a matching the W3C definition that has an hex value of #800080.
- ///
- public static readonly Rgba32 Purple = Color.Purple;
-
- ///
- /// Represents a matching the W3C definition that has an hex value of #663399.
- ///
- public static readonly Rgba32 RebeccaPurple = Color.RebeccaPurple;
-
- ///
- /// Represents a matching the W3C definition that has an hex value of #FF0000.
- ///
- public static readonly Rgba32 Red = Color.Red;
-
- ///
- /// Represents a matching the W3C definition that has an hex value of #BC8F8F.
- ///
- public static readonly Rgba32 RosyBrown = Color.RosyBrown;
-
- ///
- /// Represents a matching the W3C definition that has an hex value of #4169E1.
- ///
- public static readonly Rgba32 RoyalBlue = Color.RoyalBlue;
-
- ///
- /// Represents a matching the W3C definition that has an hex value of #8B4513.
- ///
- public static readonly Rgba32 SaddleBrown = Color.SaddleBrown;
-
- ///
- /// Represents a matching the W3C definition that has an hex value of #FA8072.
- ///
- public static readonly Rgba32 Salmon = Color.Salmon;
-
- ///
- /// Represents a matching the W3C definition that has an hex value of #F4A460.
- ///
- public static readonly Rgba32 SandyBrown = Color.SandyBrown;
-
- ///
- /// Represents a matching the W3C definition that has an hex value of #2E8B57.
- ///
- public static readonly Rgba32 SeaGreen = Color.SeaGreen;
-
- ///
- /// Represents a matching the W3C definition that has an hex value of #FFF5EE.
- ///
- public static readonly Rgba32 SeaShell = Color.SeaShell;
-
- ///
- /// Represents a matching the W3C definition that has an hex value of #A0522D.
- ///
- public static readonly Rgba32 Sienna = Color.Sienna;
-
- ///
- /// Represents a matching the W3C definition that has an hex value of #C0C0C0.
- ///
- public static readonly Rgba32 Silver = Color.Silver;
-
- ///
- /// Represents a matching the W3C definition that has an hex value of #87CEEB.
- ///
- public static readonly Rgba32 SkyBlue = Color.SkyBlue;
-
- ///
- /// Represents a matching the W3C definition that has an hex value of #6A5ACD.
- ///
- public static readonly Rgba32 SlateBlue = Color.SlateBlue;
-
- ///
- /// Represents a matching the W3C definition that has an hex value of #708090.
- ///
- public static readonly Rgba32 SlateGray = Color.SlateGray;
-
- ///
- /// Represents a matching the W3C definition that has an hex value of #FFFAFA.
- ///
- public static readonly Rgba32 Snow = Color.Snow;
-
- ///
- /// Represents a matching the W3C definition that has an hex value of #00FF7F.
- ///
- public static readonly Rgba32 SpringGreen = Color.SpringGreen;
-
- ///
- /// Represents a matching the W3C definition that has an hex value of #4682B4.
- ///
- public static readonly Rgba32 SteelBlue = Color.SteelBlue;
-
- ///
- /// Represents a matching the W3C definition that has an hex value of #D2B48C.
- ///
- public static readonly Rgba32 Tan = Color.Tan;
-
- ///
- /// Represents a matching the W3C definition that has an hex value of #008080.
- ///
- public static readonly Rgba32 Teal = Color.Teal;
-
- ///
- /// Represents a matching the W3C definition that has an hex value of #D8BFD8.
- ///
- public static readonly Rgba32 Thistle = Color.Thistle;
-
- ///
- /// Represents a matching the W3C definition that has an hex value of #FF6347.
- ///
- public static readonly Rgba32 Tomato = Color.Tomato;
-
- ///
- /// Represents a matching the W3C definition that has an hex value of #FFFFFF.
- ///
- public static readonly Rgba32 Transparent = Color.Transparent;
-
- ///
- /// Represents a matching the W3C definition that has an hex value of #40E0D0.
- ///
- public static readonly Rgba32 Turquoise = Color.Turquoise;
-
- ///
- /// Represents a matching the W3C definition that has an hex value of #EE82EE.
- ///
- public static readonly Rgba32 Violet = Color.Violet;
-
- ///
- /// Represents a matching the W3C definition that has an hex value of #F5DEB3.
- ///
- public static readonly Rgba32 Wheat = Color.Wheat;
-
- ///
- /// Represents a matching the W3C definition that has an hex value of #FFFFFF.
- ///
- public static readonly Rgba32 White = Color.White;
-
- ///
- /// Represents a matching the W3C definition that has an hex value of #F5F5F5.
- ///
- public static readonly Rgba32 WhiteSmoke = Color.WhiteSmoke;
-
- ///
- /// Represents a matching the W3C definition that has an hex value of #FFFF00.
- ///
- public static readonly Rgba32 Yellow = Color.Yellow;
-
- ///
- /// Represents a matching the W3C definition that has an hex value of #9ACD32.
- ///
- public static readonly Rgba32 YellowGreen = Color.YellowGreen;
- }
-}
\ No newline at end of file
diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.cs
index 10631e2cf9..62f8d97e8f 100644
--- a/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.cs
+++ b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.cs
@@ -230,7 +230,8 @@ namespace SixLabors.ImageSharp.PixelFormats
public static bool operator !=(Rgba32 left, Rgba32 right) => !left.Equals(right);
///
- /// Creates a new instance of the struct.
+ /// Creates a new instance of the struct
+ /// from the given hexadecimal string.
///
///
/// The hexadecimal representation of the combined color components arranged
@@ -239,19 +240,50 @@ namespace SixLabors.ImageSharp.PixelFormats
///
/// The .
///
- public static Rgba32 FromHex(string hex)
+ [MethodImpl(InliningOptions.ShortMethod)]
+ public static Rgba32 ParseHex(string hex)
+ {
+ Guard.NotNull(hex, nameof(hex));
+
+ if (!TryParseHex(hex, out Rgba32 rgba))
+ {
+ throw new ArgumentException("Hexadecimal string is not in the correct format.", nameof(hex));
+ }
+
+ return rgba;
+ }
+
+ ///
+ /// Attempts to creates a new instance of the struct
+ /// from the given hexadecimal string.
+ ///
+ ///
+ /// The hexadecimal representation of the combined color components arranged
+ /// in rgb, rgba, rrggbb, or rrggbbaa format to match web syntax.
+ ///
+ /// When this method returns, contains the equivalent of the hexadecimal input.
+ ///
+ /// The .
+ ///
+ [MethodImpl(InliningOptions.ShortMethod)]
+ public static bool TryParseHex(string hex, out Rgba32 result)
{
- Guard.NotNullOrWhiteSpace(hex, nameof(hex));
+ result = default;
+ if (string.IsNullOrWhiteSpace(hex))
+ {
+ return false;
+ }
hex = ToRgbaHex(hex);
if (hex is null || !uint.TryParse(hex, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out uint packedValue))
{
- throw new ArgumentException("Hexadecimal string is not in the correct format.", nameof(hex));
+ return false;
}
packedValue = BinaryPrimitives.ReverseEndianness(packedValue);
- return Unsafe.As(ref packedValue);
+ result = Unsafe.As(ref packedValue);
+ return true;
}
///
diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/RgbaVector.cs b/src/ImageSharp/PixelFormats/PixelImplementations/RgbaVector.cs
index 67f09f3a5d..89c5f6ddba 100644
--- a/src/ImageSharp/PixelFormats/PixelImplementations/RgbaVector.cs
+++ b/src/ImageSharp/PixelFormats/PixelImplementations/RgbaVector.cs
@@ -94,7 +94,7 @@ namespace SixLabors.ImageSharp.PixelFormats
///
/// The .
///
- public static RgbaVector FromHex(string hex) => Color.FromHex(hex).ToPixel();
+ public static RgbaVector FromHex(string hex) => Color.ParseHex(hex).ToPixel();
///
public PixelOperations CreatePixelOperations() => new PixelOperations();
diff --git a/src/ImageSharp/PixelFormats/Utils/Vector4Converters.RgbaCompatible.cs b/src/ImageSharp/PixelFormats/Utils/Vector4Converters.RgbaCompatible.cs
index 0350c669ab..9c3a592d71 100644
--- a/src/ImageSharp/PixelFormats/Utils/Vector4Converters.RgbaCompatible.cs
+++ b/src/ImageSharp/PixelFormats/Utils/Vector4Converters.RgbaCompatible.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;
@@ -126,4 +126,4 @@ namespace SixLabors.ImageSharp.PixelFormats.Utils
}
}
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/Primitives/Rectangle.cs b/src/ImageSharp/Primitives/Rectangle.cs
index 95b01fd9d6..d391057a9b 100644
--- a/src/ImageSharp/Primitives/Rectangle.cs
+++ b/src/ImageSharp/Primitives/Rectangle.cs
@@ -460,4 +460,4 @@ namespace SixLabors.ImageSharp
this.Width.Equals(other.Width) &&
this.Height.Equals(other.Height);
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/Processing/Processors/Binarization/BinaryThresholdProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Binarization/BinaryThresholdProcessor{TPixel}.cs
index 380ce64d24..ed14a44e95 100644
--- a/src/ImageSharp/Processing/Processors/Binarization/BinaryThresholdProcessor{TPixel}.cs
+++ b/src/ImageSharp/Processing/Processors/Binarization/BinaryThresholdProcessor{TPixel}.cs
@@ -2,9 +2,9 @@
// Licensed under the Apache License, Version 2.0.
using System;
-
+using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.Advanced;
-using SixLabors.ImageSharp.Advanced.ParallelUtils;
+using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Processing.Processors.Binarization
@@ -42,36 +42,66 @@ namespace SixLabors.ImageSharp.Processing.Processors.Binarization
Configuration configuration = this.Configuration;
var interest = Rectangle.Intersect(sourceRectangle, source.Bounds());
- int startY = interest.Y;
- int endY = interest.Bottom;
- int startX = interest.X;
- int endX = interest.Right;
-
bool isAlphaOnly = typeof(TPixel) == typeof(A8);
- var workingRect = Rectangle.FromLTRB(startX, startY, endX, endY);
-
- ParallelHelper.IterateRows(
- workingRect,
+ var operation = new RowIntervalOperation(interest, source, upper, lower, threshold, isAlphaOnly);
+ ParallelRowIterator.IterateRows(
configuration,
- rows =>
- {
- Rgba32 rgba = default;
- for (int y = rows.Min; y < rows.Max; y++)
- {
- Span row = source.GetPixelRowSpan(y);
+ interest,
+ in operation);
+ }
+
+ ///
+ /// A implementing the clone logic for .
+ ///
+ private readonly struct RowIntervalOperation : IRowIntervalOperation
+ {
+ private readonly ImageFrame source;
+ private readonly TPixel upper;
+ private readonly TPixel lower;
+ private readonly byte threshold;
+ private readonly int minX;
+ private readonly int maxX;
+ private readonly bool isAlphaOnly;
- for (int x = startX; x < endX; x++)
- {
- ref TPixel color = ref row[x];
- color.ToRgba32(ref rgba);
+ [MethodImpl(InliningOptions.ShortMethod)]
+ public RowIntervalOperation(
+ Rectangle bounds,
+ ImageFrame source,
+ TPixel upper,
+ TPixel lower,
+ byte threshold,
+ bool isAlphaOnly)
+ {
+ this.source = source;
+ this.upper = upper;
+ this.lower = lower;
+ this.threshold = threshold;
+ this.minX = bounds.X;
+ this.maxX = bounds.Right;
+ this.isAlphaOnly = isAlphaOnly;
+ }
+
+ ///
+ [MethodImpl(InliningOptions.ShortMethod)]
+ public void Invoke(in RowInterval rows)
+ {
+ Rgba32 rgba = default;
+ for (int y = rows.Min; y < rows.Max; y++)
+ {
+ Span row = this.source.GetPixelRowSpan(y);
+
+ for (int x = this.minX; x < this.maxX; x++)
+ {
+ ref TPixel color = ref row[x];
+ color.ToRgba32(ref rgba);
- // Convert to grayscale using ITU-R Recommendation BT.709 if required
- byte luminance = isAlphaOnly ? rgba.A : ImageMaths.Get8BitBT709Luminance(rgba.R, rgba.G, rgba.B);
- color = luminance >= threshold ? upper : lower;
- }
- }
- });
+ // Convert to grayscale using ITU-R Recommendation BT.709 if required
+ byte luminance = this.isAlphaOnly ? rgba.A : ImageMaths.Get8BitBT709Luminance(rgba.R, rgba.G, rgba.B);
+ color = luminance >= this.threshold ? this.upper : this.lower;
+ }
+ }
+ }
}
}
}
diff --git a/src/ImageSharp/Processing/Processors/Convolution/BokehBlurProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Convolution/BokehBlurProcessor{TPixel}.cs
index e44076b3b6..023a4cea0d 100644
--- a/src/ImageSharp/Processing/Processors/Convolution/BokehBlurProcessor{TPixel}.cs
+++ b/src/ImageSharp/Processing/Processors/Convolution/BokehBlurProcessor{TPixel}.cs
@@ -7,8 +7,7 @@ using System.Collections.Generic;
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
-
-using SixLabors.ImageSharp.Advanced.ParallelUtils;
+using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing.Processors.Convolution.Parameters;
@@ -269,17 +268,26 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
protected override void OnFrameApply(ImageFrame source)
{
// Preliminary gamma highlight pass
- this.ApplyGammaExposure(source.PixelBuffer, this.SourceRectangle, this.Configuration);
+ var gammaOperation = new ApplyGammaExposureRowIntervalOperation(this.SourceRectangle, source.PixelBuffer, this.Configuration, this.gamma);
+ ParallelRowIterator.IterateRows(
+ this.Configuration,
+ this.SourceRectangle,
+ in gammaOperation);
// Create a 0-filled buffer to use to store the result of the component convolutions
- using (Buffer2D processingBuffer = this.Configuration.MemoryAllocator.Allocate2D(source.Size(), AllocationOptions.Clean))
- {
- // Perform the 1D convolutions on all the kernel components and accumulate the results
- this.OnFrameApplyCore(source, this.SourceRectangle, this.Configuration, processingBuffer);
+ using Buffer2D processingBuffer = this.Configuration.MemoryAllocator.Allocate2D(source.Size(), AllocationOptions.Clean);
- // Apply the inverse gamma exposure pass, and write the final pixel data
- this.ApplyInverseGammaExposure(source.PixelBuffer, processingBuffer, this.SourceRectangle, this.Configuration);
- }
+ // Perform the 1D convolutions on all the kernel components and accumulate the results
+ this.OnFrameApplyCore(source, this.SourceRectangle, this.Configuration, processingBuffer);
+
+ float inverseGamma = 1 / this.gamma;
+
+ // Apply the inverse gamma exposure pass, and write the final pixel data
+ var operation = new ApplyInverseGammaExposureRowIntervalOperation(this.SourceRectangle, source.PixelBuffer, processingBuffer, this.Configuration, inverseGamma);
+ ParallelRowIterator.IterateRows(
+ this.Configuration,
+ this.SourceRectangle,
+ in operation);
}
///
@@ -295,216 +303,223 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
Configuration configuration,
Buffer2D processingBuffer)
{
- using (Buffer2D firstPassBuffer = this.Configuration.MemoryAllocator.Allocate2D(source.Size()))
+ // Allocate the buffer with the intermediate convolution results
+ using Buffer2D firstPassBuffer = this.Configuration.MemoryAllocator.Allocate2D(source.Size());
+
+ // Perform two 1D convolutions for each component in the current instance
+ ref Complex64[] baseRef = ref MemoryMarshal.GetReference(this.kernels.AsSpan());
+ ref Vector4 paramsRef = ref MemoryMarshal.GetReference(this.kernelParameters.AsSpan());
+ for (int i = 0; i < this.kernels.Length; i++)
{
- // Perform two 1D convolutions for each component in the current instance
- ref Complex64[] baseRef = ref MemoryMarshal.GetReference(this.kernels.AsSpan());
- ref Vector4 paramsRef = ref MemoryMarshal.GetReference(this.kernelParameters.AsSpan());
- for (int i = 0; i < this.kernels.Length; i++)
- {
- // Compute the resulting complex buffer for the current component
- var interest = Rectangle.Intersect(sourceRectangle, source.Bounds());
- Complex64[] kernel = Unsafe.Add(ref baseRef, i);
- Vector4 parameters = Unsafe.Add(ref paramsRef, i);
-
- // Compute the two 1D convolutions and accumulate the partial results on the target buffer
- this.ApplyConvolution(firstPassBuffer, source.PixelBuffer, interest, kernel, configuration);
- this.ApplyConvolution(processingBuffer, firstPassBuffer, interest, kernel, configuration, parameters.Z, parameters.W);
- }
+ // Compute the resulting complex buffer for the current component
+ Complex64[] kernel = Unsafe.Add(ref baseRef, i);
+ Vector4 parameters = Unsafe.Add(ref paramsRef, i);
+
+ // Compute the vertical 1D convolution
+ var verticalOperation = new ApplyVerticalConvolutionRowIntervalOperation(sourceRectangle, firstPassBuffer, source.PixelBuffer, kernel);
+ ParallelRowIterator.IterateRows(
+ configuration,
+ sourceRectangle,
+ in verticalOperation);
+
+ // Compute the horizontal 1D convolutions and accumulate the partial results on the target buffer
+ var horizontalOperation = new ApplyHorizontalConvolutionRowIntervalOperation(sourceRectangle, processingBuffer, firstPassBuffer, kernel, parameters.Z, parameters.W);
+ ParallelRowIterator.IterateRows(
+ configuration,
+ sourceRectangle,
+ in horizontalOperation);
}
}
///
- /// Applies the process to the specified portion of the specified at the specified location
- /// and with the specified size.
+ /// A implementing the vertical convolution logic for .
///
- /// The target values to use to store the results.
- /// The source pixels. Cannot be null.
- ///
- /// The structure that specifies the portion of the image object to draw.
- ///
- /// The 1D kernel.
- /// The
- private void ApplyConvolution(
- Buffer2D targetValues,
- Buffer2D sourcePixels,
- Rectangle sourceRectangle,
- Complex64[] kernel,
- Configuration configuration)
+ private readonly struct ApplyVerticalConvolutionRowIntervalOperation : IRowIntervalOperation
{
- int startY = sourceRectangle.Y;
- int endY = sourceRectangle.Bottom;
- int startX = sourceRectangle.X;
- int endX = sourceRectangle.Right;
- int maxY = endY - 1;
- int maxX = endX - 1;
-
- var workingRectangle = Rectangle.FromLTRB(startX, startY, endX, endY);
- int width = workingRectangle.Width;
-
- ParallelHelper.IterateRows(
- workingRectangle,
- configuration,
- rows =>
+ private readonly Rectangle bounds;
+ private readonly Buffer2D targetValues;
+ private readonly Buffer2D sourcePixels;
+ private readonly Complex64[] kernel;
+ private readonly int maxY;
+ private readonly int maxX;
+
+ [MethodImpl(InliningOptions.ShortMethod)]
+ public ApplyVerticalConvolutionRowIntervalOperation(
+ Rectangle bounds,
+ Buffer2D targetValues,
+ Buffer2D sourcePixels,
+ Complex64[] kernel)
+ {
+ this.bounds = bounds;
+ this.maxY = this.bounds.Bottom - 1;
+ this.maxX = this.bounds.Right - 1;
+ this.targetValues = targetValues;
+ this.sourcePixels = sourcePixels;
+ this.kernel = kernel;
+ }
+
+ ///
+ [MethodImpl(InliningOptions.ShortMethod)]
+ public void Invoke(in RowInterval rows)
+ {
+ for (int y = rows.Min; y < rows.Max; y++)
{
- for (int y = rows.Min; y < rows.Max; y++)
- {
- Span targetRowSpan = targetValues.GetRowSpanUnchecked(y).Slice(startX);
+ Span targetRowSpan = this.targetValues.GetRowSpanUnchecked(y).Slice(this.bounds.X);
- for (int x = 0; x < width; x++)
- {
- Buffer2DUtils.Convolve4(kernel, sourcePixels, targetRowSpan, y, x, startY, maxY, startX, maxX);
- }
+ for (int x = 0; x < this.bounds.Width; x++)
+ {
+ Buffer2DUtils.Convolve4(this.kernel, this.sourcePixels, targetRowSpan, y, x, this.bounds.Y, this.maxY, this.bounds.X, this.maxX);
}
- });
+ }
+ }
}
///
- /// Applies the process to the specified portion of the specified buffer at the specified location
- /// and with the specified size.
+ /// A implementing the horizontal convolution logic for .
///
- /// The target values to use to store the results.
- /// The source complex values. Cannot be null.
- /// The structure that specifies the portion of the image object to draw.
- /// The 1D kernel.
- /// The
- /// The weight factor for the real component of the complex pixel values.
- /// The weight factor for the imaginary component of the complex pixel values.
- private void ApplyConvolution(
- Buffer2D targetValues,
- Buffer2D sourceValues,
- Rectangle sourceRectangle,
- Complex64[] kernel,
- Configuration configuration,
- float z,
- float w)
+ private readonly struct ApplyHorizontalConvolutionRowIntervalOperation : IRowIntervalOperation
{
- int startY = sourceRectangle.Y;
- int endY = sourceRectangle.Bottom;
- int startX = sourceRectangle.X;
- int endX = sourceRectangle.Right;
- int maxY = endY - 1;
- int maxX = endX - 1;
-
- var workingRectangle = Rectangle.FromLTRB(startX, startY, endX, endY);
- int width = workingRectangle.Width;
-
- ParallelHelper.IterateRows(
- workingRectangle,
- configuration,
- rows =>
+ private readonly Rectangle bounds;
+ private readonly Buffer2D targetValues;
+ private readonly Buffer2D sourceValues;
+ private readonly Complex64[] kernel;
+ private readonly float z;
+ private readonly float w;
+ private readonly int maxY;
+ private readonly int maxX;
+
+ [MethodImpl(InliningOptions.ShortMethod)]
+ public ApplyHorizontalConvolutionRowIntervalOperation(
+ Rectangle bounds,
+ Buffer2D targetValues,
+ Buffer2D sourceValues,
+ Complex64[] kernel,
+ float z,
+ float w)
+ {
+ this.bounds = bounds;
+ this.maxY = this.bounds.Bottom - 1;
+ this.maxX = this.bounds.Right - 1;
+ this.targetValues = targetValues;
+ this.sourceValues = sourceValues;
+ this.kernel = kernel;
+ this.z = z;
+ this.w = w;
+ }
+
+ ///
+ [MethodImpl(InliningOptions.ShortMethod)]
+ public void Invoke(in RowInterval rows)
+ {
+ for (int y = rows.Min; y < rows.Max; y++)
{
- for (int y = rows.Min; y < rows.Max; y++)
- {
- Span targetRowSpan = targetValues.GetRowSpanUnchecked(y).Slice(startX);
+ Span targetRowSpan = this.targetValues.GetRowSpanUnchecked(y).Slice(this.bounds.X);
- for (int x = 0; x < width; x++)
- {
- Buffer2DUtils.Convolve4AndAccumulatePartials(kernel, sourceValues, targetRowSpan, y, x, startY, maxY, startX, maxX, z, w);
- }
+ for (int x = 0; x < this.bounds.Width; x++)
+ {
+ Buffer2DUtils.Convolve4AndAccumulatePartials(this.kernel, this.sourceValues, targetRowSpan, y, x, this.bounds.Y, this.maxY, this.bounds.X, this.maxX, this.z, this.w);
}
- });
+ }
+ }
}
///
- /// Applies the gamma correction/highlight to the input pixel buffer.
+ /// A implementing the gamma exposure logic for .
///
- /// The target pixel buffer to adjust.
- ///
- /// The structure that specifies the portion of the image object to draw.
- ///
- /// The
- private void ApplyGammaExposure(
- Buffer2D targetPixels,
- Rectangle sourceRectangle,
- Configuration configuration)
+ private readonly struct ApplyGammaExposureRowIntervalOperation : IRowIntervalOperation
{
- int startY = sourceRectangle.Y;
- int endY = sourceRectangle.Bottom;
- int startX = sourceRectangle.X;
- int endX = sourceRectangle.Right;
-
- var workingRectangle = Rectangle.FromLTRB(startX, startY, endX, endY);
- int width = workingRectangle.Width;
- float exp = this.gamma;
-
- ParallelHelper.IterateRowsWithTempBuffer(
- workingRectangle,
- configuration,
- (rows, vectorBuffer) =>
+ private readonly Rectangle bounds;
+ private readonly Buffer2D targetPixels;
+ private readonly Configuration configuration;
+ private readonly float gamma;
+
+ [MethodImpl(InliningOptions.ShortMethod)]
+ public ApplyGammaExposureRowIntervalOperation(
+ Rectangle bounds,
+ Buffer2D targetPixels,
+ Configuration configuration,
+ float gamma)
+ {
+ this.bounds = bounds;
+ this.targetPixels = targetPixels;
+ this.configuration = configuration;
+ this.gamma = gamma;
+ }
+
+ ///
+ [MethodImpl(InliningOptions.ShortMethod)]
+ public void Invoke(in RowInterval rows, Span span)
+ {
+ for (int y = rows.Min; y < rows.Max; y++)
+ {
+ Span targetRowSpan = this.targetPixels.GetRowSpanUnchecked(y).Slice(this.bounds.X);
+ PixelOperations.Instance.ToVector4(this.configuration, targetRowSpan.Slice(0, span.Length), span, PixelConversionModifiers.Premultiply);
+ ref Vector4 baseRef = ref MemoryMarshal.GetReference(span);
+
+ for (int x = 0; x < this.bounds.Width; x++)
{
- Span vectorSpan = vectorBuffer.Span;
- int length = vectorSpan.Length;
-
- for (int y = rows.Min; y < rows.Max; y++)
- {
- Span targetRowSpan = targetPixels.GetRowSpanUnchecked(y).Slice(startX);
- PixelOperations.Instance.ToVector4(configuration, targetRowSpan.Slice(0, length), vectorSpan, PixelConversionModifiers.Premultiply);
- ref Vector4 baseRef = ref MemoryMarshal.GetReference(vectorSpan);
-
- for (int x = 0; x < width; x++)
- {
- ref Vector4 v = ref Unsafe.Add(ref baseRef, x);
- v.X = MathF.Pow(v.X, exp);
- v.Y = MathF.Pow(v.Y, exp);
- v.Z = MathF.Pow(v.Z, exp);
- }
-
- PixelOperations.Instance.FromVector4Destructive(configuration, vectorSpan.Slice(0, length), targetRowSpan);
- }
- });
+ ref Vector4 v = ref Unsafe.Add(ref baseRef, x);
+ v.X = MathF.Pow(v.X, this.gamma);
+ v.Y = MathF.Pow(v.Y, this.gamma);
+ v.Z = MathF.Pow(v.Z, this.gamma);
+ }
+
+ PixelOperations.Instance.FromVector4Destructive(this.configuration, span, targetRowSpan);
+ }
+ }
}
///
- /// Applies the inverse gamma correction/highlight pass, and converts the input buffer into pixel values.
+ /// A implementing the inverse gamma exposure logic for .
///
- /// The target pixels to apply the process to.
- /// The source values. Cannot be null.
- ///
- /// The structure that specifies the portion of the image object to draw.
- ///
- /// The
- private void ApplyInverseGammaExposure(
- Buffer2D targetPixels,
- Buffer2D sourceValues,
- Rectangle sourceRectangle,
- Configuration configuration)
+ private readonly struct ApplyInverseGammaExposureRowIntervalOperation : IRowIntervalOperation
{
- int startY = sourceRectangle.Y;
- int endY = sourceRectangle.Bottom;
- int startX = sourceRectangle.X;
- int endX = sourceRectangle.Right;
-
- var workingRectangle = Rectangle.FromLTRB(startX, startY, endX, endY);
- int width = workingRectangle.Width;
- float expGamma = 1 / this.gamma;
-
- ParallelHelper.IterateRows(
- workingRectangle,
- configuration,
- rows =>
+ private readonly Rectangle bounds;
+ private readonly Buffer2D targetPixels;
+ private readonly Buffer2D sourceValues;
+ private readonly Configuration configuration;
+ private readonly float inverseGamma;
+
+ [MethodImpl(InliningOptions.ShortMethod)]
+ public ApplyInverseGammaExposureRowIntervalOperation(
+ Rectangle bounds,
+ Buffer2D targetPixels,
+ Buffer2D sourceValues,
+ Configuration configuration,
+ float inverseGamma)
+ {
+ this.bounds = bounds;
+ this.targetPixels = targetPixels;
+ this.sourceValues = sourceValues;
+ this.configuration = configuration;
+ this.inverseGamma = inverseGamma;
+ }
+
+ ///
+ [MethodImpl(InliningOptions.ShortMethod)]
+ public void Invoke(in RowInterval rows)
+ {
+ Vector4 low = Vector4.Zero;
+ var high = new Vector4(float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity);
+
+ for (int y = rows.Min; y < rows.Max; y++)
+ {
+ Span targetPixelSpan = this.targetPixels.GetRowSpanUnchecked(y).Slice(this.bounds.X);
+ Span sourceRowSpan = this.sourceValues.GetRowSpanUnchecked(y).Slice(this.bounds.X);
+ ref Vector4 sourceRef = ref MemoryMarshal.GetReference(sourceRowSpan);
+
+ for (int x = 0; x < this.bounds.Width; x++)
{
- Vector4 low = Vector4.Zero;
- var high = new Vector4(float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity);
-
- for (int y = rows.Min; y < rows.Max; y++)
- {
- Span targetPixelSpan = targetPixels.GetRowSpanUnchecked(y).Slice(startX);
- Span sourceRowSpan = sourceValues.GetRowSpanUnchecked(y).Slice(startX);
- ref Vector4 sourceRef = ref MemoryMarshal.GetReference(sourceRowSpan);
-
- for (int x = 0; x < width; x++)
- {
- ref Vector4 v = ref Unsafe.Add(ref sourceRef, x);
- var clamp = Vector4.Clamp(v, low, high);
- v.X = MathF.Pow(clamp.X, expGamma);
- v.Y = MathF.Pow(clamp.Y, expGamma);
- v.Z = MathF.Pow(clamp.Z, expGamma);
- }
-
- PixelOperations.Instance.FromVector4Destructive(configuration, sourceRowSpan.Slice(0, width), targetPixelSpan, PixelConversionModifiers.Premultiply);
- }
- });
+ ref Vector4 v = ref Unsafe.Add(ref sourceRef, x);
+ var clamp = Vector4.Clamp(v, low, high);
+ v.X = MathF.Pow(clamp.X, this.inverseGamma);
+ v.Y = MathF.Pow(clamp.Y, this.inverseGamma);
+ v.Z = MathF.Pow(clamp.Z, this.inverseGamma);
+ }
+
+ PixelOperations.Instance.FromVector4Destructive(this.configuration, sourceRowSpan.Slice(0, this.bounds.Width), targetPixelSpan, PixelConversionModifiers.Premultiply);
+ }
+ }
}
}
}
diff --git a/src/ImageSharp/Processing/Processors/Convolution/BoxBlurProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Convolution/BoxBlurProcessor{TPixel}.cs
index 095c91bac0..50004655fd 100644
--- a/src/ImageSharp/Processing/Processors/Convolution/BoxBlurProcessor{TPixel}.cs
+++ b/src/ImageSharp/Processing/Processors/Convolution/BoxBlurProcessor{TPixel}.cs
@@ -40,10 +40,9 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
///
protected override void OnFrameApply(ImageFrame source)
{
- using (var processor = new Convolution2PassProcessor(this.Configuration, this.KernelX, this.KernelY, false, this.Source, this.SourceRectangle))
- {
- processor.Apply(source);
- }
+ using var processor = new Convolution2PassProcessor(this.Configuration, this.KernelX, this.KernelY, false, this.Source, this.SourceRectangle);
+
+ processor.Apply(source);
}
///
diff --git a/src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor{TPixel}.cs
index 1e30d6a4a6..9d68196f51 100644
--- a/src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor{TPixel}.cs
+++ b/src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor{TPixel}.cs
@@ -3,9 +3,9 @@
using System;
using System.Numerics;
+using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
-
-using SixLabors.ImageSharp.Advanced.ParallelUtils;
+using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
@@ -60,79 +60,105 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
///
protected override void OnFrameApply(ImageFrame source)
{
- DenseMatrix matrixY = this.KernelY;
- DenseMatrix matrixX = this.KernelX;
- bool preserveAlpha = this.PreserveAlpha;
+ using Buffer2D targetPixels = this.Configuration.MemoryAllocator.Allocate2D(source.Width, source.Height);
+
+ source.CopyTo(targetPixels);
var interest = Rectangle.Intersect(this.SourceRectangle, source.Bounds());
- int startY = interest.Y;
- int endY = interest.Bottom;
- int startX = interest.X;
- int endX = interest.Right;
- int maxY = endY - 1;
- int maxX = endX - 1;
-
- using (Buffer2D targetPixels = this.Configuration.MemoryAllocator.Allocate2D(source.Width, source.Height))
+ var operation = new RowIntervalOperation(interest, targetPixels, source.PixelBuffer, this.KernelY, this.KernelX, this.Configuration, this.PreserveAlpha);
+
+ ParallelRowIterator.IterateRows(
+ this.Configuration,
+ interest,
+ in operation);
+
+ Buffer2D.SwapOrCopyContent(source.PixelBuffer, targetPixels);
+ }
+
+ ///
+ /// A implementing the convolution logic for .
+ ///
+ private readonly struct RowIntervalOperation : IRowIntervalOperation
+ {
+ private readonly Rectangle bounds;
+ private readonly int maxY;
+ private readonly int maxX;
+ private readonly Buffer2D targetPixels;
+ private readonly Buffer2D sourcePixels;
+ private readonly DenseMatrix kernelY;
+ private readonly DenseMatrix kernelX;
+ private readonly Configuration configuration;
+ private readonly bool preserveAlpha;
+
+ [MethodImpl(InliningOptions.ShortMethod)]
+ public RowIntervalOperation(
+ Rectangle bounds,
+ Buffer2D targetPixels,
+ Buffer2D sourcePixels,
+ DenseMatrix kernelY,
+ DenseMatrix kernelX,
+ Configuration configuration,
+ bool preserveAlpha)
{
- source.CopyTo(targetPixels);
+ this.bounds = bounds;
+ this.maxY = this.bounds.Bottom - 1;
+ this.maxX = this.bounds.Right - 1;
+ this.targetPixels = targetPixels;
+ this.sourcePixels = sourcePixels;
+ this.kernelY = kernelY;
+ this.kernelX = kernelX;
+ this.configuration = configuration;
+ this.preserveAlpha = preserveAlpha;
+ }
- var workingRectangle = Rectangle.FromLTRB(startX, startY, endX, endY);
- int width = workingRectangle.Width;
+ ///
+ [MethodImpl(InliningOptions.ShortMethod)]
+ public void Invoke(in RowInterval rows, Span span)
+ {
+ ref Vector4 spanRef = ref MemoryMarshal.GetReference(span);
- ParallelHelper.IterateRowsWithTempBuffer(
- workingRectangle,
- this.Configuration,
- (rows, vectorBuffer) =>
+ for (int y = rows.Min; y < rows.Max; y++)
+ {
+ Span targetRowSpan = this.targetPixels.GetRowSpanUnchecked(y).Slice(this.bounds.X);
+ PixelOperations.Instance.ToVector4(this.configuration, targetRowSpan.Slice(0, span.Length), span);
+
+ if (this.preserveAlpha)
+ {
+ for (int x = 0; x < this.bounds.Width; x++)
+ {
+ DenseMatrixUtils.Convolve2D3(
+ in this.kernelY,
+ in this.kernelX,
+ this.sourcePixels,
+ ref spanRef,
+ y,
+ x,
+ this.bounds.Y,
+ this.maxY,
+ this.bounds.X,
+ this.maxX);
+ }
+ }
+ else
+ {
+ for (int x = 0; x < this.bounds.Width; x++)
{
- Span vectorSpan = vectorBuffer.Span;
- int length = vectorSpan.Length;
- ref Vector4 vectorSpanRef = ref MemoryMarshal.GetReference(vectorSpan);
-
- for (int y = rows.Min; y < rows.Max; y++)
- {
- Span targetRowSpan = targetPixels.GetRowSpanUnchecked(y).Slice(startX);
- PixelOperations.Instance.ToVector4(this.Configuration, targetRowSpan.Slice(0, length), vectorSpan);
-
- if (preserveAlpha)
- {
- for (int x = 0; x < width; x++)
- {
- DenseMatrixUtils.Convolve2D3(
- in matrixY,
- in matrixX,
- source.PixelBuffer,
- ref vectorSpanRef,
- y,
- x,
- startY,
- maxY,
- startX,
- maxX);
- }
- }
- else
- {
- for (int x = 0; x < width; x++)
- {
- DenseMatrixUtils.Convolve2D4(
- in matrixY,
- in matrixX,
- source.PixelBuffer,
- ref vectorSpanRef,
- y,
- x,
- startY,
- maxY,
- startX,
- maxX);
- }
- }
-
- PixelOperations.Instance.FromVector4Destructive(this.Configuration, vectorSpan, targetRowSpan);
- }
- });
-
- Buffer2D.SwapOrCopyContent(source.PixelBuffer, targetPixels);
+ DenseMatrixUtils.Convolve2D4(
+ in this.kernelY,
+ in this.kernelX,
+ this.sourcePixels,
+ ref spanRef,
+ y,
+ x,
+ this.bounds.Y,
+ this.maxY,
+ this.bounds.X,
+ this.maxX);
+ }
+ }
+
+ PixelOperations.Instance.FromVector4Destructive(this.configuration, span, targetRowSpan);
+ }
}
}
}
diff --git a/src/ImageSharp/Processing/Processors/Convolution/Convolution2PassProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Convolution/Convolution2PassProcessor{TPixel}.cs
index f36d5d6d06..809cda8a35 100644
--- a/src/ImageSharp/Processing/Processors/Convolution/Convolution2PassProcessor{TPixel}.cs
+++ b/src/ImageSharp/Processing/Processors/Convolution/Convolution2PassProcessor{TPixel}.cs
@@ -3,9 +3,9 @@
using System;
using System.Numerics;
+using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
-
-using SixLabors.ImageSharp.Advanced.ParallelUtils;
+using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
@@ -59,95 +59,104 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
///
protected override void OnFrameApply(ImageFrame source)
{
- using (Buffer2D firstPassPixels = this.Configuration.MemoryAllocator.Allocate2D(source.Size()))
- {
- var interest = Rectangle.Intersect(this.SourceRectangle, source.Bounds());
- this.ApplyConvolution(firstPassPixels, source.PixelBuffer, interest, this.KernelX, this.Configuration);
- this.ApplyConvolution(source.PixelBuffer, firstPassPixels, interest, this.KernelY, this.Configuration);
- }
+ using Buffer2D firstPassPixels = this.Configuration.MemoryAllocator.Allocate2D(source.Size());
+
+ var interest = Rectangle.Intersect(this.SourceRectangle, source.Bounds());
+
+ // Horizontal convolution
+ var horizontalOperation = new RowIntervalOperation(interest, firstPassPixels, source.PixelBuffer, this.KernelX, this.Configuration, this.PreserveAlpha);
+ ParallelRowIterator.IterateRows(
+ this.Configuration,
+ interest,
+ in horizontalOperation);
+
+ // Vertical convolution
+ var verticalOperation = new RowIntervalOperation(interest, source.PixelBuffer, firstPassPixels, this.KernelY, this.Configuration, this.PreserveAlpha);
+ ParallelRowIterator.IterateRows(
+ this.Configuration,
+ interest,
+ in verticalOperation);
}
///
- /// Applies the process to the specified portion of the specified at the specified location
- /// and with the specified size.
+ /// A implementing the convolution logic for .
///
- /// The target pixels to apply the process to.
- /// The source pixels. Cannot be null.
- ///
- /// The structure that specifies the portion of the image object to draw.
- ///
- /// The kernel operator.
- /// The
- private void ApplyConvolution(
- Buffer2D targetPixels,
- Buffer2D sourcePixels,
- Rectangle sourceRectangle,
- in DenseMatrix kernel,
- Configuration configuration)
+ private readonly struct RowIntervalOperation : IRowIntervalOperation
{
- DenseMatrix matrix = kernel;
- bool preserveAlpha = this.PreserveAlpha;
-
- int startY = sourceRectangle.Y;
- int endY = sourceRectangle.Bottom;
- int startX = sourceRectangle.X;
- int endX = sourceRectangle.Right;
- int maxY = endY - 1;
- int maxX = endX - 1;
-
- var workingRectangle = Rectangle.FromLTRB(startX, startY, endX, endY);
- int width = workingRectangle.Width;
-
- ParallelHelper.IterateRowsWithTempBuffer(
- workingRectangle,
- configuration,
- (rows, vectorBuffer) =>
- {
- Span vectorSpan = vectorBuffer.Span;
- int length = vectorSpan.Length;
- ref Vector4 vectorSpanRef = ref MemoryMarshal.GetReference(vectorSpan);
+ private readonly Rectangle bounds;
+ private readonly Buffer2D targetPixels;
+ private readonly Buffer2D sourcePixels;
+ private readonly DenseMatrix kernel;
+ private readonly Configuration configuration;
+ private readonly bool preserveAlpha;
+
+ [MethodImpl(InliningOptions.ShortMethod)]
+ public RowIntervalOperation(
+ Rectangle bounds,
+ Buffer2D targetPixels,
+ Buffer2D sourcePixels,
+ DenseMatrix kernel,
+ Configuration configuration,
+ bool preserveAlpha)
+ {
+ this.bounds = bounds;
+ this.targetPixels = targetPixels;
+ this.sourcePixels = sourcePixels;
+ this.kernel = kernel;
+ this.configuration = configuration;
+ this.preserveAlpha = preserveAlpha;
+ }
- for (int y = rows.Min; y < rows.Max; y++)
+ ///
+ [MethodImpl(InliningOptions.ShortMethod)]
+ public void Invoke(in RowInterval rows, Span span)
+ {
+ ref Vector4 spanRef = ref MemoryMarshal.GetReference(span);
+
+ int maxY = this.bounds.Bottom - 1;
+ int maxX = this.bounds.Right - 1;
+
+ for (int y = rows.Min; y < rows.Max; y++)
+ {
+ Span targetRowSpan = this.targetPixels.GetRowSpanUnchecked(y).Slice(this.bounds.X);
+ PixelOperations.Instance.ToVector4(this.configuration, targetRowSpan.Slice(0, span.Length), span);
+
+ if (this.preserveAlpha)
+ {
+ for (int x = 0; x < this.bounds.Width; x++)
{
- Span targetRowSpan = targetPixels.GetRowSpanUnchecked(y).Slice(startX);
- PixelOperations.Instance.ToVector4(configuration, targetRowSpan.Slice(0, length), vectorSpan);
-
- if (preserveAlpha)
- {
- for (int x = 0; x < width; x++)
- {
- DenseMatrixUtils.Convolve3(
- in matrix,
- sourcePixels,
- ref vectorSpanRef,
- y,
- x,
- startY,
- maxY,
- startX,
- maxX);
- }
- }
- else
- {
- for (int x = 0; x < width; x++)
- {
- DenseMatrixUtils.Convolve4(
- in matrix,
- sourcePixels,
- ref vectorSpanRef,
- y,
- x,
- startY,
- maxY,
- startX,
- maxX);
- }
- }
-
- PixelOperations.Instance.FromVector4Destructive(configuration, vectorSpan, targetRowSpan);
+ DenseMatrixUtils.Convolve3(
+ in this.kernel,
+ this.sourcePixels,
+ ref spanRef,
+ y,
+ x,
+ this.bounds.Y,
+ maxY,
+ this.bounds.X,
+ maxX);
}
- });
+ }
+ else
+ {
+ for (int x = 0; x < this.bounds.Width; x++)
+ {
+ DenseMatrixUtils.Convolve4(
+ in this.kernel,
+ this.sourcePixels,
+ ref spanRef,
+ y,
+ x,
+ this.bounds.Y,
+ maxY,
+ this.bounds.X,
+ maxX);
+ }
+ }
+
+ PixelOperations.Instance.FromVector4Destructive(this.configuration, span, targetRowSpan);
+ }
+ }
}
}
}
diff --git a/src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessor{TPixel}.cs
index 779360bde0..426a2800cf 100644
--- a/src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessor{TPixel}.cs
+++ b/src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessor{TPixel}.cs
@@ -3,9 +3,9 @@
using System;
using System.Numerics;
+using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
-
-using SixLabors.ImageSharp.Advanced.ParallelUtils;
+using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
@@ -51,76 +51,99 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
///
protected override void OnFrameApply(ImageFrame source)
{
- DenseMatrix matrix = this.KernelXY;
- bool preserveAlpha = this.PreserveAlpha;
+ using Buffer2D targetPixels = this.Configuration.MemoryAllocator.Allocate2D(source.Size());
+
+ source.CopyTo(targetPixels);
var interest = Rectangle.Intersect(this.SourceRectangle, source.Bounds());
- int startY = interest.Y;
- int endY = interest.Bottom;
- int startX = interest.X;
- int endX = interest.Right;
- int maxY = endY - 1;
- int maxX = endX - 1;
+ var operation = new RowIntervalOperation(interest, targetPixels, source.PixelBuffer, this.KernelXY, this.Configuration, this.PreserveAlpha);
+ ParallelRowIterator.IterateRows(
+ this.Configuration,
+ interest,
+ in operation);
- using (Buffer2D targetPixels = this.Configuration.MemoryAllocator.Allocate2D(source.Size()))
- {
- source.CopyTo(targetPixels);
+ Buffer2D.SwapOrCopyContent(source.PixelBuffer, targetPixels);
+ }
- var workingRectangle = Rectangle.FromLTRB(startX, startY, endX, endY);
- int width = workingRectangle.Width;
+ ///
+ /// A implementing the convolution logic for .
+ ///
+ private readonly struct RowIntervalOperation : IRowIntervalOperation
+ {
+ private readonly Rectangle bounds;
+ private readonly int maxY;
+ private readonly int maxX;
+ private readonly Buffer2D targetPixels;
+ private readonly Buffer2D sourcePixels;
+ private readonly DenseMatrix kernel;
+ private readonly Configuration configuration;
+ private readonly bool preserveAlpha;
- ParallelHelper.IterateRowsWithTempBuffer(
- workingRectangle,
- this.Configuration,
- (rows, vectorBuffer) =>
- {
- Span vectorSpan = vectorBuffer.Span;
- int length = vectorSpan.Length;
- ref Vector4 vectorSpanRef = ref MemoryMarshal.GetReference(vectorSpan);
+ [MethodImpl(InliningOptions.ShortMethod)]
+ public RowIntervalOperation(
+ Rectangle bounds,
+ Buffer2D targetPixels,
+ Buffer2D sourcePixels,
+ DenseMatrix kernel,
+ Configuration configuration,
+ bool preserveAlpha)
+ {
+ this.bounds = bounds;
+ this.maxY = this.bounds.Bottom - 1;
+ this.maxX = this.bounds.Right - 1;
+ this.targetPixels = targetPixels;
+ this.sourcePixels = sourcePixels;
+ this.kernel = kernel;
+ this.configuration = configuration;
+ this.preserveAlpha = preserveAlpha;
+ }
- for (int y = rows.Min; y < rows.Max; y++)
- {
- Span targetRowSpan = targetPixels.GetRowSpanUnchecked(y).Slice(startX);
- PixelOperations.Instance.ToVector4(this.Configuration, targetRowSpan.Slice(0, length), vectorSpan);
+ ///
+ [MethodImpl(InliningOptions.ShortMethod)]
+ public void Invoke(in RowInterval rows, Span span)
+ {
+ ref Vector4 spanRef = ref MemoryMarshal.GetReference(span);
- if (preserveAlpha)
- {
- for (int x = 0; x < width; x++)
- {
- DenseMatrixUtils.Convolve3(
- in matrix,
- source.PixelBuffer,
- ref vectorSpanRef,
- y,
- x,
- startY,
- maxY,
- startX,
- maxX);
- }
- }
- else
- {
- for (int x = 0; x < width; x++)
- {
- DenseMatrixUtils.Convolve4(
- in matrix,
- source.PixelBuffer,
- ref vectorSpanRef,
- y,
- x,
- startY,
- maxY,
- startX,
- maxX);
- }
- }
+ for (int y = rows.Min; y < rows.Max; y++)
+ {
+ Span targetRowSpan = this.targetPixels.GetRowSpanUnchecked(y).Slice(this.bounds.X);
+ PixelOperations.Instance.ToVector4(this.configuration, targetRowSpan.Slice(0, span.Length), span);
- PixelOperations.Instance.FromVector4Destructive(this.Configuration, vectorSpan, targetRowSpan);
- }
- });
+ if (this.preserveAlpha)
+ {
+ for (int x = 0; x < this.bounds.Width; x++)
+ {
+ DenseMatrixUtils.Convolve3(
+ in this.kernel,
+ this.sourcePixels,
+ ref spanRef,
+ y,
+ x,
+ this.bounds.Y,
+ this.maxY,
+ this.bounds.X,
+ this.maxX);
+ }
+ }
+ else
+ {
+ for (int x = 0; x < this.bounds.Width; x++)
+ {
+ DenseMatrixUtils.Convolve4(
+ in this.kernel,
+ this.sourcePixels,
+ ref spanRef,
+ y,
+ x,
+ this.bounds.Y,
+ this.maxY,
+ this.bounds.X,
+ this.maxX);
+ }
+ }
- Buffer2D.SwapOrCopyContent(source.PixelBuffer, targetPixels);
+ PixelOperations.Instance.FromVector4Destructive(this.configuration, span, targetRowSpan);
+ }
}
}
}
diff --git a/src/ImageSharp/Processing/Processors/Convolution/EdgeDetector2DProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Convolution/EdgeDetector2DProcessor{TPixel}.cs
index 31c4fad79f..c8c57fc293 100644
--- a/src/ImageSharp/Processing/Processors/Convolution/EdgeDetector2DProcessor{TPixel}.cs
+++ b/src/ImageSharp/Processing/Processors/Convolution/EdgeDetector2DProcessor{TPixel}.cs
@@ -63,10 +63,9 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
///
protected override void OnFrameApply(ImageFrame source)
{
- using (var processor = new Convolution2DProcessor(this.Configuration, this.KernelX, this.KernelY, true, this.Source, this.SourceRectangle))
- {
- processor.Apply(source);
- }
+ using var processor = new Convolution2DProcessor(this.Configuration, this.KernelX, this.KernelY, true, this.Source, this.SourceRectangle);
+
+ processor.Apply(source);
}
}
}
diff --git a/src/ImageSharp/Processing/Processors/Convolution/EdgeDetectorCompassProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Convolution/EdgeDetectorCompassProcessor{TPixel}.cs
index 29178300e2..2764b0b3f7 100644
--- a/src/ImageSharp/Processing/Processors/Convolution/EdgeDetectorCompassProcessor{TPixel}.cs
+++ b/src/ImageSharp/Processing/Processors/Convolution/EdgeDetectorCompassProcessor{TPixel}.cs
@@ -1,12 +1,10 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
-using System;
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
-
-using SixLabors.ImageSharp.Advanced.ParallelUtils;
+using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing.Processors.Filters;
@@ -55,88 +53,79 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
{
DenseMatrix[] kernels = this.Kernels.Flatten();
- int startY = this.SourceRectangle.Y;
- int endY = this.SourceRectangle.Bottom;
- int startX = this.SourceRectangle.X;
- int endX = this.SourceRectangle.Right;
+ var interest = Rectangle.Intersect(this.SourceRectangle, source.Bounds());
- // Align start/end positions.
- int minX = Math.Max(0, startX);
- int maxX = Math.Min(source.Width, endX);
- int minY = Math.Max(0, startY);
- int maxY = Math.Min(source.Height, endY);
+ // We need a clean copy for each pass to start from
+ using ImageFrame cleanCopy = source.Clone();
- // we need a clean copy for each pass to start from
- using (ImageFrame cleanCopy = source.Clone())
+ using (var processor = new ConvolutionProcessor(this.Configuration, kernels[0], true, this.Source, interest))
{
- using (var processor = new ConvolutionProcessor(this.Configuration, kernels[0], true, this.Source, this.SourceRectangle))
- {
- processor.Apply(source);
- }
+ processor.Apply(source);
+ }
- if (kernels.Length == 1)
- {
- return;
- }
+ if (kernels.Length == 1)
+ {
+ return;
+ }
- int shiftY = startY;
- int shiftX = startX;
+ // Additional runs
+ for (int i = 1; i < kernels.Length; i++)
+ {
+ using ImageFrame pass = cleanCopy.Clone();
- // Reset offset if necessary.
- if (minX > 0)
+ using (var processor = new ConvolutionProcessor(this.Configuration, kernels[i], true, this.Source, interest))
{
- shiftX = 0;
+ processor.Apply(pass);
}
- if (minY > 0)
- {
- shiftY = 0;
- }
+ var operation = new RowIntervalOperation(source.PixelBuffer, pass.PixelBuffer, interest);
+ ParallelRowIterator.IterateRows(
+ this.Configuration,
+ interest,
+ in operation);
+ }
+ }
- var workingRect = Rectangle.FromLTRB(minX, minY, maxX, maxY);
+ ///
+ /// A implementing the convolution logic for .
+ ///
+ private readonly struct RowIntervalOperation : IRowIntervalOperation
+ {
+ private readonly Buffer2D targetPixels;
+ private readonly Buffer2D passPixels;
+ private readonly int minX;
+ private readonly int maxX;
+
+ [MethodImpl(InliningOptions.ShortMethod)]
+ public RowIntervalOperation(
+ Buffer2D targetPixels,
+ Buffer2D passPixels,
+ Rectangle bounds)
+ {
+ this.targetPixels = targetPixels;
+ this.passPixels = passPixels;
+ this.minX = bounds.X;
+ this.maxX = bounds.Right;
+ }
- // Additional runs.
- // ReSharper disable once ForCanBeConvertedToForeach
- for (int i = 1; i < kernels.Length; i++)
+ ///
+ [MethodImpl(InliningOptions.ShortMethod)]
+ public void Invoke(in RowInterval rows)
+ {
+ for (int y = rows.Min; y < rows.Max; y++)
{
- using (ImageFrame pass = cleanCopy.Clone())
+ ref TPixel passPixelsBase = ref MemoryMarshal.GetReference(this.passPixels.GetRowSpanUnchecked(y));
+ ref TPixel targetPixelsBase = ref MemoryMarshal.GetReference(this.targetPixels.GetRowSpanUnchecked(y));
+
+ for (int x = this.minX; x < this.maxX; x++)
{
- using (var processor = new ConvolutionProcessor(this.Configuration, kernels[i], true, this.Source, this.SourceRectangle))
- {
- processor.Apply(pass);
- }
-
- Buffer2D passPixels = pass.PixelBuffer;
- Buffer2D targetPixels = source.PixelBuffer;
-
- ParallelHelper.IterateRows(
- workingRect,
- this.Configuration,
- rows =>
- {
- for (int y = rows.Min; y < rows.Max; y++)
- {
- int offsetY = y - shiftY;
-
- ref TPixel passPixelsBase = ref MemoryMarshal.GetReference(passPixels.GetRowSpanUnchecked(offsetY));
- ref TPixel targetPixelsBase = ref MemoryMarshal.GetReference(targetPixels.GetRowSpanUnchecked(offsetY));
-
- for (int x = minX; x < maxX; x++)
- {
- int offsetX = x - shiftX;
-
- // Grab the max components of the two pixels
- ref TPixel currentPassPixel = ref Unsafe.Add(ref passPixelsBase, offsetX);
- ref TPixel currentTargetPixel = ref Unsafe.Add(ref targetPixelsBase, offsetX);
-
- var pixelValue = Vector4.Max(
- currentPassPixel.ToVector4(),
- currentTargetPixel.ToVector4());
-
- currentTargetPixel.FromVector4(pixelValue);
- }
- }
- });
+ // Grab the max components of the two pixels
+ ref TPixel currentPassPixel = ref Unsafe.Add(ref passPixelsBase, x);
+ ref TPixel currentTargetPixel = ref Unsafe.Add(ref targetPixelsBase, x);
+
+ var pixelValue = Vector4.Max(currentPassPixel.ToVector4(), currentTargetPixel.ToVector4());
+
+ currentTargetPixel.FromVector4(pixelValue);
}
}
}
diff --git a/src/ImageSharp/Processing/Processors/Convolution/GaussianBlurProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Convolution/GaussianBlurProcessor{TPixel}.cs
index 3c1f82caa8..3d0a7a714d 100644
--- a/src/ImageSharp/Processing/Processors/Convolution/GaussianBlurProcessor{TPixel}.cs
+++ b/src/ImageSharp/Processing/Processors/Convolution/GaussianBlurProcessor{TPixel}.cs
@@ -44,10 +44,9 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
///
protected override void OnFrameApply(ImageFrame source)
{
- using (var processor = new Convolution2PassProcessor(this.Configuration, this.KernelX, this.KernelY, false, this.Source, this.SourceRectangle))
- {
- processor.Apply(source);
- }
+ using var processor = new Convolution2PassProcessor(this.Configuration, this.KernelX, this.KernelY, false, this.Source, this.SourceRectangle);
+
+ processor.Apply(source);
}
}
}
diff --git a/src/ImageSharp/Processing/Processors/Convolution/GaussianSharpenProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Convolution/GaussianSharpenProcessor{TPixel}.cs
index f4f27a42de..506d34a3b8 100644
--- a/src/ImageSharp/Processing/Processors/Convolution/GaussianSharpenProcessor{TPixel}.cs
+++ b/src/ImageSharp/Processing/Processors/Convolution/GaussianSharpenProcessor{TPixel}.cs
@@ -44,10 +44,9 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
///
protected override void OnFrameApply(ImageFrame source)
{
- using (var processor = new Convolution2PassProcessor(this.Configuration, this.KernelX, this.KernelY, false, this.Source, this.SourceRectangle))
- {
- processor.Apply(source);
- }
+ using var processor = new Convolution2PassProcessor(this.Configuration, this.KernelX, this.KernelY, false, this.Source, this.SourceRectangle);
+
+ processor.Apply(source);
}
}
}
diff --git a/src/ImageSharp/Processing/Processors/Drawing/DrawImageProcessor{TPixelBg,TPixelFg}.cs b/src/ImageSharp/Processing/Processors/Drawing/DrawImageProcessor{TPixelBg,TPixelFg}.cs
index a8b9093e5e..c1ce30cae1 100644
--- a/src/ImageSharp/Processing/Processors/Drawing/DrawImageProcessor{TPixelBg,TPixelFg}.cs
+++ b/src/ImageSharp/Processing/Processors/Drawing/DrawImageProcessor{TPixelBg,TPixelFg}.cs
@@ -2,9 +2,9 @@
// Licensed under the Apache License, Version 2.0.
using System;
-
+using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.Advanced;
-using SixLabors.ImageSharp.Advanced.ParallelUtils;
+using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Processing.Processors.Drawing
@@ -99,18 +99,62 @@ namespace SixLabors.ImageSharp.Processing.Processors.Drawing
"Cannot draw image because the source image does not overlap the target image.");
}
- ParallelHelper.IterateRows(
- workingRect,
+ var operation = new RowIntervalOperation(source, targetImage, blender, configuration, minX, width, locationY, targetX, this.Opacity);
+ ParallelRowIterator.IterateRows(
configuration,
- rows =>
+ workingRect,
+ in operation);
+ }
+
+ ///
+ /// A implementing the draw logic for .
+ ///
+ private readonly struct RowIntervalOperation : IRowIntervalOperation
+ {
+ private readonly ImageFrame sourceFrame;
+ private readonly Image targetImage;
+ private readonly PixelBlender blender;
+ private readonly Configuration configuration;
+ private readonly int minX;
+ private readonly int width;
+ private readonly int locationY;
+ private readonly int targetX;
+ private readonly float opacity;
+
+ [MethodImpl(InliningOptions.ShortMethod)]
+ public RowIntervalOperation(
+ ImageFrame sourceFrame,
+ Image targetImage,
+ PixelBlender blender,
+ Configuration configuration,
+ int minX,
+ int width,
+ int locationY,
+ int targetX,
+ float opacity)
+ {
+ this.sourceFrame = sourceFrame;
+ this.targetImage = targetImage;
+ this.blender = blender;
+ this.configuration = configuration;
+ this.minX = minX;
+ this.width = width;
+ this.locationY = locationY;
+ this.targetX = targetX;
+ this.opacity = opacity;
+ }
+
+ ///
+ [MethodImpl(InliningOptions.ShortMethod)]
+ public void Invoke(in RowInterval rows)
+ {
+ for (int y = rows.Min; y < rows.Max; y++)
{
- for (int y = rows.Min; y < rows.Max; y++)
- {
- Span background = source.GetPixelRowSpan(y).Slice(minX, width);
- Span foreground = targetImage.GetPixelRowSpan(y - locationY).Slice(targetX, width);
- blender.Blend(configuration, background, background, foreground, this.Opacity);
- }
- });
+ Span background = this.sourceFrame.GetPixelRowSpan(y).Slice(this.minX, this.width);
+ Span foreground = this.targetImage.GetPixelRowSpan(y - this.locationY).Slice(this.targetX, this.width);
+ this.blender.Blend(this.configuration, background, background, foreground, this.opacity);
+ }
+ }
}
}
}
diff --git a/src/ImageSharp/Processing/Processors/Effects/IPixelRowDelegate.cs b/src/ImageSharp/Processing/Processors/Effects/IPixelRowDelegate.cs
new file mode 100644
index 0000000000..626ffd7168
--- /dev/null
+++ b/src/ImageSharp/Processing/Processors/Effects/IPixelRowDelegate.cs
@@ -0,0 +1,21 @@
+// Copyright (c) Six Labors and contributors.
+// Licensed under the Apache License, Version 2.0.
+
+using System;
+using System.Numerics;
+
+namespace SixLabors.ImageSharp.Processing.Processors.Effects
+{
+ ///
+ /// An used by the row delegates for a given instance
+ ///
+ public interface IPixelRowDelegate
+ {
+ ///
+ /// Applies the current pixel row delegate to a target row of preprocessed pixels.
+ ///
+ /// The target row of pixels to process.
+ /// The initial horizontal and vertical offset for the input pixels to process.
+ void Invoke(Span span, Point offset);
+ }
+}
diff --git a/src/ImageSharp/Processing/Processors/Effects/OilPaintingProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Effects/OilPaintingProcessor{TPixel}.cs
index 049fb6d02b..9bf18671a3 100644
--- a/src/ImageSharp/Processing/Processors/Effects/OilPaintingProcessor{TPixel}.cs
+++ b/src/ImageSharp/Processing/Processors/Effects/OilPaintingProcessor{TPixel}.cs
@@ -5,9 +5,7 @@ using System;
using System.Buffers;
using System.Numerics;
using System.Runtime.CompilerServices;
-
using SixLabors.ImageSharp.Advanced;
-using SixLabors.ImageSharp.Advanced.ParallelUtils;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
@@ -45,122 +43,145 @@ namespace SixLabors.ImageSharp.Processing.Processors.Effects
throw new ArgumentOutOfRangeException(nameof(brushSize));
}
- int startY = this.SourceRectangle.Y;
- int endY = this.SourceRectangle.Bottom;
- int startX = this.SourceRectangle.X;
- int endX = this.SourceRectangle.Right;
- int maxY = endY - 1;
- int maxX = endX - 1;
-
- int radius = brushSize >> 1;
- int levels = this.definition.Levels;
- int rowWidth = source.Width;
- int rectangleWidth = this.SourceRectangle.Width;
-
- Configuration configuration = this.Configuration;
-
using Buffer2D targetPixels = this.Configuration.MemoryAllocator.Allocate2D(source.Size());
+
source.CopyTo(targetPixels);
- var workingRect = Rectangle.FromLTRB(startX, startY, endX, endY);
- ParallelHelper.IterateRows(
- workingRect,
+ var operation = new RowIntervalOperation(this.SourceRectangle, targetPixels, source, this.Configuration, brushSize >> 1, this.definition.Levels);
+ ParallelRowIterator.IterateRows(
this.Configuration,
- (rows) =>
- {
- /* Allocate the two temporary Vector4 buffers, one for the source row and one for the target row.
- * The ParallelHelper.IterateRowsWithTempBuffers overload is not used in this case because
- * the two allocated buffers have a length equal to the width of the source image,
- * and not just equal to the width of the target rectangle to process.
- * Furthermore, there are two buffers being allocated in this case, so using that overload would
- * have still required the explicit allocation of the secondary buffer.
- * Similarly, one temporary float buffer is also allocated from the pool, and that is used
- * to create the target bins for all the color channels being processed.
- * This buffer is only rented once outside of the main processing loop, and its contents
- * are cleared for each loop iteration, to avoid the repeated allocation for each processed pixel. */
- using (IMemoryOwner sourceRowBuffer = configuration.MemoryAllocator.Allocate(rowWidth))
- using (IMemoryOwner targetRowBuffer = configuration.MemoryAllocator.Allocate(rowWidth))
- using (IMemoryOwner bins = configuration.MemoryAllocator.Allocate(levels * 4))
- {
- Span sourceRowVector4Span = sourceRowBuffer.Memory.Span;
- Span sourceRowAreaVector4Span = sourceRowVector4Span.Slice(startX, rectangleWidth);
+ this.SourceRectangle,
+ in operation);
- Span targetRowVector4Span = targetRowBuffer.Memory.Span;
- Span targetRowAreaVector4Span = targetRowVector4Span.Slice(startX, rectangleWidth);
-
- ref float binsRef = ref bins.GetReference();
- ref int intensityBinRef = ref Unsafe.As(ref binsRef);
- ref float redBinRef = ref Unsafe.Add(ref binsRef, levels);
- ref float blueBinRef = ref Unsafe.Add(ref redBinRef, levels);
- ref float greenBinRef = ref Unsafe.Add(ref blueBinRef, levels);
-
- for (int y = rows.Min; y < rows.Max; y++)
- {
- Span sourceRowPixelSpan = source.GetPixelRowSpan(y);
- Span sourceRowAreaPixelSpan = sourceRowPixelSpan.Slice(startX, rectangleWidth);
+ Buffer2D.SwapOrCopyContent(source.PixelBuffer, targetPixels);
+ }
- PixelOperations.Instance.ToVector4(configuration, sourceRowAreaPixelSpan, sourceRowAreaVector4Span);
+ ///
+ /// A implementing the convolution logic for .
+ ///
+ private readonly struct RowIntervalOperation : IRowIntervalOperation
+ {
+ private readonly Rectangle bounds;
+ private readonly Buffer2D targetPixels;
+ private readonly ImageFrame source;
+ private readonly Configuration configuration;
+ private readonly int radius;
+ private readonly int levels;
+
+ [MethodImpl(InliningOptions.ShortMethod)]
+ public RowIntervalOperation(
+ Rectangle bounds,
+ Buffer2D targetPixels,
+ ImageFrame source,
+ Configuration configuration,
+ int radius,
+ int levels)
+ {
+ this.bounds = bounds;
+ this.targetPixels = targetPixels;
+ this.source = source;
+ this.configuration = configuration;
+ this.radius = radius;
+ this.levels = levels;
+ }
- for (int x = startX; x < endX; x++)
- {
- int maxIntensity = 0;
- int maxIndex = 0;
+ ///
+ [MethodImpl(InliningOptions.ShortMethod)]
+ public void Invoke(in RowInterval rows)
+ {
+ int maxY = this.bounds.Bottom - 1;
+ int maxX = this.bounds.Right - 1;
+
+ /* Allocate the two temporary Vector4 buffers, one for the source row and one for the target row.
+ * The ParallelHelper.IterateRowsWithTempBuffers overload is not used in this case because
+ * the two allocated buffers have a length equal to the width of the source image,
+ * and not just equal to the width of the target rectangle to process.
+ * Furthermore, there are two buffers being allocated in this case, so using that overload would
+ * have still required the explicit allocation of the secondary buffer.
+ * Similarly, one temporary float buffer is also allocated from the pool, and that is used
+ * to create the target bins for all the color channels being processed.
+ * This buffer is only rented once outside of the main processing loop, and its contents
+ * are cleared for each loop iteration, to avoid the repeated allocation for each processed pixel. */
+ using IMemoryOwner sourceRowBuffer = this.configuration.MemoryAllocator.Allocate(this.source.Width);
+ using IMemoryOwner targetRowBuffer = this.configuration.MemoryAllocator.Allocate