Browse Source

Merge pull request #908 from SixLabors/af/general-color-type

Introduce representation-agnostic Color type
af/merge-core
Anton Firsov 7 years ago
committed by GitHub
parent
commit
806839256a
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 1
      ImageSharp.sln.DotSettings
  2. 2
      src/ImageSharp/Advanced/AotCompilerTools.cs
  3. 83
      src/ImageSharp/Color/Color.Conversions.cs
  4. 721
      src/ImageSharp/Color/Color.NamedColors.cs
  5. 166
      src/ImageSharp/Color/Color.WebSafePalette.cs
  6. 135
      src/ImageSharp/Color/Color.WernerPalette.cs
  7. 218
      src/ImageSharp/Color/Color.cs
  8. 9
      src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs
  9. 29
      src/ImageSharp/Formats/Gif/GifEncoderCore.cs
  10. 6
      src/ImageSharp/Formats/Gif/LzwEncoder.cs
  11. 12
      src/ImageSharp/Formats/Png/PngEncoderCore.cs
  12. 2
      src/ImageSharp/ImageSharp.csproj.DotSettings
  13. 4
      src/ImageSharp/PixelFormats/ColorBuilder{TPixel}.cs
  14. 284
      src/ImageSharp/PixelFormats/NamedColors{TPixel}.cs
  15. 16
      src/ImageSharp/PixelFormats/PixelImplementations/Argb32.cs
  16. 16
      src/ImageSharp/PixelFormats/PixelImplementations/Bgr24.cs
  17. 16
      src/ImageSharp/PixelFormats/PixelImplementations/Bgra32.cs
  18. 16
      src/ImageSharp/PixelFormats/PixelImplementations/Rgb24.cs
  19. 16
      src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.cs
  20. 166
      src/ImageSharp/PixelFormats/PixelImplementations/Rgba64.cs
  21. 2
      src/ImageSharp/Primitives/ValueSize.cs
  22. 78
      src/ImageSharp/Processing/DitherExtensions.cs
  23. 0
      src/ImageSharp/Processing/Extensions/AutoOrientExtensions.cs
  24. 45
      src/ImageSharp/Processing/Extensions/BackgroundColorExtensions.cs
  25. 47
      src/ImageSharp/Processing/Extensions/BinaryDiffuseExtensions.cs
  26. 40
      src/ImageSharp/Processing/Extensions/BinaryDitherExtensions.cs
  27. 49
      src/ImageSharp/Processing/Extensions/BinaryThresholdExtensions.cs
  28. 0
      src/ImageSharp/Processing/Extensions/BlackWhiteExtensions.cs
  29. 0
      src/ImageSharp/Processing/Extensions/BoxBlurExtensions.cs
  30. 0
      src/ImageSharp/Processing/Extensions/BrightnessExtensions.cs
  31. 0
      src/ImageSharp/Processing/Extensions/ColorBlindnessExtensions.cs
  32. 0
      src/ImageSharp/Processing/Extensions/ContrastExtensions.cs
  33. 0
      src/ImageSharp/Processing/Extensions/CropExtensions.cs
  34. 0
      src/ImageSharp/Processing/Extensions/DetectEdgesExtensions.cs
  35. 69
      src/ImageSharp/Processing/Extensions/DiffuseExtensions.cs
  36. 79
      src/ImageSharp/Processing/Extensions/DitherExtensions.cs
  37. 0
      src/ImageSharp/Processing/Extensions/EntropyCropExtensions.cs
  38. 0
      src/ImageSharp/Processing/Extensions/FilterExtensions.cs
  39. 0
      src/ImageSharp/Processing/Extensions/FlipExtensions.cs
  40. 0
      src/ImageSharp/Processing/Extensions/GaussianBlurExtensions.cs
  41. 0
      src/ImageSharp/Processing/Extensions/GaussianSharpenExtensions.cs
  42. 98
      src/ImageSharp/Processing/Extensions/GlowExtensions.cs
  43. 0
      src/ImageSharp/Processing/Extensions/GrayscaleExtensions.cs
  44. 2
      src/ImageSharp/Processing/Extensions/HistogramEqualizationExtensions.cs
  45. 0
      src/ImageSharp/Processing/Extensions/HueExtensions.cs
  46. 0
      src/ImageSharp/Processing/Extensions/InvertExtensions.cs
  47. 0
      src/ImageSharp/Processing/Extensions/KodachromeExtensions.cs
  48. 0
      src/ImageSharp/Processing/Extensions/LomographExtensions.cs
  49. 0
      src/ImageSharp/Processing/Extensions/OilPaintExtensions.cs
  50. 0
      src/ImageSharp/Processing/Extensions/OpacityExtensions.cs
  51. 0
      src/ImageSharp/Processing/Extensions/PadExtensions.cs
  52. 0
      src/ImageSharp/Processing/Extensions/PixelateExtensions.cs
  53. 0
      src/ImageSharp/Processing/Extensions/PolaroidExtensions.cs
  54. 0
      src/ImageSharp/Processing/Extensions/ProcessingExtensions.cs
  55. 0
      src/ImageSharp/Processing/Extensions/QuantizeExtensions.cs
  56. 0
      src/ImageSharp/Processing/Extensions/ResizeExtensions.cs
  57. 0
      src/ImageSharp/Processing/Extensions/RotateExtensions.cs
  58. 0
      src/ImageSharp/Processing/Extensions/RotateFlipExtensions.cs
  59. 0
      src/ImageSharp/Processing/Extensions/SaturateExtensions.cs
  60. 0
      src/ImageSharp/Processing/Extensions/SepiaExtensions.cs
  61. 0
      src/ImageSharp/Processing/Extensions/SkewExtensions.cs
  62. 0
      src/ImageSharp/Processing/Extensions/TransformExtensions.cs
  63. 121
      src/ImageSharp/Processing/Extensions/VignetteExtensions.cs
  64. 68
      src/ImageSharp/Processing/Processors/Binarization/BinaryErrorDiffusionProcessor.cs
  65. 77
      src/ImageSharp/Processing/Processors/Binarization/BinaryErrorDiffusionProcessor{TPixel}.cs
  66. 66
      src/ImageSharp/Processing/Processors/Binarization/BinaryOrderedDitherProcessor.cs
  67. 75
      src/ImageSharp/Processing/Processors/Binarization/BinaryOrderedDitherProcessor{TPixel}.cs
  68. 67
      src/ImageSharp/Processing/Processors/Binarization/BinaryThresholdProcessor.cs
  69. 70
      src/ImageSharp/Processing/Processors/Binarization/BinaryThresholdProcessor{TPixel}.cs
  70. 2
      src/ImageSharp/Processing/Processors/Convolution/EdgeDetector2DProcessor{TPixel}.cs
  71. 2
      src/ImageSharp/Processing/Processors/Convolution/EdgeDetectorCompassProcessor{TPixel}.cs
  72. 2
      src/ImageSharp/Processing/Processors/Convolution/EdgeDetectorProcessor{TPixel}.cs
  73. 8
      src/ImageSharp/Processing/Processors/Convolution/SobelProcessor.cs
  74. 77
      src/ImageSharp/Processing/Processors/Dithering/ErrorDiffusionPaletteProcessor.cs
  75. 81
      src/ImageSharp/Processing/Processors/Dithering/ErrorDiffusionPaletteProcessor{TPixel}.cs
  76. 70
      src/ImageSharp/Processing/Processors/Dithering/OrderedDitherPaletteProcessor.cs
  77. 79
      src/ImageSharp/Processing/Processors/Dithering/OrderedDitherPaletteProcessor{TPixel}.cs
  78. 33
      src/ImageSharp/Processing/Processors/Dithering/PaletteDitherProcessor.cs
  79. 62
      src/ImageSharp/Processing/Processors/Dithering/PaletteDitherProcessor{TPixel}.cs
  80. 8
      src/ImageSharp/Processing/Processors/Filters/GrayscaleBt709Processor.cs
  81. 4
      src/ImageSharp/Processing/Processors/Filters/LomographProcessor{TPixel}.cs
  82. 14
      src/ImageSharp/Processing/Processors/Filters/PolaroidProcessor{TPixel}.cs
  83. 15
      src/ImageSharp/Processing/Processors/ImageProcessorExtensions.cs
  84. 86
      src/ImageSharp/Processing/Processors/Overlays/BackgroundColorProcessor.cs
  85. 101
      src/ImageSharp/Processing/Processors/Overlays/BackgroundColorProcessor{TPixel}.cs
  86. 126
      src/ImageSharp/Processing/Processors/Overlays/GlowProcessor.cs
  87. 112
      src/ImageSharp/Processing/Processors/Overlays/GlowProcessor{TPixel}.cs
  88. 120
      src/ImageSharp/Processing/Processors/Overlays/VignetteProcessor.cs
  89. 114
      src/ImageSharp/Processing/Processors/Overlays/VignetteProcessor{TPixel}.cs
  90. 112
      src/ImageSharp/Processing/Processors/Quantization/FrameQuantizer{TPixel}.cs
  91. 2
      src/ImageSharp/Processing/Processors/Quantization/IFrameQuantizer{TPixel}.cs
  92. 38
      src/ImageSharp/Processing/Processors/Quantization/IQuantizedFrame{TPixel}.cs
  93. 6
      src/ImageSharp/Processing/Processors/Quantization/OctreeFrameQuantizer{TPixel}.cs
  94. 13
      src/ImageSharp/Processing/Processors/Quantization/PaletteFrameQuantizer{TPixel}.cs
  95. 59
      src/ImageSharp/Processing/Processors/Quantization/PaletteQuantizer.cs
  96. 110
      src/ImageSharp/Processing/Processors/Quantization/PaletteQuantizer{TPixel}.cs
  97. 9
      src/ImageSharp/Processing/Processors/Quantization/QuantizeProcessor{TPixel}.cs
  98. 29
      src/ImageSharp/Processing/Processors/Quantization/QuantizedFrameExtensions.cs
  99. 23
      src/ImageSharp/Processing/Processors/Quantization/QuantizedFrame{TPixel}.cs
  100. 13
      src/ImageSharp/Processing/Processors/Quantization/WebSafePaletteQuantizer.cs

1
ImageSharp.sln.DotSettings

@ -388,5 +388,6 @@
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002ECSharpPlaceAttributeOnSameLineMigration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EMigrateBlankLinesAroundFieldToBlankLinesAroundProperty/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EMigrateThisQualifierSettings/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Bgra/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Quantizer/@EntryIndexedValue">True</s:Boolean>
</wpf:ResourceDictionary>

2
src/ImageSharp/Advanced/AotCompilerTools.cs

@ -104,7 +104,7 @@ namespace SixLabors.ImageSharp.Advanced
private static void AotCompileWuQuantizer<TPixel>()
where TPixel : struct, IPixel<TPixel>
{
var test = new WuFrameQuantizer<TPixel>(new WuQuantizer(false));
var test = new WuFrameQuantizer<TPixel>(Configuration.Default.MemoryAllocator, new WuQuantizer(false));
test.QuantizeFrame(new ImageFrame<TPixel>(Configuration.Default, 1, 1));
test.AotGetPalette();
}

83
src/ImageSharp/Color/Color.Conversions.cs

@ -0,0 +1,83 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System.Numerics;
using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp
{
/// <content>
/// Contains constructors and implicit conversion methods.
/// </content>
public readonly partial struct Color
{
/// <summary>
/// Initializes a new instance of the <see cref="Color"/> struct.
/// </summary>
/// <param name="pixel">The <see cref="Rgba64"/> containing the color information.</param>
[MethodImpl(InliningOptions.ShortMethod)]
public Color(Rgba64 pixel) => this.data = pixel;
/// <summary>
/// Initializes a new instance of the <see cref="Color"/> struct.
/// </summary>
/// <param name="pixel">The <see cref="Rgba32"/> containing the color information.</param>
[MethodImpl(InliningOptions.ShortMethod)]
public Color(Rgba32 pixel) => this.data = new Rgba64(pixel);
/// <summary>
/// Initializes a new instance of the <see cref="Color"/> struct.
/// </summary>
/// <param name="pixel">The <see cref="Argb32"/> containing the color information.</param>
[MethodImpl(InliningOptions.ShortMethod)]
public Color(Argb32 pixel) => this.data = new Rgba64(pixel);
/// <summary>
/// Initializes a new instance of the <see cref="Color"/> struct.
/// </summary>
/// <param name="pixel">The <see cref="Bgra32"/> containing the color information.</param>
[MethodImpl(InliningOptions.ShortMethod)]
public Color(Bgra32 pixel) => this.data = new Rgba64(pixel);
/// <summary>
/// Initializes a new instance of the <see cref="Color"/> struct.
/// </summary>
/// <param name="pixel">The <see cref="Rgb24"/> containing the color information.</param>
[MethodImpl(InliningOptions.ShortMethod)]
public Color(Rgb24 pixel) => this.data = new Rgba64(pixel);
/// <summary>
/// Initializes a new instance of the <see cref="Color"/> struct.
/// </summary>
/// <param name="pixel">The <see cref="Bgr24"/> containing the color information.</param>
[MethodImpl(InliningOptions.ShortMethod)]
public Color(Bgr24 pixel) => this.data = new Rgba64(pixel);
/// <summary>
/// Initializes a new instance of the <see cref="Color"/> struct.
/// </summary>
/// <param name="vector">The <see cref="Vector4"/> containing the color information.</param>
[MethodImpl(InliningOptions.ShortMethod)]
public Color(Vector4 vector) => this.data = new Rgba64(vector);
[MethodImpl(InliningOptions.ShortMethod)]
internal Rgba64 ToRgba64() => this.data;
[MethodImpl(InliningOptions.ShortMethod)]
internal Rgba32 ToRgba32() => this.data.ToRgba32();
[MethodImpl(InliningOptions.ShortMethod)]
internal Bgra32 ToBgra32() => this.data.ToBgra32();
[MethodImpl(InliningOptions.ShortMethod)]
internal Argb32 ToArgb32() => this.data.ToArgb32();
[MethodImpl(InliningOptions.ShortMethod)]
internal Rgb24 ToRgb24() => this.data.ToRgb24();
[MethodImpl(InliningOptions.ShortMethod)]
internal Bgr24 ToBgr24() => this.data.ToBgr24();
}
}

721
src/ImageSharp/Color/Color.NamedColors.cs

@ -0,0 +1,721 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
namespace SixLabors.ImageSharp
{
/// <content>
/// Contains static named color values.
/// </content>
public readonly partial struct Color
{
/// <summary>
/// Represents a <see paramref="Color"/> matching the W3C definition that has an hex value of #F0F8FF.
/// </summary>
public static readonly Color AliceBlue = FromRgba(240, 248, 255, 255);
/// <summary>
/// Represents a <see paramref="Color"/> matching the W3C definition that has an hex value of #FAEBD7.
/// </summary>
public static readonly Color AntiqueWhite = FromRgba(250, 235, 215, 255);
/// <summary>
/// Represents a <see paramref="Color"/> matching the W3C definition that has an hex value of #00FFFF.
/// </summary>
public static readonly Color Aqua = FromRgba(0, 255, 255, 255);
/// <summary>
/// Represents a <see paramref="Color"/> matching the W3C definition that has an hex value of #7FFFD4.
/// </summary>
public static readonly Color Aquamarine = FromRgba(127, 255, 212, 255);
/// <summary>
/// Represents a <see paramref="Color"/> matching the W3C definition that has an hex value of #F0FFFF.
/// </summary>
public static readonly Color Azure = FromRgba(240, 255, 255, 255);
/// <summary>
/// Represents a <see paramref="Color"/> matching the W3C definition that has an hex value of #F5F5DC.
/// </summary>
public static readonly Color Beige = FromRgba(245, 245, 220, 255);
/// <summary>
/// Represents a <see paramref="Color"/> matching the W3C definition that has an hex value of #FFE4C4.
/// </summary>
public static readonly Color Bisque = FromRgba(255, 228, 196, 255);
/// <summary>
/// Represents a <see paramref="Color"/> matching the W3C definition that has an hex value of #000000.
/// </summary>
public static readonly Color Black = FromRgba(0, 0, 0, 255);
/// <summary>
/// Represents a <see paramref="Color"/> matching the W3C definition that has an hex value of #FFEBCD.
/// </summary>
public static readonly Color BlanchedAlmond = FromRgba(255, 235, 205, 255);
/// <summary>
/// Represents a <see paramref="Color"/> matching the W3C definition that has an hex value of #0000FF.
/// </summary>
public static readonly Color Blue = FromRgba(0, 0, 255, 255);
/// <summary>
/// Represents a <see paramref="Color"/> matching the W3C definition that has an hex value of #8A2BE2.
/// </summary>
public static readonly Color BlueViolet = FromRgba(138, 43, 226, 255);
/// <summary>
/// Represents a <see paramref="Color"/> matching the W3C definition that has an hex value of #A52A2A.
/// </summary>
public static readonly Color Brown = FromRgba(165, 42, 42, 255);
/// <summary>
/// Represents a <see paramref="Color"/> matching the W3C definition that has an hex value of #DEB887.
/// </summary>
public static readonly Color BurlyWood = FromRgba(222, 184, 135, 255);
/// <summary>
/// Represents a <see paramref="Color"/> matching the W3C definition that has an hex value of #5F9EA0.
/// </summary>
public static readonly Color CadetBlue = FromRgba(95, 158, 160, 255);
/// <summary>
/// Represents a <see paramref="Color"/> matching the W3C definition that has an hex value of #7FFF00.
/// </summary>
public static readonly Color Chartreuse = FromRgba(127, 255, 0, 255);
/// <summary>
/// Represents a <see paramref="Color"/> matching the W3C definition that has an hex value of #D2691E.
/// </summary>
public static readonly Color Chocolate = FromRgba(210, 105, 30, 255);
/// <summary>
/// Represents a <see paramref="Color"/> matching the W3C definition that has an hex value of #FF7F50.
/// </summary>
public static readonly Color Coral = FromRgba(255, 127, 80, 255);
/// <summary>
/// Represents a <see paramref="Color"/> matching the W3C definition that has an hex value of #6495ED.
/// </summary>
public static readonly Color CornflowerBlue = FromRgba(100, 149, 237, 255);
/// <summary>
/// Represents a <see paramref="Color"/> matching the W3C definition that has an hex value of #FFF8DC.
/// </summary>
public static readonly Color Cornsilk = FromRgba(255, 248, 220, 255);
/// <summary>
/// Represents a <see paramref="Color"/> matching the W3C definition that has an hex value of #DC143C.
/// </summary>
public static readonly Color Crimson = FromRgba(220, 20, 60, 255);
/// <summary>
/// Represents a <see paramref="Color"/> matching the W3C definition that has an hex value of #00FFFF.
/// </summary>
public static readonly Color Cyan = FromRgba(0, 255, 255, 255);
/// <summary>
/// Represents a <see paramref="Color"/> matching the W3C definition that has an hex value of #00008B.
/// </summary>
public static readonly Color DarkBlue = FromRgba(0, 0, 139, 255);
/// <summary>
/// Represents a <see paramref="Color"/> matching the W3C definition that has an hex value of #008B8B.
/// </summary>
public static readonly Color DarkCyan = FromRgba(0, 139, 139, 255);
/// <summary>
/// Represents a <see paramref="Color"/> matching the W3C definition that has an hex value of #B8860B.
/// </summary>
public static readonly Color DarkGoldenrod = FromRgba(184, 134, 11, 255);
/// <summary>
/// Represents a <see paramref="Color"/> matching the W3C definition that has an hex value of #A9A9A9.
/// </summary>
public static readonly Color DarkGray = FromRgba(169, 169, 169, 255);
/// <summary>
/// Represents a <see paramref="Color"/> matching the W3C definition that has an hex value of #006400.
/// </summary>
public static readonly Color DarkGreen = FromRgba(0, 100, 0, 255);
/// <summary>
/// Represents a <see paramref="Color"/> matching the W3C definition that has an hex value of #BDB76B.
/// </summary>
public static readonly Color DarkKhaki = FromRgba(189, 183, 107, 255);
/// <summary>
/// Represents a <see paramref="Color"/> matching the W3C definition that has an hex value of #8B008B.
/// </summary>
public static readonly Color DarkMagenta = FromRgba(139, 0, 139, 255);
/// <summary>
/// Represents a <see paramref="Color"/> matching the W3C definition that has an hex value of #556B2F.
/// </summary>
public static readonly Color DarkOliveGreen = FromRgba(85, 107, 47, 255);
/// <summary>
/// Represents a <see paramref="Color"/> matching the W3C definition that has an hex value of #FF8C00.
/// </summary>
public static readonly Color DarkOrange = FromRgba(255, 140, 0, 255);
/// <summary>
/// Represents a <see paramref="Color"/> matching the W3C definition that has an hex value of #9932CC.
/// </summary>
public static readonly Color DarkOrchid = FromRgba(153, 50, 204, 255);
/// <summary>
/// Represents a <see paramref="Color"/> matching the W3C definition that has an hex value of #8B0000.
/// </summary>
public static readonly Color DarkRed = FromRgba(139, 0, 0, 255);
/// <summary>
/// Represents a <see paramref="Color"/> matching the W3C definition that has an hex value of #E9967A.
/// </summary>
public static readonly Color DarkSalmon = FromRgba(233, 150, 122, 255);
/// <summary>
/// Represents a <see paramref="Color"/> matching the W3C definition that has an hex value of #8FBC8B.
/// </summary>
public static readonly Color DarkSeaGreen = FromRgba(143, 188, 139, 255);
/// <summary>
/// Represents a <see paramref="Color"/> matching the W3C definition that has an hex value of #483D8B.
/// </summary>
public static readonly Color DarkSlateBlue = FromRgba(72, 61, 139, 255);
/// <summary>
/// Represents a <see paramref="Color"/> matching the W3C definition that has an hex value of #2F4F4F.
/// </summary>
public static readonly Color DarkSlateGray = FromRgba(47, 79, 79, 255);
/// <summary>
/// Represents a <see paramref="Color"/> matching the W3C definition that has an hex value of #00CED1.
/// </summary>
public static readonly Color DarkTurquoise = FromRgba(0, 206, 209, 255);
/// <summary>
/// Represents a <see paramref="Color"/> matching the W3C definition that has an hex value of #9400D3.
/// </summary>
public static readonly Color DarkViolet = FromRgba(148, 0, 211, 255);
/// <summary>
/// Represents a <see paramref="Color"/> matching the W3C definition that has an hex value of #FF1493.
/// </summary>
public static readonly Color DeepPink = FromRgba(255, 20, 147, 255);
/// <summary>
/// Represents a <see paramref="Color"/> matching the W3C definition that has an hex value of #00BFFF.
/// </summary>
public static readonly Color DeepSkyBlue = FromRgba(0, 191, 255, 255);
/// <summary>
/// Represents a <see paramref="Color"/> matching the W3C definition that has an hex value of #696969.
/// </summary>
public static readonly Color DimGray = FromRgba(105, 105, 105, 255);
/// <summary>
/// Represents a <see paramref="Color"/> matching the W3C definition that has an hex value of #1E90FF.
/// </summary>
public static readonly Color DodgerBlue = FromRgba(30, 144, 255, 255);
/// <summary>
/// Represents a <see paramref="Color"/> matching the W3C definition that has an hex value of #B22222.
/// </summary>
public static readonly Color Firebrick = FromRgba(178, 34, 34, 255);
/// <summary>
/// Represents a <see paramref="Color"/> matching the W3C definition that has an hex value of #FFFAF0.
/// </summary>
public static readonly Color FloralWhite = FromRgba(255, 250, 240, 255);
/// <summary>
/// Represents a <see paramref="Color"/> matching the W3C definition that has an hex value of #228B22.
/// </summary>
public static readonly Color ForestGreen = FromRgba(34, 139, 34, 255);
/// <summary>
/// Represents a <see paramref="Color"/> matching the W3C definition that has an hex value of #FF00FF.
/// </summary>
public static readonly Color Fuchsia = FromRgba(255, 0, 255, 255);
/// <summary>
/// Represents a <see paramref="Color"/> matching the W3C definition that has an hex value of #DCDCDC.
/// </summary>
public static readonly Color Gainsboro = FromRgba(220, 220, 220, 255);
/// <summary>
/// Represents a <see paramref="Color"/> matching the W3C definition that has an hex value of #F8F8FF.
/// </summary>
public static readonly Color GhostWhite = FromRgba(248, 248, 255, 255);
/// <summary>
/// Represents a <see paramref="Color"/> matching the W3C definition that has an hex value of #FFD700.
/// </summary>
public static readonly Color Gold = FromRgba(255, 215, 0, 255);
/// <summary>
/// Represents a <see paramref="Color"/> matching the W3C definition that has an hex value of #DAA520.
/// </summary>
public static readonly Color Goldenrod = FromRgba(218, 165, 32, 255);
/// <summary>
/// Represents a <see paramref="Color"/> matching the W3C definition that has an hex value of #808080.
/// </summary>
public static readonly Color Gray = FromRgba(128, 128, 128, 255);
/// <summary>
/// Represents a <see paramref="Color"/> matching the W3C definition that has an hex value of #008000.
/// </summary>
public static readonly Color Green = FromRgba(0, 128, 0, 255);
/// <summary>
/// Represents a <see paramref="Color"/> matching the W3C definition that has an hex value of #ADFF2F.
/// </summary>
public static readonly Color GreenYellow = FromRgba(173, 255, 47, 255);
/// <summary>
/// Represents a <see paramref="Color"/> matching the W3C definition that has an hex value of #F0FFF0.
/// </summary>
public static readonly Color Honeydew = FromRgba(240, 255, 240, 255);
/// <summary>
/// Represents a <see paramref="Color"/> matching the W3C definition that has an hex value of #FF69B4.
/// </summary>
public static readonly Color HotPink = FromRgba(255, 105, 180, 255);
/// <summary>
/// Represents a <see paramref="Color"/> matching the W3C definition that has an hex value of #CD5C5C.
/// </summary>
public static readonly Color IndianRed = FromRgba(205, 92, 92, 255);
/// <summary>
/// Represents a <see paramref="Color"/> matching the W3C definition that has an hex value of #4B0082.
/// </summary>
public static readonly Color Indigo = FromRgba(75, 0, 130, 255);
/// <summary>
/// Represents a <see paramref="Color"/> matching the W3C definition that has an hex value of #FFFFF0.
/// </summary>
public static readonly Color Ivory = FromRgba(255, 255, 240, 255);
/// <summary>
/// Represents a <see paramref="Color"/> matching the W3C definition that has an hex value of #F0E68C.
/// </summary>
public static readonly Color Khaki = FromRgba(240, 230, 140, 255);
/// <summary>
/// Represents a <see paramref="Color"/> matching the W3C definition that has an hex value of #E6E6FA.
/// </summary>
public static readonly Color Lavender = FromRgba(230, 230, 250, 255);
/// <summary>
/// Represents a <see paramref="Color"/> matching the W3C definition that has an hex value of #FFF0F5.
/// </summary>
public static readonly Color LavenderBlush = FromRgba(255, 240, 245, 255);
/// <summary>
/// Represents a <see paramref="Color"/> matching the W3C definition that has an hex value of #7CFC00.
/// </summary>
public static readonly Color LawnGreen = FromRgba(124, 252, 0, 255);
/// <summary>
/// Represents a <see paramref="Color"/> matching the W3C definition that has an hex value of #FFFACD.
/// </summary>
public static readonly Color LemonChiffon = FromRgba(255, 250, 205, 255);
/// <summary>
/// Represents a <see paramref="Color"/> matching the W3C definition that has an hex value of #ADD8E6.
/// </summary>
public static readonly Color LightBlue = FromRgba(173, 216, 230, 255);
/// <summary>
/// Represents a <see paramref="Color"/> matching the W3C definition that has an hex value of #F08080.
/// </summary>
public static readonly Color LightCoral = FromRgba(240, 128, 128, 255);
/// <summary>
/// Represents a <see paramref="Color"/> matching the W3C definition that has an hex value of #E0FFFF.
/// </summary>
public static readonly Color LightCyan = FromRgba(224, 255, 255, 255);
/// <summary>
/// Represents a <see paramref="Color"/> matching the W3C definition that has an hex value of #FAFAD2.
/// </summary>
public static readonly Color LightGoldenrodYellow = FromRgba(250, 250, 210, 255);
/// <summary>
/// Represents a <see paramref="Color"/> matching the W3C definition that has an hex value of #D3D3D3.
/// </summary>
public static readonly Color LightGray = FromRgba(211, 211, 211, 255);
/// <summary>
/// Represents a <see paramref="Color"/> matching the W3C definition that has an hex value of #90EE90.
/// </summary>
public static readonly Color LightGreen = FromRgba(144, 238, 144, 255);
/// <summary>
/// Represents a <see paramref="Color"/> matching the W3C definition that has an hex value of #FFB6C1.
/// </summary>
public static readonly Color LightPink = FromRgba(255, 182, 193, 255);
/// <summary>
/// Represents a <see paramref="Color"/> matching the W3C definition that has an hex value of #FFA07A.
/// </summary>
public static readonly Color LightSalmon = FromRgba(255, 160, 122, 255);
/// <summary>
/// Represents a <see paramref="Color"/> matching the W3C definition that has an hex value of #20B2AA.
/// </summary>
public static readonly Color LightSeaGreen = FromRgba(32, 178, 170, 255);
/// <summary>
/// Represents a <see paramref="Color"/> matching the W3C definition that has an hex value of #87CEFA.
/// </summary>
public static readonly Color LightSkyBlue = FromRgba(135, 206, 250, 255);
/// <summary>
/// Represents a <see paramref="Color"/> matching the W3C definition that has an hex value of #778899.
/// </summary>
public static readonly Color LightSlateGray = FromRgba(119, 136, 153, 255);
/// <summary>
/// Represents a <see paramref="Color"/> matching the W3C definition that has an hex value of #B0C4DE.
/// </summary>
public static readonly Color LightSteelBlue = FromRgba(176, 196, 222, 255);
/// <summary>
/// Represents a <see paramref="Color"/> matching the W3C definition that has an hex value of #FFFFE0.
/// </summary>
public static readonly Color LightYellow = FromRgba(255, 255, 224, 255);
/// <summary>
/// Represents a <see paramref="Color"/> matching the W3C definition that has an hex value of #00FF00.
/// </summary>
public static readonly Color Lime = FromRgba(0, 255, 0, 255);
/// <summary>
/// Represents a <see paramref="Color"/> matching the W3C definition that has an hex value of #32CD32.
/// </summary>
public static readonly Color LimeGreen = FromRgba(50, 205, 50, 255);
/// <summary>
/// Represents a <see paramref="Color"/> matching the W3C definition that has an hex value of #FAF0E6.
/// </summary>
public static readonly Color Linen = FromRgba(250, 240, 230, 255);
/// <summary>
/// Represents a <see paramref="Color"/> matching the W3C definition that has an hex value of #FF00FF.
/// </summary>
public static readonly Color Magenta = FromRgba(255, 0, 255, 255);
/// <summary>
/// Represents a <see paramref="Color"/> matching the W3C definition that has an hex value of #800000.
/// </summary>
public static readonly Color Maroon = FromRgba(128, 0, 0, 255);
/// <summary>
/// Represents a <see paramref="Color"/> matching the W3C definition that has an hex value of #66CDAA.
/// </summary>
public static readonly Color MediumAquamarine = FromRgba(102, 205, 170, 255);
/// <summary>
/// Represents a <see paramref="Color"/> matching the W3C definition that has an hex value of #0000CD.
/// </summary>
public static readonly Color MediumBlue = FromRgba(0, 0, 205, 255);
/// <summary>
/// Represents a <see paramref="Color"/> matching the W3C definition that has an hex value of #BA55D3.
/// </summary>
public static readonly Color MediumOrchid = FromRgba(186, 85, 211, 255);
/// <summary>
/// Represents a <see paramref="Color"/> matching the W3C definition that has an hex value of #9370DB.
/// </summary>
public static readonly Color MediumPurple = FromRgba(147, 112, 219, 255);
/// <summary>
/// Represents a <see paramref="Color"/> matching the W3C definition that has an hex value of #3CB371.
/// </summary>
public static readonly Color MediumSeaGreen = FromRgba(60, 179, 113, 255);
/// <summary>
/// Represents a <see paramref="Color"/> matching the W3C definition that has an hex value of #7B68EE.
/// </summary>
public static readonly Color MediumSlateBlue = FromRgba(123, 104, 238, 255);
/// <summary>
/// Represents a <see paramref="Color"/> matching the W3C definition that has an hex value of #00FA9A.
/// </summary>
public static readonly Color MediumSpringGreen = FromRgba(0, 250, 154, 255);
/// <summary>
/// Represents a <see paramref="Color"/> matching the W3C definition that has an hex value of #48D1CC.
/// </summary>
public static readonly Color MediumTurquoise = FromRgba(72, 209, 204, 255);
/// <summary>
/// Represents a <see paramref="Color"/> matching the W3C definition that has an hex value of #C71585.
/// </summary>
public static readonly Color MediumVioletRed = FromRgba(199, 21, 133, 255);
/// <summary>
/// Represents a <see paramref="Color"/> matching the W3C definition that has an hex value of #191970.
/// </summary>
public static readonly Color MidnightBlue = FromRgba(25, 25, 112, 255);
/// <summary>
/// Represents a <see paramref="Color"/> matching the W3C definition that has an hex value of #F5FFFA.
/// </summary>
public static readonly Color MintCream = FromRgba(245, 255, 250, 255);
/// <summary>
/// Represents a <see paramref="Color"/> matching the W3C definition that has an hex value of #FFE4E1.
/// </summary>
public static readonly Color MistyRose = FromRgba(255, 228, 225, 255);
/// <summary>
/// Represents a <see paramref="Color"/> matching the W3C definition that has an hex value of #FFE4B5.
/// </summary>
public static readonly Color Moccasin = FromRgba(255, 228, 181, 255);
/// <summary>
/// Represents a <see paramref="Color"/> matching the W3C definition that has an hex value of #FFDEAD.
/// </summary>
public static readonly Color NavajoWhite = FromRgba(255, 222, 173, 255);
/// <summary>
/// Represents a <see paramref="Color"/> matching the W3C definition that has an hex value of #000080.
/// </summary>
public static readonly Color Navy = FromRgba(0, 0, 128, 255);
/// <summary>
/// Represents a <see paramref="Color"/> matching the W3C definition that has an hex value of #FDF5E6.
/// </summary>
public static readonly Color OldLace = FromRgba(253, 245, 230, 255);
/// <summary>
/// Represents a <see paramref="Color"/> matching the W3C definition that has an hex value of #808000.
/// </summary>
public static readonly Color Olive = FromRgba(128, 128, 0, 255);
/// <summary>
/// Represents a <see paramref="Color"/> matching the W3C definition that has an hex value of #6B8E23.
/// </summary>
public static readonly Color OliveDrab = FromRgba(107, 142, 35, 255);
/// <summary>
/// Represents a <see paramref="Color"/> matching the W3C definition that has an hex value of #FFA500.
/// </summary>
public static readonly Color Orange = FromRgba(255, 165, 0, 255);
/// <summary>
/// Represents a <see paramref="Color"/> matching the W3C definition that has an hex value of #FF4500.
/// </summary>
public static readonly Color OrangeRed = FromRgba(255, 69, 0, 255);
/// <summary>
/// Represents a <see paramref="Color"/> matching the W3C definition that has an hex value of #DA70D6.
/// </summary>
public static readonly Color Orchid = FromRgba(218, 112, 214, 255);
/// <summary>
/// Represents a <see paramref="Color"/> matching the W3C definition that has an hex value of #EEE8AA.
/// </summary>
public static readonly Color PaleGoldenrod = FromRgba(238, 232, 170, 255);
/// <summary>
/// Represents a <see paramref="Color"/> matching the W3C definition that has an hex value of #98FB98.
/// </summary>
public static readonly Color PaleGreen = FromRgba(152, 251, 152, 255);
/// <summary>
/// Represents a <see paramref="Color"/> matching the W3C definition that has an hex value of #AFEEEE.
/// </summary>
public static readonly Color PaleTurquoise = FromRgba(175, 238, 238, 255);
/// <summary>
/// Represents a <see paramref="Color"/> matching the W3C definition that has an hex value of #DB7093.
/// </summary>
public static readonly Color PaleVioletRed = FromRgba(219, 112, 147, 255);
/// <summary>
/// Represents a <see paramref="Color"/> matching the W3C definition that has an hex value of #FFEFD5.
/// </summary>
public static readonly Color PapayaWhip = FromRgba(255, 239, 213, 255);
/// <summary>
/// Represents a <see paramref="Color"/> matching the W3C definition that has an hex value of #FFDAB9.
/// </summary>
public static readonly Color PeachPuff = FromRgba(255, 218, 185, 255);
/// <summary>
/// Represents a <see paramref="Color"/> matching the W3C definition that has an hex value of #CD853F.
/// </summary>
public static readonly Color Peru = FromRgba(205, 133, 63, 255);
/// <summary>
/// Represents a <see paramref="Color"/> matching the W3C definition that has an hex value of #FFC0CB.
/// </summary>
public static readonly Color Pink = FromRgba(255, 192, 203, 255);
/// <summary>
/// Represents a <see paramref="Color"/> matching the W3C definition that has an hex value of #DDA0DD.
/// </summary>
public static readonly Color Plum = FromRgba(221, 160, 221, 255);
/// <summary>
/// Represents a <see paramref="Color"/> matching the W3C definition that has an hex value of #B0E0E6.
/// </summary>
public static readonly Color PowderBlue = FromRgba(176, 224, 230, 255);
/// <summary>
/// Represents a <see paramref="Color"/> matching the W3C definition that has an hex value of #800080.
/// </summary>
public static readonly Color Purple = FromRgba(128, 0, 128, 255);
/// <summary>
/// Represents a <see paramref="Color"/> matching the W3C definition that has an hex value of #663399.
/// </summary>
public static readonly Color RebeccaPurple = FromRgba(102, 51, 153, 255);
/// <summary>
/// Represents a <see paramref="Color"/> matching the W3C definition that has an hex value of #FF0000.
/// </summary>
public static readonly Color Red = FromRgba(255, 0, 0, 255);
/// <summary>
/// Represents a <see paramref="Color"/> matching the W3C definition that has an hex value of #BC8F8F.
/// </summary>
public static readonly Color RosyBrown = FromRgba(188, 143, 143, 255);
/// <summary>
/// Represents a <see paramref="Color"/> matching the W3C definition that has an hex value of #4169E1.
/// </summary>
public static readonly Color RoyalBlue = FromRgba(65, 105, 225, 255);
/// <summary>
/// Represents a <see paramref="Color"/> matching the W3C definition that has an hex value of #8B4513.
/// </summary>
public static readonly Color SaddleBrown = FromRgba(139, 69, 19, 255);
/// <summary>
/// Represents a <see paramref="Color"/> matching the W3C definition that has an hex value of #FA8072.
/// </summary>
public static readonly Color Salmon = FromRgba(250, 128, 114, 255);
/// <summary>
/// Represents a <see paramref="Color"/> matching the W3C definition that has an hex value of #F4A460.
/// </summary>
public static readonly Color SandyBrown = FromRgba(244, 164, 96, 255);
/// <summary>
/// Represents a <see paramref="Color"/> matching the W3C definition that has an hex value of #2E8B57.
/// </summary>
public static readonly Color SeaGreen = FromRgba(46, 139, 87, 255);
/// <summary>
/// Represents a <see paramref="Color"/> matching the W3C definition that has an hex value of #FFF5EE.
/// </summary>
public static readonly Color SeaShell = FromRgba(255, 245, 238, 255);
/// <summary>
/// Represents a <see paramref="Color"/> matching the W3C definition that has an hex value of #A0522D.
/// </summary>
public static readonly Color Sienna = FromRgba(160, 82, 45, 255);
/// <summary>
/// Represents a <see paramref="Color"/> matching the W3C definition that has an hex value of #C0C0C0.
/// </summary>
public static readonly Color Silver = FromRgba(192, 192, 192, 255);
/// <summary>
/// Represents a <see paramref="Color"/> matching the W3C definition that has an hex value of #87CEEB.
/// </summary>
public static readonly Color SkyBlue = FromRgba(135, 206, 235, 255);
/// <summary>
/// Represents a <see paramref="Color"/> matching the W3C definition that has an hex value of #6A5ACD.
/// </summary>
public static readonly Color SlateBlue = FromRgba(106, 90, 205, 255);
/// <summary>
/// Represents a <see paramref="Color"/> matching the W3C definition that has an hex value of #708090.
/// </summary>
public static readonly Color SlateGray = FromRgba(112, 128, 144, 255);
/// <summary>
/// Represents a <see paramref="Color"/> matching the W3C definition that has an hex value of #FFFAFA.
/// </summary>
public static readonly Color Snow = FromRgba(255, 250, 250, 255);
/// <summary>
/// Represents a <see paramref="Color"/> matching the W3C definition that has an hex value of #00FF7F.
/// </summary>
public static readonly Color SpringGreen = FromRgba(0, 255, 127, 255);
/// <summary>
/// Represents a <see paramref="Color"/> matching the W3C definition that has an hex value of #4682B4.
/// </summary>
public static readonly Color SteelBlue = FromRgba(70, 130, 180, 255);
/// <summary>
/// Represents a <see paramref="Color"/> matching the W3C definition that has an hex value of #D2B48C.
/// </summary>
public static readonly Color Tan = FromRgba(210, 180, 140, 255);
/// <summary>
/// Represents a <see paramref="Color"/> matching the W3C definition that has an hex value of #008080.
/// </summary>
public static readonly Color Teal = FromRgba(0, 128, 128, 255);
/// <summary>
/// Represents a <see paramref="Color"/> matching the W3C definition that has an hex value of #D8BFD8.
/// </summary>
public static readonly Color Thistle = FromRgba(216, 191, 216, 255);
/// <summary>
/// Represents a <see paramref="Color"/> matching the W3C definition that has an hex value of #FF6347.
/// </summary>
public static readonly Color Tomato = FromRgba(255, 99, 71, 255);
/// <summary>
/// Represents a <see paramref="Color"/> matching the W3C definition that has an hex value of #FFFFFF.
/// </summary>
public static readonly Color Transparent = FromRgba(255, 255, 255, 0);
/// <summary>
/// Represents a <see paramref="Color"/> matching the W3C definition that has an hex value of #40E0D0.
/// </summary>
public static readonly Color Turquoise = FromRgba(64, 224, 208, 255);
/// <summary>
/// Represents a <see paramref="Color"/> matching the W3C definition that has an hex value of #EE82EE.
/// </summary>
public static readonly Color Violet = FromRgba(238, 130, 238, 255);
/// <summary>
/// Represents a <see paramref="Color"/> matching the W3C definition that has an hex value of #F5DEB3.
/// </summary>
public static readonly Color Wheat = FromRgba(245, 222, 179, 255);
/// <summary>
/// Represents a <see paramref="Color"/> matching the W3C definition that has an hex value of #FFFFFF.
/// </summary>
public static readonly Color White = FromRgba(255, 255, 255, 255);
/// <summary>
/// Represents a <see paramref="Color"/> matching the W3C definition that has an hex value of #F5F5F5.
/// </summary>
public static readonly Color WhiteSmoke = FromRgba(245, 245, 245, 255);
/// <summary>
/// Represents a <see paramref="Color"/> matching the W3C definition that has an hex value of #FFFF00.
/// </summary>
public static readonly Color Yellow = FromRgba(255, 255, 0, 255);
/// <summary>
/// Represents a <see paramref="Color"/> matching the W3C definition that has an hex value of #9ACD32.
/// </summary>
public static readonly Color YellowGreen = FromRgba(154, 205, 50, 255);
}
}

166
src/ImageSharp/Color/Color.WebSafePalette.cs

@ -0,0 +1,166 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
namespace SixLabors.ImageSharp
{
/// <content>
/// Contains the definition of <see cref="WebSafePalette"/>.
/// </content>
public partial struct Color
{
private static readonly Lazy<Color[]> WebSafePaletteLazy = new Lazy<Color[]>(CreateWebSafePalette, true);
/// <summary>
/// Gets a collection of named, web safe colors as defined in the CSS Color Module Level 4.
/// </summary>
public static ReadOnlyMemory<Color> WebSafePalette => WebSafePaletteLazy.Value;
private static Color[] CreateWebSafePalette() => new[]
{
AliceBlue,
AntiqueWhite,
Aqua,
Aquamarine,
Azure,
Beige,
Bisque,
Black,
BlanchedAlmond,
Blue,
BlueViolet,
Brown,
BurlyWood,
CadetBlue,
Chartreuse,
Chocolate,
Coral,
CornflowerBlue,
Cornsilk,
Crimson,
Cyan,
DarkBlue,
DarkCyan,
DarkGoldenrod,
DarkGray,
DarkGreen,
DarkKhaki,
DarkMagenta,
DarkOliveGreen,
DarkOrange,
DarkOrchid,
DarkRed,
DarkSalmon,
DarkSeaGreen,
DarkSlateBlue,
DarkSlateGray,
DarkTurquoise,
DarkViolet,
DeepPink,
DeepSkyBlue,
DimGray,
DodgerBlue,
Firebrick,
FloralWhite,
ForestGreen,
Fuchsia,
Gainsboro,
GhostWhite,
Gold,
Goldenrod,
Gray,
Green,
GreenYellow,
Honeydew,
HotPink,
IndianRed,
Indigo,
Ivory,
Khaki,
Lavender,
LavenderBlush,
LawnGreen,
LemonChiffon,
LightBlue,
LightCoral,
LightCyan,
LightGoldenrodYellow,
LightGray,
LightGreen,
LightPink,
LightSalmon,
LightSeaGreen,
LightSkyBlue,
LightSlateGray,
LightSteelBlue,
LightYellow,
Lime,
LimeGreen,
Linen,
Magenta,
Maroon,
MediumAquamarine,
MediumBlue,
MediumOrchid,
MediumPurple,
MediumSeaGreen,
MediumSlateBlue,
MediumSpringGreen,
MediumTurquoise,
MediumVioletRed,
MidnightBlue,
MintCream,
MistyRose,
Moccasin,
NavajoWhite,
Navy,
OldLace,
Olive,
OliveDrab,
Orange,
OrangeRed,
Orchid,
PaleGoldenrod,
PaleGreen,
PaleTurquoise,
PaleVioletRed,
PapayaWhip,
PeachPuff,
Peru,
Pink,
Plum,
PowderBlue,
Purple,
RebeccaPurple,
Red,
RosyBrown,
RoyalBlue,
SaddleBrown,
Salmon,
SandyBrown,
SeaGreen,
SeaShell,
Sienna,
Silver,
SkyBlue,
SlateBlue,
SlateGray,
Snow,
SpringGreen,
SteelBlue,
Tan,
Teal,
Thistle,
Tomato,
Transparent,
Turquoise,
Violet,
Wheat,
White,
WhiteSmoke,
Yellow,
YellowGreen
};
}
}

135
src/ImageSharp/Color/Color.WernerPalette.cs

@ -0,0 +1,135 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
namespace SixLabors.ImageSharp
{
/// <content>
/// Contains the definition of <see cref="WernerPalette"/>.
/// </content>
public partial struct Color
{
private static readonly Lazy<Color[]> WernerPaletteLazy = new Lazy<Color[]>(CreateWernerPalette, true);
/// <summary>
/// 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 <see href="https://www.c82.net/werner"/>.
/// </summary>
public static ReadOnlyMemory<Color> WernerPalette => WernerPaletteLazy.Value;
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")
};
}
}

218
src/ImageSharp/Color/Color.cs

@ -0,0 +1,218 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
using System.Buffers.Binary;
using System.Globalization;
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp
{
/// <summary>
/// Represents a color value that is convertible to any <see cref="IPixel{TSelf}"/> type.
/// </summary>
/// <remarks>
/// The internal representation and layout of this structure is hidden by intention.
/// It's not serializable, and it should not be considered as part of a contract.
/// Unlike System.Drawing.Color, <see cref="Color"/> has to be converted to a specific pixel value
/// to query the color components.
/// </remarks>
public readonly partial struct Color : IEquatable<Color>
{
private readonly Rgba64 data;
[MethodImpl(InliningOptions.ShortMethod)]
private Color(byte r, byte g, byte b, byte a)
{
this.data = new Rgba64(
ImageMaths.UpscaleFrom8BitTo16Bit(r),
ImageMaths.UpscaleFrom8BitTo16Bit(g),
ImageMaths.UpscaleFrom8BitTo16Bit(b),
ImageMaths.UpscaleFrom8BitTo16Bit(a));
}
[MethodImpl(InliningOptions.ShortMethod)]
private Color(byte r, byte g, byte b)
{
this.data = new Rgba64(
ImageMaths.UpscaleFrom8BitTo16Bit(r),
ImageMaths.UpscaleFrom8BitTo16Bit(g),
ImageMaths.UpscaleFrom8BitTo16Bit(b),
ushort.MaxValue);
}
/// <summary>
/// Checks whether two <see cref="Color"/> structures are equal.
/// </summary>
/// <param name="left">The left hand <see cref="Color"/> operand.</param>
/// <param name="right">The right hand <see cref="Color"/> operand.</param>
/// <returns>
/// True if the <paramref name="left"/> parameter is equal to the <paramref name="right"/> parameter;
/// otherwise, false.
/// </returns>
[MethodImpl(InliningOptions.ShortMethod)]
public static bool operator ==(Color left, Color right)
{
return left.Equals(right);
}
/// <summary>
/// Checks whether two <see cref="Color"/> structures are equal.
/// </summary>
/// <param name="left">The left hand <see cref="Color"/> operand.</param>
/// <param name="right">The right hand <see cref="Color"/> operand.</param>
/// <returns>
/// True if the <paramref name="left"/> parameter is not equal to the <paramref name="right"/> parameter;
/// otherwise, false.
/// </returns>
[MethodImpl(InliningOptions.ShortMethod)]
public static bool operator !=(Color left, Color right)
{
return !left.Equals(right);
}
/// <summary>
/// Creates a <see cref="Color"/> from RGBA bytes.
/// </summary>
/// <param name="r">The red component (0-255).</param>
/// <param name="g">The green component (0-255).</param>
/// <param name="b">The blue component (0-255).</param>
/// <param name="a">The alpha component (0-255).</param>
/// <returns>The <see cref="Color"/>.</returns>
[MethodImpl(InliningOptions.ShortMethod)]
public static Color FromRgba(byte r, byte g, byte b, byte a) => new Color(r, g, b, a);
/// <summary>
/// Creates a <see cref="Color"/> from RGB bytes.
/// </summary>
/// <param name="r">The red component (0-255).</param>
/// <param name="g">The green component (0-255).</param>
/// <param name="b">The blue component (0-255).</param>
/// <returns>The <see cref="Color"/>.</returns>
[MethodImpl(InliningOptions.ShortMethod)]
public static Color FromRgb(byte r, byte g, byte b) => new Color(r, g, b);
/// <summary>
/// Creates a new <see cref="Color"/> instance from the string representing a color in hexadecimal form.
/// </summary>
/// <param name="hex">
/// The hexadecimal representation of the combined color components arranged
/// in rgb, rgba, rrggbb, or rrggbbaa format to match web syntax.
/// </param>
/// <returns>Returns a <see cref="Color"/> that represents the color defined by the provided RGBA hex string.</returns>
public static Color FromHex(string hex)
{
Guard.NotNullOrWhiteSpace(hex, nameof(hex));
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));
}
var rgba = new Rgba32(BinaryPrimitives.ReverseEndianness(packedValue));
return new Color(rgba);
}
/// <summary>
/// Gets the hexadecimal representation of the color instance in rrggbbaa form.
/// </summary>
/// <returns>A hexadecimal string representation of the value.</returns>
[MethodImpl(InliningOptions.ShortMethod)]
public string ToHex() => this.data.ToRgba32().ToHex();
/// <inheritdoc />
public override string ToString() => this.ToHex();
/// <summary>
/// Converts the color instance to an <see cref="IPixel{TSelf}"/>
/// implementation defined by <typeparamref name="TPixel"/>.
/// </summary>
/// <typeparam name="TPixel">The pixel type to convert to.</typeparam>
/// <returns>The pixel value.</returns>
[MethodImpl(InliningOptions.ShortMethod)]
public TPixel ToPixel<TPixel>()
where TPixel : struct, IPixel<TPixel>
{
TPixel pixel = default;
pixel.FromRgba64(this.data);
return pixel;
}
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public bool Equals(Color other)
{
return this.data.PackedValue == other.data.PackedValue;
}
/// <inheritdoc />
public override bool Equals(object obj)
{
return obj is Color other && this.Equals(other);
}
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public override int GetHashCode()
{
return this.data.PackedValue.GetHashCode();
}
/// <summary>
/// Bulk convert a span of <see cref="Color"/> to a span of a specified pixel type.
/// </summary>
[MethodImpl(InliningOptions.ShortMethod)]
internal static void ToPixel<TPixel>(
Configuration configuration,
ReadOnlySpan<Color> source,
Span<TPixel> destination)
where TPixel : struct, IPixel<TPixel>
{
ReadOnlySpan<Rgba64> rgba64Span = MemoryMarshal.Cast<Color, Rgba64>(source);
PixelOperations<TPixel>.Instance.FromRgba64(Configuration.Default, rgba64Span, destination);
}
/// <summary>
/// Converts the specified hex value to an rrggbbaa hex value.
/// </summary>
/// <param name="hex">The hex value to convert.</param>
/// <returns>
/// A rrggbbaa hex value.
/// </returns>
private static string ToRgbaHex(string hex)
{
if (hex[0] == '#')
{
hex = hex.Substring(1);
}
if (hex.Length == 8)
{
return hex;
}
if (hex.Length == 6)
{
return hex + "FF";
}
if (hex.Length < 3 || hex.Length > 4)
{
return null;
}
char r = hex[0];
char g = hex[1];
char b = hex[2];
char a = hex.Length == 3 ? 'F' : hex[3];
return new string(new[] { r, r, g, g, b, b, a, a });
}
}
}

9
src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs

@ -306,12 +306,15 @@ namespace SixLabors.ImageSharp.Formats.Bmp
where TPixel : struct, IPixel<TPixel>
{
using (IMemoryOwner<byte> colorPaletteBuffer = this.memoryAllocator.AllocateManagedByteBuffer(ColorPaletteSize8Bit, AllocationOptions.Clean))
using (QuantizedFrame<TPixel> quantized = this.quantizer.CreateFrameQuantizer<TPixel>(this.configuration, 256).QuantizeFrame(image))
using (IQuantizedFrame<TPixel> quantized = this.quantizer.CreateFrameQuantizer<TPixel>(this.configuration, 256).QuantizeFrame(image))
{
Span<byte> colorPalette = colorPaletteBuffer.GetSpan();
int idx = 0;
var color = default(Rgba32);
foreach (TPixel quantizedColor in quantized.Palette)
ReadOnlySpan<TPixel> paletteSpan = quantized.Palette.Span;
// TODO: Use bulk conversion here for better perf
foreach (TPixel quantizedColor in paletteSpan)
{
quantizedColor.ToRgba32(ref color);
colorPalette[idx] = color.B;
@ -327,7 +330,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp
for (int y = image.Height - 1; y >= 0; y--)
{
Span<byte> pixelSpan = quantized.GetRowSpan(y);
ReadOnlySpan<byte> pixelSpan = quantized.GetRowSpan(y);
stream.Write(pixelSpan);
for (int i = 0; i < this.padding; i++)

29
src/ImageSharp/Formats/Gif/GifEncoderCore.cs

@ -95,7 +95,7 @@ namespace SixLabors.ImageSharp.Formats.Gif
bool useGlobalTable = this.colorTableMode == GifColorTableMode.Global;
// Quantize the image returning a palette.
QuantizedFrame<TPixel> quantized = null;
IQuantizedFrame<TPixel> quantized = null;
using (IFrameQuantizer<TPixel> frameQuantizer = this.quantizer.CreateFrameQuantizer<TPixel>(image.GetConfiguration()))
{
quantized = frameQuantizer.QuantizeFrame(image.Frames.RootFrame);
@ -141,11 +141,9 @@ namespace SixLabors.ImageSharp.Formats.Gif
stream.WriteByte(GifConstants.EndIntroducer);
}
private void EncodeGlobal<TPixel>(Image<TPixel> image, QuantizedFrame<TPixel> quantized, int transparencyIndex, Stream stream)
private void EncodeGlobal<TPixel>(Image<TPixel> image, IQuantizedFrame<TPixel> quantized, int transparencyIndex, Stream stream)
where TPixel : struct, IPixel<TPixel>
{
var palleteQuantizer = new PaletteQuantizer<TPixel>(quantized.Palette, this.quantizer.Diffuser);
for (int i = 0; i < image.Frames.Count; i++)
{
ImageFrame<TPixel> frame = image.Frames[i];
@ -160,16 +158,19 @@ namespace SixLabors.ImageSharp.Formats.Gif
}
else
{
using (IFrameQuantizer<TPixel> palleteFrameQuantizer = palleteQuantizer.CreateFrameQuantizer(image.GetConfiguration()))
using (QuantizedFrame<TPixel> paletteQuantized = palleteFrameQuantizer.QuantizeFrame(frame))
using (IFrameQuantizer<TPixel> palleteFrameQuantizer =
new PaletteFrameQuantizer<TPixel>(this.quantizer.Diffuser, quantized.Palette))
{
this.WriteImageData(paletteQuantized, stream);
using (IQuantizedFrame<TPixel> paletteQuantized = palleteFrameQuantizer.QuantizeFrame(frame))
{
this.WriteImageData(paletteQuantized, stream);
}
}
}
}
}
private void EncodeLocal<TPixel>(Image<TPixel> image, QuantizedFrame<TPixel> quantized, Stream stream)
private void EncodeLocal<TPixel>(Image<TPixel> image, IQuantizedFrame<TPixel> quantized, Stream stream)
where TPixel : struct, IPixel<TPixel>
{
ImageFrame<TPixel> previousFrame = null;
@ -221,7 +222,7 @@ namespace SixLabors.ImageSharp.Formats.Gif
/// <returns>
/// The <see cref="int"/>.
/// </returns>
private int GetTransparentIndex<TPixel>(QuantizedFrame<TPixel> quantized)
private int GetTransparentIndex<TPixel>(IQuantizedFrame<TPixel> quantized)
where TPixel : struct, IPixel<TPixel>
{
// Transparent pixels are much more likely to be found at the end of a palette
@ -232,7 +233,7 @@ namespace SixLabors.ImageSharp.Formats.Gif
{
Span<Rgba32> rgbaSpan = rgbaBuffer.GetSpan();
ref Rgba32 paletteRef = ref MemoryMarshal.GetReference(rgbaSpan);
PixelOperations<TPixel>.Instance.ToRgba32(this.configuration, quantized.Palette, rgbaSpan);
PixelOperations<TPixel>.Instance.ToRgba32(this.configuration, quantized.Palette.Span, rgbaSpan);
for (int i = quantized.Palette.Length - 1; i >= 0; i--)
{
@ -424,7 +425,7 @@ namespace SixLabors.ImageSharp.Formats.Gif
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="image">The <see cref="ImageFrame{TPixel}"/> to encode.</param>
/// <param name="stream">The stream to write to.</param>
private void WriteColorTable<TPixel>(QuantizedFrame<TPixel> image, Stream stream)
private void WriteColorTable<TPixel>(IQuantizedFrame<TPixel> image, Stream stream)
where TPixel : struct, IPixel<TPixel>
{
// The maximum number of colors for the bit depth
@ -435,7 +436,7 @@ namespace SixLabors.ImageSharp.Formats.Gif
{
PixelOperations<TPixel>.Instance.ToRgb24Bytes(
this.configuration,
image.Palette.AsSpan(),
image.Palette.Span,
colorTable.GetSpan(),
pixelCount);
stream.Write(colorTable.Array, 0, colorTableLength);
@ -446,9 +447,9 @@ namespace SixLabors.ImageSharp.Formats.Gif
/// Writes the image pixel data to the stream.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="image">The <see cref="QuantizedFrame{TPixel}"/> containing indexed pixels.</param>
/// <param name="image">The <see cref="IQuantizedFrame{TPixel}"/> containing indexed pixels.</param>
/// <param name="stream">The stream to write to.</param>
private void WriteImageData<TPixel>(QuantizedFrame<TPixel> image, Stream stream)
private void WriteImageData<TPixel>(IQuantizedFrame<TPixel> image, Stream stream)
where TPixel : struct, IPixel<TPixel>
{
using (var encoder = new LzwEncoder(this.memoryAllocator, (byte)this.bitDepth))

6
src/ImageSharp/Formats/Gif/LzwEncoder.cs

@ -180,7 +180,7 @@ namespace SixLabors.ImageSharp.Formats.Gif
/// </summary>
/// <param name="indexedPixels">The span of indexed pixels.</param>
/// <param name="stream">The stream to write to.</param>
public void Encode(Span<byte> indexedPixels, Stream stream)
public void Encode(ReadOnlySpan<byte> indexedPixels, Stream stream)
{
// Write "initial code size" byte
stream.WriteByte((byte)this.initialCodeSize);
@ -251,7 +251,7 @@ namespace SixLabors.ImageSharp.Formats.Gif
/// <param name="indexedPixels">The span of indexed pixels.</param>
/// <param name="intialBits">The initial bits.</param>
/// <param name="stream">The stream to write to.</param>
private void Compress(Span<byte> indexedPixels, int intialBits, Stream stream)
private void Compress(ReadOnlySpan<byte> indexedPixels, int intialBits, Stream stream)
{
int fcode;
int c;
@ -375,7 +375,7 @@ namespace SixLabors.ImageSharp.Formats.Gif
/// The <see cref="int"/>
/// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private int NextPixel(Span<byte> indexedPixels)
private int NextPixel(ReadOnlySpan<byte> indexedPixels)
{
return indexedPixels[this.position++] & 0xFF;
}

12
src/ImageSharp/Formats/Png/PngEncoderCore.cs

@ -227,7 +227,7 @@ namespace SixLabors.ImageSharp.Formats.Png
stream.Write(PngConstants.HeaderBytes, 0, PngConstants.HeaderBytes.Length);
QuantizedFrame<TPixel> quantized = null;
IQuantizedFrame<TPixel> quantized = null;
if (this.pngColorType == PngColorType.Palette)
{
byte bits = (byte)this.pngBitDepth;
@ -511,7 +511,7 @@ namespace SixLabors.ImageSharp.Formats.Png
/// <param name="quantized">The quantized pixels. Can be null.</param>
/// <param name="row">The row.</param>
/// <returns>The <see cref="IManagedByteBuffer"/></returns>
private IManagedByteBuffer EncodePixelRow<TPixel>(ReadOnlySpan<TPixel> rowSpan, QuantizedFrame<TPixel> quantized, int row)
private IManagedByteBuffer EncodePixelRow<TPixel>(ReadOnlySpan<TPixel> rowSpan, IQuantizedFrame<TPixel> quantized, int row)
where TPixel : struct, IPixel<TPixel>
{
switch (this.pngColorType)
@ -662,11 +662,11 @@ namespace SixLabors.ImageSharp.Formats.Png
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="stream">The <see cref="Stream"/> containing image data.</param>
/// <param name="quantized">The quantized frame.</param>
private void WritePaletteChunk<TPixel>(Stream stream, QuantizedFrame<TPixel> quantized)
private void WritePaletteChunk<TPixel>(Stream stream, IQuantizedFrame<TPixel> quantized)
where TPixel : struct, IPixel<TPixel>
{
// Grab the palette and write it to the stream.
TPixel[] palette = quantized.Palette;
ReadOnlySpan<TPixel> palette = quantized.Palette.Span;
int paletteLength = Math.Min(palette.Length, 256);
int colorTableLength = paletteLength * 3;
bool anyAlpha = false;
@ -676,7 +676,7 @@ namespace SixLabors.ImageSharp.Formats.Png
{
ref byte colorTableRef = ref MemoryMarshal.GetReference(colorTable.GetSpan());
ref byte alphaTableRef = ref MemoryMarshal.GetReference(alphaTable.GetSpan());
Span<byte> quantizedSpan = quantized.GetPixelSpan();
ReadOnlySpan<byte> quantizedSpan = quantized.GetPixelSpan();
Rgba32 rgba = default;
@ -808,7 +808,7 @@ namespace SixLabors.ImageSharp.Formats.Png
/// <param name="pixels">The image.</param>
/// <param name="quantized">The quantized pixel data. Can be null.</param>
/// <param name="stream">The stream.</param>
private void WriteDataChunks<TPixel>(ImageFrame<TPixel> pixels, QuantizedFrame<TPixel> quantized, Stream stream)
private void WriteDataChunks<TPixel>(ImageFrame<TPixel> pixels, IQuantizedFrame<TPixel> quantized, Stream stream)
where TPixel : struct, IPixel<TPixel>
{
this.bytesPerScanline = this.CalculateScanlineLength(this.width);

2
src/ImageSharp/ImageSharp.csproj.DotSettings

@ -1,4 +1,5 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=color/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=common/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=common_005Cexceptions/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=pixelformats_005Cgenerated/@EntryIndexedValue">True</s:Boolean>
@ -6,6 +7,7 @@
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=pixelformats_005Cpixelimplementations/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=pixelformats_005Cpixeltypes/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=pixelformats_005Cutils/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=processing_005Cextensions/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=processing_005Cprocessors_005Cconvolution_005Ckernels/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=processing_005Cprocessors_005Ctransforms_005Cresamplers/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=processing_005Cprocessors_005Ctransforms_005Cresize/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>

4
src/ImageSharp/PixelFormats/ColorBuilder{TPixel}.cs

@ -47,7 +47,7 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <param name="green">The green intensity.</param>
/// <param name="blue">The blue intensity.</param>
/// <returns>Returns a <typeparamref name="TPixel"/> that represents the color defined by the provided RGB values with 100% opacity.</returns>
public static TPixel FromRGB(byte red, byte green, byte blue) => FromRGBA(red, green, blue, 255);
public static TPixel FromRgb(byte red, byte green, byte blue) => FromRgba(red, green, blue, 255);
/// <summary>
/// Creates a new <typeparamref name="TPixel"/> representation from standard RGBA bytes.
@ -57,7 +57,7 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <param name="blue">The blue intensity.</param>
/// <param name="alpha">The alpha intensity.</param>
/// <returns>Returns a <typeparamref name="TPixel"/> that represents the color defined by the provided RGBA values.</returns>
public static TPixel FromRGBA(byte red, byte green, byte blue, byte alpha)
public static TPixel FromRgba(byte red, byte green, byte blue, byte alpha)
{
TPixel color = default;
color.FromRgba32(new Rgba32(red, green, blue, alpha));

284
src/ImageSharp/PixelFormats/NamedColors{TPixel}.cs

@ -22,712 +22,712 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <summary>
/// Represents a <see paramref="TPixel"/> matching the W3C definition that has an hex value of #F0F8FF.
/// </summary>
public static readonly TPixel AliceBlue = ColorBuilder<TPixel>.FromRGBA(240, 248, 255, 255);
public static readonly TPixel AliceBlue = ColorBuilder<TPixel>.FromRgba(240, 248, 255, 255);
/// <summary>
/// Represents a <see paramref="TPixel"/> matching the W3C definition that has an hex value of #FAEBD7.
/// </summary>
public static readonly TPixel AntiqueWhite = ColorBuilder<TPixel>.FromRGBA(250, 235, 215, 255);
public static readonly TPixel AntiqueWhite = ColorBuilder<TPixel>.FromRgba(250, 235, 215, 255);
/// <summary>
/// Represents a <see paramref="TPixel"/> matching the W3C definition that has an hex value of #00FFFF.
/// </summary>
public static readonly TPixel Aqua = ColorBuilder<TPixel>.FromRGBA(0, 255, 255, 255);
public static readonly TPixel Aqua = ColorBuilder<TPixel>.FromRgba(0, 255, 255, 255);
/// <summary>
/// Represents a <see paramref="TPixel"/> matching the W3C definition that has an hex value of #7FFFD4.
/// </summary>
public static readonly TPixel Aquamarine = ColorBuilder<TPixel>.FromRGBA(127, 255, 212, 255);
public static readonly TPixel Aquamarine = ColorBuilder<TPixel>.FromRgba(127, 255, 212, 255);
/// <summary>
/// Represents a <see paramref="TPixel"/> matching the W3C definition that has an hex value of #F0FFFF.
/// </summary>
public static readonly TPixel Azure = ColorBuilder<TPixel>.FromRGBA(240, 255, 255, 255);
public static readonly TPixel Azure = ColorBuilder<TPixel>.FromRgba(240, 255, 255, 255);
/// <summary>
/// Represents a <see paramref="TPixel"/> matching the W3C definition that has an hex value of #F5F5DC.
/// </summary>
public static readonly TPixel Beige = ColorBuilder<TPixel>.FromRGBA(245, 245, 220, 255);
public static readonly TPixel Beige = ColorBuilder<TPixel>.FromRgba(245, 245, 220, 255);
/// <summary>
/// Represents a <see paramref="TPixel"/> matching the W3C definition that has an hex value of #FFE4C4.
/// </summary>
public static readonly TPixel Bisque = ColorBuilder<TPixel>.FromRGBA(255, 228, 196, 255);
public static readonly TPixel Bisque = ColorBuilder<TPixel>.FromRgba(255, 228, 196, 255);
/// <summary>
/// Represents a <see paramref="TPixel"/> matching the W3C definition that has an hex value of #000000.
/// </summary>
public static readonly TPixel Black = ColorBuilder<TPixel>.FromRGBA(0, 0, 0, 255);
public static readonly TPixel Black = ColorBuilder<TPixel>.FromRgba(0, 0, 0, 255);
/// <summary>
/// Represents a <see paramref="TPixel"/> matching the W3C definition that has an hex value of #FFEBCD.
/// </summary>
public static readonly TPixel BlanchedAlmond = ColorBuilder<TPixel>.FromRGBA(255, 235, 205, 255);
public static readonly TPixel BlanchedAlmond = ColorBuilder<TPixel>.FromRgba(255, 235, 205, 255);
/// <summary>
/// Represents a <see paramref="TPixel"/> matching the W3C definition that has an hex value of #0000FF.
/// </summary>
public static readonly TPixel Blue = ColorBuilder<TPixel>.FromRGBA(0, 0, 255, 255);
public static readonly TPixel Blue = ColorBuilder<TPixel>.FromRgba(0, 0, 255, 255);
/// <summary>
/// Represents a <see paramref="TPixel"/> matching the W3C definition that has an hex value of #8A2BE2.
/// </summary>
public static readonly TPixel BlueViolet = ColorBuilder<TPixel>.FromRGBA(138, 43, 226, 255);
public static readonly TPixel BlueViolet = ColorBuilder<TPixel>.FromRgba(138, 43, 226, 255);
/// <summary>
/// Represents a <see paramref="TPixel"/> matching the W3C definition that has an hex value of #A52A2A.
/// </summary>
public static readonly TPixel Brown = ColorBuilder<TPixel>.FromRGBA(165, 42, 42, 255);
public static readonly TPixel Brown = ColorBuilder<TPixel>.FromRgba(165, 42, 42, 255);
/// <summary>
/// Represents a <see paramref="TPixel"/> matching the W3C definition that has an hex value of #DEB887.
/// </summary>
public static readonly TPixel BurlyWood = ColorBuilder<TPixel>.FromRGBA(222, 184, 135, 255);
public static readonly TPixel BurlyWood = ColorBuilder<TPixel>.FromRgba(222, 184, 135, 255);
/// <summary>
/// Represents a <see paramref="TPixel"/> matching the W3C definition that has an hex value of #5F9EA0.
/// </summary>
public static readonly TPixel CadetBlue = ColorBuilder<TPixel>.FromRGBA(95, 158, 160, 255);
public static readonly TPixel CadetBlue = ColorBuilder<TPixel>.FromRgba(95, 158, 160, 255);
/// <summary>
/// Represents a <see paramref="TPixel"/> matching the W3C definition that has an hex value of #7FFF00.
/// </summary>
public static readonly TPixel Chartreuse = ColorBuilder<TPixel>.FromRGBA(127, 255, 0, 255);
public static readonly TPixel Chartreuse = ColorBuilder<TPixel>.FromRgba(127, 255, 0, 255);
/// <summary>
/// Represents a <see paramref="TPixel"/> matching the W3C definition that has an hex value of #D2691E.
/// </summary>
public static readonly TPixel Chocolate = ColorBuilder<TPixel>.FromRGBA(210, 105, 30, 255);
public static readonly TPixel Chocolate = ColorBuilder<TPixel>.FromRgba(210, 105, 30, 255);
/// <summary>
/// Represents a <see paramref="TPixel"/> matching the W3C definition that has an hex value of #FF7F50.
/// </summary>
public static readonly TPixel Coral = ColorBuilder<TPixel>.FromRGBA(255, 127, 80, 255);
public static readonly TPixel Coral = ColorBuilder<TPixel>.FromRgba(255, 127, 80, 255);
/// <summary>
/// Represents a <see paramref="TPixel"/> matching the W3C definition that has an hex value of #6495ED.
/// </summary>
public static readonly TPixel CornflowerBlue = ColorBuilder<TPixel>.FromRGBA(100, 149, 237, 255);
public static readonly TPixel CornflowerBlue = ColorBuilder<TPixel>.FromRgba(100, 149, 237, 255);
/// <summary>
/// Represents a <see paramref="TPixel"/> matching the W3C definition that has an hex value of #FFF8DC.
/// </summary>
public static readonly TPixel Cornsilk = ColorBuilder<TPixel>.FromRGBA(255, 248, 220, 255);
public static readonly TPixel Cornsilk = ColorBuilder<TPixel>.FromRgba(255, 248, 220, 255);
/// <summary>
/// Represents a <see paramref="TPixel"/> matching the W3C definition that has an hex value of #DC143C.
/// </summary>
public static readonly TPixel Crimson = ColorBuilder<TPixel>.FromRGBA(220, 20, 60, 255);
public static readonly TPixel Crimson = ColorBuilder<TPixel>.FromRgba(220, 20, 60, 255);
/// <summary>
/// Represents a <see paramref="TPixel"/> matching the W3C definition that has an hex value of #00FFFF.
/// </summary>
public static readonly TPixel Cyan = ColorBuilder<TPixel>.FromRGBA(0, 255, 255, 255);
public static readonly TPixel Cyan = ColorBuilder<TPixel>.FromRgba(0, 255, 255, 255);
/// <summary>
/// Represents a <see paramref="TPixel"/> matching the W3C definition that has an hex value of #00008B.
/// </summary>
public static readonly TPixel DarkBlue = ColorBuilder<TPixel>.FromRGBA(0, 0, 139, 255);
public static readonly TPixel DarkBlue = ColorBuilder<TPixel>.FromRgba(0, 0, 139, 255);
/// <summary>
/// Represents a <see paramref="TPixel"/> matching the W3C definition that has an hex value of #008B8B.
/// </summary>
public static readonly TPixel DarkCyan = ColorBuilder<TPixel>.FromRGBA(0, 139, 139, 255);
public static readonly TPixel DarkCyan = ColorBuilder<TPixel>.FromRgba(0, 139, 139, 255);
/// <summary>
/// Represents a <see paramref="TPixel"/> matching the W3C definition that has an hex value of #B8860B.
/// </summary>
public static readonly TPixel DarkGoldenrod = ColorBuilder<TPixel>.FromRGBA(184, 134, 11, 255);
public static readonly TPixel DarkGoldenrod = ColorBuilder<TPixel>.FromRgba(184, 134, 11, 255);
/// <summary>
/// Represents a <see paramref="TPixel"/> matching the W3C definition that has an hex value of #A9A9A9.
/// </summary>
public static readonly TPixel DarkGray = ColorBuilder<TPixel>.FromRGBA(169, 169, 169, 255);
public static readonly TPixel DarkGray = ColorBuilder<TPixel>.FromRgba(169, 169, 169, 255);
/// <summary>
/// Represents a <see paramref="TPixel"/> matching the W3C definition that has an hex value of #006400.
/// </summary>
public static readonly TPixel DarkGreen = ColorBuilder<TPixel>.FromRGBA(0, 100, 0, 255);
public static readonly TPixel DarkGreen = ColorBuilder<TPixel>.FromRgba(0, 100, 0, 255);
/// <summary>
/// Represents a <see paramref="TPixel"/> matching the W3C definition that has an hex value of #BDB76B.
/// </summary>
public static readonly TPixel DarkKhaki = ColorBuilder<TPixel>.FromRGBA(189, 183, 107, 255);
public static readonly TPixel DarkKhaki = ColorBuilder<TPixel>.FromRgba(189, 183, 107, 255);
/// <summary>
/// Represents a <see paramref="TPixel"/> matching the W3C definition that has an hex value of #8B008B.
/// </summary>
public static readonly TPixel DarkMagenta = ColorBuilder<TPixel>.FromRGBA(139, 0, 139, 255);
public static readonly TPixel DarkMagenta = ColorBuilder<TPixel>.FromRgba(139, 0, 139, 255);
/// <summary>
/// Represents a <see paramref="TPixel"/> matching the W3C definition that has an hex value of #556B2F.
/// </summary>
public static readonly TPixel DarkOliveGreen = ColorBuilder<TPixel>.FromRGBA(85, 107, 47, 255);
public static readonly TPixel DarkOliveGreen = ColorBuilder<TPixel>.FromRgba(85, 107, 47, 255);
/// <summary>
/// Represents a <see paramref="TPixel"/> matching the W3C definition that has an hex value of #FF8C00.
/// </summary>
public static readonly TPixel DarkOrange = ColorBuilder<TPixel>.FromRGBA(255, 140, 0, 255);
public static readonly TPixel DarkOrange = ColorBuilder<TPixel>.FromRgba(255, 140, 0, 255);
/// <summary>
/// Represents a <see paramref="TPixel"/> matching the W3C definition that has an hex value of #9932CC.
/// </summary>
public static readonly TPixel DarkOrchid = ColorBuilder<TPixel>.FromRGBA(153, 50, 204, 255);
public static readonly TPixel DarkOrchid = ColorBuilder<TPixel>.FromRgba(153, 50, 204, 255);
/// <summary>
/// Represents a <see paramref="TPixel"/> matching the W3C definition that has an hex value of #8B0000.
/// </summary>
public static readonly TPixel DarkRed = ColorBuilder<TPixel>.FromRGBA(139, 0, 0, 255);
public static readonly TPixel DarkRed = ColorBuilder<TPixel>.FromRgba(139, 0, 0, 255);
/// <summary>
/// Represents a <see paramref="TPixel"/> matching the W3C definition that has an hex value of #E9967A.
/// </summary>
public static readonly TPixel DarkSalmon = ColorBuilder<TPixel>.FromRGBA(233, 150, 122, 255);
public static readonly TPixel DarkSalmon = ColorBuilder<TPixel>.FromRgba(233, 150, 122, 255);
/// <summary>
/// Represents a <see paramref="TPixel"/> matching the W3C definition that has an hex value of #8FBC8B.
/// </summary>
public static readonly TPixel DarkSeaGreen = ColorBuilder<TPixel>.FromRGBA(143, 188, 139, 255);
public static readonly TPixel DarkSeaGreen = ColorBuilder<TPixel>.FromRgba(143, 188, 139, 255);
/// <summary>
/// Represents a <see paramref="TPixel"/> matching the W3C definition that has an hex value of #483D8B.
/// </summary>
public static readonly TPixel DarkSlateBlue = ColorBuilder<TPixel>.FromRGBA(72, 61, 139, 255);
public static readonly TPixel DarkSlateBlue = ColorBuilder<TPixel>.FromRgba(72, 61, 139, 255);
/// <summary>
/// Represents a <see paramref="TPixel"/> matching the W3C definition that has an hex value of #2F4F4F.
/// </summary>
public static readonly TPixel DarkSlateGray = ColorBuilder<TPixel>.FromRGBA(47, 79, 79, 255);
public static readonly TPixel DarkSlateGray = ColorBuilder<TPixel>.FromRgba(47, 79, 79, 255);
/// <summary>
/// Represents a <see paramref="TPixel"/> matching the W3C definition that has an hex value of #00CED1.
/// </summary>
public static readonly TPixel DarkTurquoise = ColorBuilder<TPixel>.FromRGBA(0, 206, 209, 255);
public static readonly TPixel DarkTurquoise = ColorBuilder<TPixel>.FromRgba(0, 206, 209, 255);
/// <summary>
/// Represents a <see paramref="TPixel"/> matching the W3C definition that has an hex value of #9400D3.
/// </summary>
public static readonly TPixel DarkViolet = ColorBuilder<TPixel>.FromRGBA(148, 0, 211, 255);
public static readonly TPixel DarkViolet = ColorBuilder<TPixel>.FromRgba(148, 0, 211, 255);
/// <summary>
/// Represents a <see paramref="TPixel"/> matching the W3C definition that has an hex value of #FF1493.
/// </summary>
public static readonly TPixel DeepPink = ColorBuilder<TPixel>.FromRGBA(255, 20, 147, 255);
public static readonly TPixel DeepPink = ColorBuilder<TPixel>.FromRgba(255, 20, 147, 255);
/// <summary>
/// Represents a <see paramref="TPixel"/> matching the W3C definition that has an hex value of #00BFFF.
/// </summary>
public static readonly TPixel DeepSkyBlue = ColorBuilder<TPixel>.FromRGBA(0, 191, 255, 255);
public static readonly TPixel DeepSkyBlue = ColorBuilder<TPixel>.FromRgba(0, 191, 255, 255);
/// <summary>
/// Represents a <see paramref="TPixel"/> matching the W3C definition that has an hex value of #696969.
/// </summary>
public static readonly TPixel DimGray = ColorBuilder<TPixel>.FromRGBA(105, 105, 105, 255);
public static readonly TPixel DimGray = ColorBuilder<TPixel>.FromRgba(105, 105, 105, 255);
/// <summary>
/// Represents a <see paramref="TPixel"/> matching the W3C definition that has an hex value of #1E90FF.
/// </summary>
public static readonly TPixel DodgerBlue = ColorBuilder<TPixel>.FromRGBA(30, 144, 255, 255);
public static readonly TPixel DodgerBlue = ColorBuilder<TPixel>.FromRgba(30, 144, 255, 255);
/// <summary>
/// Represents a <see paramref="TPixel"/> matching the W3C definition that has an hex value of #B22222.
/// </summary>
public static readonly TPixel Firebrick = ColorBuilder<TPixel>.FromRGBA(178, 34, 34, 255);
public static readonly TPixel Firebrick = ColorBuilder<TPixel>.FromRgba(178, 34, 34, 255);
/// <summary>
/// Represents a <see paramref="TPixel"/> matching the W3C definition that has an hex value of #FFFAF0.
/// </summary>
public static readonly TPixel FloralWhite = ColorBuilder<TPixel>.FromRGBA(255, 250, 240, 255);
public static readonly TPixel FloralWhite = ColorBuilder<TPixel>.FromRgba(255, 250, 240, 255);
/// <summary>
/// Represents a <see paramref="TPixel"/> matching the W3C definition that has an hex value of #228B22.
/// </summary>
public static readonly TPixel ForestGreen = ColorBuilder<TPixel>.FromRGBA(34, 139, 34, 255);
public static readonly TPixel ForestGreen = ColorBuilder<TPixel>.FromRgba(34, 139, 34, 255);
/// <summary>
/// Represents a <see paramref="TPixel"/> matching the W3C definition that has an hex value of #FF00FF.
/// </summary>
public static readonly TPixel Fuchsia = ColorBuilder<TPixel>.FromRGBA(255, 0, 255, 255);
public static readonly TPixel Fuchsia = ColorBuilder<TPixel>.FromRgba(255, 0, 255, 255);
/// <summary>
/// Represents a <see paramref="TPixel"/> matching the W3C definition that has an hex value of #DCDCDC.
/// </summary>
public static readonly TPixel Gainsboro = ColorBuilder<TPixel>.FromRGBA(220, 220, 220, 255);
public static readonly TPixel Gainsboro = ColorBuilder<TPixel>.FromRgba(220, 220, 220, 255);
/// <summary>
/// Represents a <see paramref="TPixel"/> matching the W3C definition that has an hex value of #F8F8FF.
/// </summary>
public static readonly TPixel GhostWhite = ColorBuilder<TPixel>.FromRGBA(248, 248, 255, 255);
public static readonly TPixel GhostWhite = ColorBuilder<TPixel>.FromRgba(248, 248, 255, 255);
/// <summary>
/// Represents a <see paramref="TPixel"/> matching the W3C definition that has an hex value of #FFD700.
/// </summary>
public static readonly TPixel Gold = ColorBuilder<TPixel>.FromRGBA(255, 215, 0, 255);
public static readonly TPixel Gold = ColorBuilder<TPixel>.FromRgba(255, 215, 0, 255);
/// <summary>
/// Represents a <see paramref="TPixel"/> matching the W3C definition that has an hex value of #DAA520.
/// </summary>
public static readonly TPixel Goldenrod = ColorBuilder<TPixel>.FromRGBA(218, 165, 32, 255);
public static readonly TPixel Goldenrod = ColorBuilder<TPixel>.FromRgba(218, 165, 32, 255);
/// <summary>
/// Represents a <see paramref="TPixel"/> matching the W3C definition that has an hex value of #808080.
/// </summary>
public static readonly TPixel Gray = ColorBuilder<TPixel>.FromRGBA(128, 128, 128, 255);
public static readonly TPixel Gray = ColorBuilder<TPixel>.FromRgba(128, 128, 128, 255);
/// <summary>
/// Represents a <see paramref="TPixel"/> matching the W3C definition that has an hex value of #008000.
/// </summary>
public static readonly TPixel Green = ColorBuilder<TPixel>.FromRGBA(0, 128, 0, 255);
public static readonly TPixel Green = ColorBuilder<TPixel>.FromRgba(0, 128, 0, 255);
/// <summary>
/// Represents a <see paramref="TPixel"/> matching the W3C definition that has an hex value of #ADFF2F.
/// </summary>
public static readonly TPixel GreenYellow = ColorBuilder<TPixel>.FromRGBA(173, 255, 47, 255);
public static readonly TPixel GreenYellow = ColorBuilder<TPixel>.FromRgba(173, 255, 47, 255);
/// <summary>
/// Represents a <see paramref="TPixel"/> matching the W3C definition that has an hex value of #F0FFF0.
/// </summary>
public static readonly TPixel Honeydew = ColorBuilder<TPixel>.FromRGBA(240, 255, 240, 255);
public static readonly TPixel Honeydew = ColorBuilder<TPixel>.FromRgba(240, 255, 240, 255);
/// <summary>
/// Represents a <see paramref="TPixel"/> matching the W3C definition that has an hex value of #FF69B4.
/// </summary>
public static readonly TPixel HotPink = ColorBuilder<TPixel>.FromRGBA(255, 105, 180, 255);
public static readonly TPixel HotPink = ColorBuilder<TPixel>.FromRgba(255, 105, 180, 255);
/// <summary>
/// Represents a <see paramref="TPixel"/> matching the W3C definition that has an hex value of #CD5C5C.
/// </summary>
public static readonly TPixel IndianRed = ColorBuilder<TPixel>.FromRGBA(205, 92, 92, 255);
public static readonly TPixel IndianRed = ColorBuilder<TPixel>.FromRgba(205, 92, 92, 255);
/// <summary>
/// Represents a <see paramref="TPixel"/> matching the W3C definition that has an hex value of #4B0082.
/// </summary>
public static readonly TPixel Indigo = ColorBuilder<TPixel>.FromRGBA(75, 0, 130, 255);
public static readonly TPixel Indigo = ColorBuilder<TPixel>.FromRgba(75, 0, 130, 255);
/// <summary>
/// Represents a <see paramref="TPixel"/> matching the W3C definition that has an hex value of #FFFFF0.
/// </summary>
public static readonly TPixel Ivory = ColorBuilder<TPixel>.FromRGBA(255, 255, 240, 255);
public static readonly TPixel Ivory = ColorBuilder<TPixel>.FromRgba(255, 255, 240, 255);
/// <summary>
/// Represents a <see paramref="TPixel"/> matching the W3C definition that has an hex value of #F0E68C.
/// </summary>
public static readonly TPixel Khaki = ColorBuilder<TPixel>.FromRGBA(240, 230, 140, 255);
public static readonly TPixel Khaki = ColorBuilder<TPixel>.FromRgba(240, 230, 140, 255);
/// <summary>
/// Represents a <see paramref="TPixel"/> matching the W3C definition that has an hex value of #E6E6FA.
/// </summary>
public static readonly TPixel Lavender = ColorBuilder<TPixel>.FromRGBA(230, 230, 250, 255);
public static readonly TPixel Lavender = ColorBuilder<TPixel>.FromRgba(230, 230, 250, 255);
/// <summary>
/// Represents a <see paramref="TPixel"/> matching the W3C definition that has an hex value of #FFF0F5.
/// </summary>
public static readonly TPixel LavenderBlush = ColorBuilder<TPixel>.FromRGBA(255, 240, 245, 255);
public static readonly TPixel LavenderBlush = ColorBuilder<TPixel>.FromRgba(255, 240, 245, 255);
/// <summary>
/// Represents a <see paramref="TPixel"/> matching the W3C definition that has an hex value of #7CFC00.
/// </summary>
public static readonly TPixel LawnGreen = ColorBuilder<TPixel>.FromRGBA(124, 252, 0, 255);
public static readonly TPixel LawnGreen = ColorBuilder<TPixel>.FromRgba(124, 252, 0, 255);
/// <summary>
/// Represents a <see paramref="TPixel"/> matching the W3C definition that has an hex value of #FFFACD.
/// </summary>
public static readonly TPixel LemonChiffon = ColorBuilder<TPixel>.FromRGBA(255, 250, 205, 255);
public static readonly TPixel LemonChiffon = ColorBuilder<TPixel>.FromRgba(255, 250, 205, 255);
/// <summary>
/// Represents a <see paramref="TPixel"/> matching the W3C definition that has an hex value of #ADD8E6.
/// </summary>
public static readonly TPixel LightBlue = ColorBuilder<TPixel>.FromRGBA(173, 216, 230, 255);
public static readonly TPixel LightBlue = ColorBuilder<TPixel>.FromRgba(173, 216, 230, 255);
/// <summary>
/// Represents a <see paramref="TPixel"/> matching the W3C definition that has an hex value of #F08080.
/// </summary>
public static readonly TPixel LightCoral = ColorBuilder<TPixel>.FromRGBA(240, 128, 128, 255);
public static readonly TPixel LightCoral = ColorBuilder<TPixel>.FromRgba(240, 128, 128, 255);
/// <summary>
/// Represents a <see paramref="TPixel"/> matching the W3C definition that has an hex value of #E0FFFF.
/// </summary>
public static readonly TPixel LightCyan = ColorBuilder<TPixel>.FromRGBA(224, 255, 255, 255);
public static readonly TPixel LightCyan = ColorBuilder<TPixel>.FromRgba(224, 255, 255, 255);
/// <summary>
/// Represents a <see paramref="TPixel"/> matching the W3C definition that has an hex value of #FAFAD2.
/// </summary>
public static readonly TPixel LightGoldenrodYellow = ColorBuilder<TPixel>.FromRGBA(250, 250, 210, 255);
public static readonly TPixel LightGoldenrodYellow = ColorBuilder<TPixel>.FromRgba(250, 250, 210, 255);
/// <summary>
/// Represents a <see paramref="TPixel"/> matching the W3C definition that has an hex value of #D3D3D3.
/// </summary>
public static readonly TPixel LightGray = ColorBuilder<TPixel>.FromRGBA(211, 211, 211, 255);
public static readonly TPixel LightGray = ColorBuilder<TPixel>.FromRgba(211, 211, 211, 255);
/// <summary>
/// Represents a <see paramref="TPixel"/> matching the W3C definition that has an hex value of #90EE90.
/// </summary>
public static readonly TPixel LightGreen = ColorBuilder<TPixel>.FromRGBA(144, 238, 144, 255);
public static readonly TPixel LightGreen = ColorBuilder<TPixel>.FromRgba(144, 238, 144, 255);
/// <summary>
/// Represents a <see paramref="TPixel"/> matching the W3C definition that has an hex value of #FFB6C1.
/// </summary>
public static readonly TPixel LightPink = ColorBuilder<TPixel>.FromRGBA(255, 182, 193, 255);
public static readonly TPixel LightPink = ColorBuilder<TPixel>.FromRgba(255, 182, 193, 255);
/// <summary>
/// Represents a <see paramref="TPixel"/> matching the W3C definition that has an hex value of #FFA07A.
/// </summary>
public static readonly TPixel LightSalmon = ColorBuilder<TPixel>.FromRGBA(255, 160, 122, 255);
public static readonly TPixel LightSalmon = ColorBuilder<TPixel>.FromRgba(255, 160, 122, 255);
/// <summary>
/// Represents a <see paramref="TPixel"/> matching the W3C definition that has an hex value of #20B2AA.
/// </summary>
public static readonly TPixel LightSeaGreen = ColorBuilder<TPixel>.FromRGBA(32, 178, 170, 255);
public static readonly TPixel LightSeaGreen = ColorBuilder<TPixel>.FromRgba(32, 178, 170, 255);
/// <summary>
/// Represents a <see paramref="TPixel"/> matching the W3C definition that has an hex value of #87CEFA.
/// </summary>
public static readonly TPixel LightSkyBlue = ColorBuilder<TPixel>.FromRGBA(135, 206, 250, 255);
public static readonly TPixel LightSkyBlue = ColorBuilder<TPixel>.FromRgba(135, 206, 250, 255);
/// <summary>
/// Represents a <see paramref="TPixel"/> matching the W3C definition that has an hex value of #778899.
/// </summary>
public static readonly TPixel LightSlateGray = ColorBuilder<TPixel>.FromRGBA(119, 136, 153, 255);
public static readonly TPixel LightSlateGray = ColorBuilder<TPixel>.FromRgba(119, 136, 153, 255);
/// <summary>
/// Represents a <see paramref="TPixel"/> matching the W3C definition that has an hex value of #B0C4DE.
/// </summary>
public static readonly TPixel LightSteelBlue = ColorBuilder<TPixel>.FromRGBA(176, 196, 222, 255);
public static readonly TPixel LightSteelBlue = ColorBuilder<TPixel>.FromRgba(176, 196, 222, 255);
/// <summary>
/// Represents a <see paramref="TPixel"/> matching the W3C definition that has an hex value of #FFFFE0.
/// </summary>
public static readonly TPixel LightYellow = ColorBuilder<TPixel>.FromRGBA(255, 255, 224, 255);
public static readonly TPixel LightYellow = ColorBuilder<TPixel>.FromRgba(255, 255, 224, 255);
/// <summary>
/// Represents a <see paramref="TPixel"/> matching the W3C definition that has an hex value of #00FF00.
/// </summary>
public static readonly TPixel Lime = ColorBuilder<TPixel>.FromRGBA(0, 255, 0, 255);
public static readonly TPixel Lime = ColorBuilder<TPixel>.FromRgba(0, 255, 0, 255);
/// <summary>
/// Represents a <see paramref="TPixel"/> matching the W3C definition that has an hex value of #32CD32.
/// </summary>
public static readonly TPixel LimeGreen = ColorBuilder<TPixel>.FromRGBA(50, 205, 50, 255);
public static readonly TPixel LimeGreen = ColorBuilder<TPixel>.FromRgba(50, 205, 50, 255);
/// <summary>
/// Represents a <see paramref="TPixel"/> matching the W3C definition that has an hex value of #FAF0E6.
/// </summary>
public static readonly TPixel Linen = ColorBuilder<TPixel>.FromRGBA(250, 240, 230, 255);
public static readonly TPixel Linen = ColorBuilder<TPixel>.FromRgba(250, 240, 230, 255);
/// <summary>
/// Represents a <see paramref="TPixel"/> matching the W3C definition that has an hex value of #FF00FF.
/// </summary>
public static readonly TPixel Magenta = ColorBuilder<TPixel>.FromRGBA(255, 0, 255, 255);
public static readonly TPixel Magenta = ColorBuilder<TPixel>.FromRgba(255, 0, 255, 255);
/// <summary>
/// Represents a <see paramref="TPixel"/> matching the W3C definition that has an hex value of #800000.
/// </summary>
public static readonly TPixel Maroon = ColorBuilder<TPixel>.FromRGBA(128, 0, 0, 255);
public static readonly TPixel Maroon = ColorBuilder<TPixel>.FromRgba(128, 0, 0, 255);
/// <summary>
/// Represents a <see paramref="TPixel"/> matching the W3C definition that has an hex value of #66CDAA.
/// </summary>
public static readonly TPixel MediumAquamarine = ColorBuilder<TPixel>.FromRGBA(102, 205, 170, 255);
public static readonly TPixel MediumAquamarine = ColorBuilder<TPixel>.FromRgba(102, 205, 170, 255);
/// <summary>
/// Represents a <see paramref="TPixel"/> matching the W3C definition that has an hex value of #0000CD.
/// </summary>
public static readonly TPixel MediumBlue = ColorBuilder<TPixel>.FromRGBA(0, 0, 205, 255);
public static readonly TPixel MediumBlue = ColorBuilder<TPixel>.FromRgba(0, 0, 205, 255);
/// <summary>
/// Represents a <see paramref="TPixel"/> matching the W3C definition that has an hex value of #BA55D3.
/// </summary>
public static readonly TPixel MediumOrchid = ColorBuilder<TPixel>.FromRGBA(186, 85, 211, 255);
public static readonly TPixel MediumOrchid = ColorBuilder<TPixel>.FromRgba(186, 85, 211, 255);
/// <summary>
/// Represents a <see paramref="TPixel"/> matching the W3C definition that has an hex value of #9370DB.
/// </summary>
public static readonly TPixel MediumPurple = ColorBuilder<TPixel>.FromRGBA(147, 112, 219, 255);
public static readonly TPixel MediumPurple = ColorBuilder<TPixel>.FromRgba(147, 112, 219, 255);
/// <summary>
/// Represents a <see paramref="TPixel"/> matching the W3C definition that has an hex value of #3CB371.
/// </summary>
public static readonly TPixel MediumSeaGreen = ColorBuilder<TPixel>.FromRGBA(60, 179, 113, 255);
public static readonly TPixel MediumSeaGreen = ColorBuilder<TPixel>.FromRgba(60, 179, 113, 255);
/// <summary>
/// Represents a <see paramref="TPixel"/> matching the W3C definition that has an hex value of #7B68EE.
/// </summary>
public static readonly TPixel MediumSlateBlue = ColorBuilder<TPixel>.FromRGBA(123, 104, 238, 255);
public static readonly TPixel MediumSlateBlue = ColorBuilder<TPixel>.FromRgba(123, 104, 238, 255);
/// <summary>
/// Represents a <see paramref="TPixel"/> matching the W3C definition that has an hex value of #00FA9A.
/// </summary>
public static readonly TPixel MediumSpringGreen = ColorBuilder<TPixel>.FromRGBA(0, 250, 154, 255);
public static readonly TPixel MediumSpringGreen = ColorBuilder<TPixel>.FromRgba(0, 250, 154, 255);
/// <summary>
/// Represents a <see paramref="TPixel"/> matching the W3C definition that has an hex value of #48D1CC.
/// </summary>
public static readonly TPixel MediumTurquoise = ColorBuilder<TPixel>.FromRGBA(72, 209, 204, 255);
public static readonly TPixel MediumTurquoise = ColorBuilder<TPixel>.FromRgba(72, 209, 204, 255);
/// <summary>
/// Represents a <see paramref="TPixel"/> matching the W3C definition that has an hex value of #C71585.
/// </summary>
public static readonly TPixel MediumVioletRed = ColorBuilder<TPixel>.FromRGBA(199, 21, 133, 255);
public static readonly TPixel MediumVioletRed = ColorBuilder<TPixel>.FromRgba(199, 21, 133, 255);
/// <summary>
/// Represents a <see paramref="TPixel"/> matching the W3C definition that has an hex value of #191970.
/// </summary>
public static readonly TPixel MidnightBlue = ColorBuilder<TPixel>.FromRGBA(25, 25, 112, 255);
public static readonly TPixel MidnightBlue = ColorBuilder<TPixel>.FromRgba(25, 25, 112, 255);
/// <summary>
/// Represents a <see paramref="TPixel"/> matching the W3C definition that has an hex value of #F5FFFA.
/// </summary>
public static readonly TPixel MintCream = ColorBuilder<TPixel>.FromRGBA(245, 255, 250, 255);
public static readonly TPixel MintCream = ColorBuilder<TPixel>.FromRgba(245, 255, 250, 255);
/// <summary>
/// Represents a <see paramref="TPixel"/> matching the W3C definition that has an hex value of #FFE4E1.
/// </summary>
public static readonly TPixel MistyRose = ColorBuilder<TPixel>.FromRGBA(255, 228, 225, 255);
public static readonly TPixel MistyRose = ColorBuilder<TPixel>.FromRgba(255, 228, 225, 255);
/// <summary>
/// Represents a <see paramref="TPixel"/> matching the W3C definition that has an hex value of #FFE4B5.
/// </summary>
public static readonly TPixel Moccasin = ColorBuilder<TPixel>.FromRGBA(255, 228, 181, 255);
public static readonly TPixel Moccasin = ColorBuilder<TPixel>.FromRgba(255, 228, 181, 255);
/// <summary>
/// Represents a <see paramref="TPixel"/> matching the W3C definition that has an hex value of #FFDEAD.
/// </summary>
public static readonly TPixel NavajoWhite = ColorBuilder<TPixel>.FromRGBA(255, 222, 173, 255);
public static readonly TPixel NavajoWhite = ColorBuilder<TPixel>.FromRgba(255, 222, 173, 255);
/// <summary>
/// Represents a <see paramref="TPixel"/> matching the W3C definition that has an hex value of #000080.
/// </summary>
public static readonly TPixel Navy = ColorBuilder<TPixel>.FromRGBA(0, 0, 128, 255);
public static readonly TPixel Navy = ColorBuilder<TPixel>.FromRgba(0, 0, 128, 255);
/// <summary>
/// Represents a <see paramref="TPixel"/> matching the W3C definition that has an hex value of #FDF5E6.
/// </summary>
public static readonly TPixel OldLace = ColorBuilder<TPixel>.FromRGBA(253, 245, 230, 255);
public static readonly TPixel OldLace = ColorBuilder<TPixel>.FromRgba(253, 245, 230, 255);
/// <summary>
/// Represents a <see paramref="TPixel"/> matching the W3C definition that has an hex value of #808000.
/// </summary>
public static readonly TPixel Olive = ColorBuilder<TPixel>.FromRGBA(128, 128, 0, 255);
public static readonly TPixel Olive = ColorBuilder<TPixel>.FromRgba(128, 128, 0, 255);
/// <summary>
/// Represents a <see paramref="TPixel"/> matching the W3C definition that has an hex value of #6B8E23.
/// </summary>
public static readonly TPixel OliveDrab = ColorBuilder<TPixel>.FromRGBA(107, 142, 35, 255);
public static readonly TPixel OliveDrab = ColorBuilder<TPixel>.FromRgba(107, 142, 35, 255);
/// <summary>
/// Represents a <see paramref="TPixel"/> matching the W3C definition that has an hex value of #FFA500.
/// </summary>
public static readonly TPixel Orange = ColorBuilder<TPixel>.FromRGBA(255, 165, 0, 255);
public static readonly TPixel Orange = ColorBuilder<TPixel>.FromRgba(255, 165, 0, 255);
/// <summary>
/// Represents a <see paramref="TPixel"/> matching the W3C definition that has an hex value of #FF4500.
/// </summary>
public static readonly TPixel OrangeRed = ColorBuilder<TPixel>.FromRGBA(255, 69, 0, 255);
public static readonly TPixel OrangeRed = ColorBuilder<TPixel>.FromRgba(255, 69, 0, 255);
/// <summary>
/// Represents a <see paramref="TPixel"/> matching the W3C definition that has an hex value of #DA70D6.
/// </summary>
public static readonly TPixel Orchid = ColorBuilder<TPixel>.FromRGBA(218, 112, 214, 255);
public static readonly TPixel Orchid = ColorBuilder<TPixel>.FromRgba(218, 112, 214, 255);
/// <summary>
/// Represents a <see paramref="TPixel"/> matching the W3C definition that has an hex value of #EEE8AA.
/// </summary>
public static readonly TPixel PaleGoldenrod = ColorBuilder<TPixel>.FromRGBA(238, 232, 170, 255);
public static readonly TPixel PaleGoldenrod = ColorBuilder<TPixel>.FromRgba(238, 232, 170, 255);
/// <summary>
/// Represents a <see paramref="TPixel"/> matching the W3C definition that has an hex value of #98FB98.
/// </summary>
public static readonly TPixel PaleGreen = ColorBuilder<TPixel>.FromRGBA(152, 251, 152, 255);
public static readonly TPixel PaleGreen = ColorBuilder<TPixel>.FromRgba(152, 251, 152, 255);
/// <summary>
/// Represents a <see paramref="TPixel"/> matching the W3C definition that has an hex value of #AFEEEE.
/// </summary>
public static readonly TPixel PaleTurquoise = ColorBuilder<TPixel>.FromRGBA(175, 238, 238, 255);
public static readonly TPixel PaleTurquoise = ColorBuilder<TPixel>.FromRgba(175, 238, 238, 255);
/// <summary>
/// Represents a <see paramref="TPixel"/> matching the W3C definition that has an hex value of #DB7093.
/// </summary>
public static readonly TPixel PaleVioletRed = ColorBuilder<TPixel>.FromRGBA(219, 112, 147, 255);
public static readonly TPixel PaleVioletRed = ColorBuilder<TPixel>.FromRgba(219, 112, 147, 255);
/// <summary>
/// Represents a <see paramref="TPixel"/> matching the W3C definition that has an hex value of #FFEFD5.
/// </summary>
public static readonly TPixel PapayaWhip = ColorBuilder<TPixel>.FromRGBA(255, 239, 213, 255);
public static readonly TPixel PapayaWhip = ColorBuilder<TPixel>.FromRgba(255, 239, 213, 255);
/// <summary>
/// Represents a <see paramref="TPixel"/> matching the W3C definition that has an hex value of #FFDAB9.
/// </summary>
public static readonly TPixel PeachPuff = ColorBuilder<TPixel>.FromRGBA(255, 218, 185, 255);
public static readonly TPixel PeachPuff = ColorBuilder<TPixel>.FromRgba(255, 218, 185, 255);
/// <summary>
/// Represents a <see paramref="TPixel"/> matching the W3C definition that has an hex value of #CD853F.
/// </summary>
public static readonly TPixel Peru = ColorBuilder<TPixel>.FromRGBA(205, 133, 63, 255);
public static readonly TPixel Peru = ColorBuilder<TPixel>.FromRgba(205, 133, 63, 255);
/// <summary>
/// Represents a <see paramref="TPixel"/> matching the W3C definition that has an hex value of #FFC0CB.
/// </summary>
public static readonly TPixel Pink = ColorBuilder<TPixel>.FromRGBA(255, 192, 203, 255);
public static readonly TPixel Pink = ColorBuilder<TPixel>.FromRgba(255, 192, 203, 255);
/// <summary>
/// Represents a <see paramref="TPixel"/> matching the W3C definition that has an hex value of #DDA0DD.
/// </summary>
public static readonly TPixel Plum = ColorBuilder<TPixel>.FromRGBA(221, 160, 221, 255);
public static readonly TPixel Plum = ColorBuilder<TPixel>.FromRgba(221, 160, 221, 255);
/// <summary>
/// Represents a <see paramref="TPixel"/> matching the W3C definition that has an hex value of #B0E0E6.
/// </summary>
public static readonly TPixel PowderBlue = ColorBuilder<TPixel>.FromRGBA(176, 224, 230, 255);
public static readonly TPixel PowderBlue = ColorBuilder<TPixel>.FromRgba(176, 224, 230, 255);
/// <summary>
/// Represents a <see paramref="TPixel"/> matching the W3C definition that has an hex value of #800080.
/// </summary>
public static readonly TPixel Purple = ColorBuilder<TPixel>.FromRGBA(128, 0, 128, 255);
public static readonly TPixel Purple = ColorBuilder<TPixel>.FromRgba(128, 0, 128, 255);
/// <summary>
/// Represents a <see paramref="TPixel"/> matching the W3C definition that has an hex value of #663399.
/// </summary>
public static readonly TPixel RebeccaPurple = ColorBuilder<TPixel>.FromRGBA(102, 51, 153, 255);
public static readonly TPixel RebeccaPurple = ColorBuilder<TPixel>.FromRgba(102, 51, 153, 255);
/// <summary>
/// Represents a <see paramref="TPixel"/> matching the W3C definition that has an hex value of #FF0000.
/// </summary>
public static readonly TPixel Red = ColorBuilder<TPixel>.FromRGBA(255, 0, 0, 255);
public static readonly TPixel Red = ColorBuilder<TPixel>.FromRgba(255, 0, 0, 255);
/// <summary>
/// Represents a <see paramref="TPixel"/> matching the W3C definition that has an hex value of #BC8F8F.
/// </summary>
public static readonly TPixel RosyBrown = ColorBuilder<TPixel>.FromRGBA(188, 143, 143, 255);
public static readonly TPixel RosyBrown = ColorBuilder<TPixel>.FromRgba(188, 143, 143, 255);
/// <summary>
/// Represents a <see paramref="TPixel"/> matching the W3C definition that has an hex value of #4169E1.
/// </summary>
public static readonly TPixel RoyalBlue = ColorBuilder<TPixel>.FromRGBA(65, 105, 225, 255);
public static readonly TPixel RoyalBlue = ColorBuilder<TPixel>.FromRgba(65, 105, 225, 255);
/// <summary>
/// Represents a <see paramref="TPixel"/> matching the W3C definition that has an hex value of #8B4513.
/// </summary>
public static readonly TPixel SaddleBrown = ColorBuilder<TPixel>.FromRGBA(139, 69, 19, 255);
public static readonly TPixel SaddleBrown = ColorBuilder<TPixel>.FromRgba(139, 69, 19, 255);
/// <summary>
/// Represents a <see paramref="TPixel"/> matching the W3C definition that has an hex value of #FA8072.
/// </summary>
public static readonly TPixel Salmon = ColorBuilder<TPixel>.FromRGBA(250, 128, 114, 255);
public static readonly TPixel Salmon = ColorBuilder<TPixel>.FromRgba(250, 128, 114, 255);
/// <summary>
/// Represents a <see paramref="TPixel"/> matching the W3C definition that has an hex value of #F4A460.
/// </summary>
public static readonly TPixel SandyBrown = ColorBuilder<TPixel>.FromRGBA(244, 164, 96, 255);
public static readonly TPixel SandyBrown = ColorBuilder<TPixel>.FromRgba(244, 164, 96, 255);
/// <summary>
/// Represents a <see paramref="TPixel"/> matching the W3C definition that has an hex value of #2E8B57.
/// </summary>
public static readonly TPixel SeaGreen = ColorBuilder<TPixel>.FromRGBA(46, 139, 87, 255);
public static readonly TPixel SeaGreen = ColorBuilder<TPixel>.FromRgba(46, 139, 87, 255);
/// <summary>
/// Represents a <see paramref="TPixel"/> matching the W3C definition that has an hex value of #FFF5EE.
/// </summary>
public static readonly TPixel SeaShell = ColorBuilder<TPixel>.FromRGBA(255, 245, 238, 255);
public static readonly TPixel SeaShell = ColorBuilder<TPixel>.FromRgba(255, 245, 238, 255);
/// <summary>
/// Represents a <see paramref="TPixel"/> matching the W3C definition that has an hex value of #A0522D.
/// </summary>
public static readonly TPixel Sienna = ColorBuilder<TPixel>.FromRGBA(160, 82, 45, 255);
public static readonly TPixel Sienna = ColorBuilder<TPixel>.FromRgba(160, 82, 45, 255);
/// <summary>
/// Represents a <see paramref="TPixel"/> matching the W3C definition that has an hex value of #C0C0C0.
/// </summary>
public static readonly TPixel Silver = ColorBuilder<TPixel>.FromRGBA(192, 192, 192, 255);
public static readonly TPixel Silver = ColorBuilder<TPixel>.FromRgba(192, 192, 192, 255);
/// <summary>
/// Represents a <see paramref="TPixel"/> matching the W3C definition that has an hex value of #87CEEB.
/// </summary>
public static readonly TPixel SkyBlue = ColorBuilder<TPixel>.FromRGBA(135, 206, 235, 255);
public static readonly TPixel SkyBlue = ColorBuilder<TPixel>.FromRgba(135, 206, 235, 255);
/// <summary>
/// Represents a <see paramref="TPixel"/> matching the W3C definition that has an hex value of #6A5ACD.
/// </summary>
public static readonly TPixel SlateBlue = ColorBuilder<TPixel>.FromRGBA(106, 90, 205, 255);
public static readonly TPixel SlateBlue = ColorBuilder<TPixel>.FromRgba(106, 90, 205, 255);
/// <summary>
/// Represents a <see paramref="TPixel"/> matching the W3C definition that has an hex value of #708090.
/// </summary>
public static readonly TPixel SlateGray = ColorBuilder<TPixel>.FromRGBA(112, 128, 144, 255);
public static readonly TPixel SlateGray = ColorBuilder<TPixel>.FromRgba(112, 128, 144, 255);
/// <summary>
/// Represents a <see paramref="TPixel"/> matching the W3C definition that has an hex value of #FFFAFA.
/// </summary>
public static readonly TPixel Snow = ColorBuilder<TPixel>.FromRGBA(255, 250, 250, 255);
public static readonly TPixel Snow = ColorBuilder<TPixel>.FromRgba(255, 250, 250, 255);
/// <summary>
/// Represents a <see paramref="TPixel"/> matching the W3C definition that has an hex value of #00FF7F.
/// </summary>
public static readonly TPixel SpringGreen = ColorBuilder<TPixel>.FromRGBA(0, 255, 127, 255);
public static readonly TPixel SpringGreen = ColorBuilder<TPixel>.FromRgba(0, 255, 127, 255);
/// <summary>
/// Represents a <see paramref="TPixel"/> matching the W3C definition that has an hex value of #4682B4.
/// </summary>
public static readonly TPixel SteelBlue = ColorBuilder<TPixel>.FromRGBA(70, 130, 180, 255);
public static readonly TPixel SteelBlue = ColorBuilder<TPixel>.FromRgba(70, 130, 180, 255);
/// <summary>
/// Represents a <see paramref="TPixel"/> matching the W3C definition that has an hex value of #D2B48C.
/// </summary>
public static readonly TPixel Tan = ColorBuilder<TPixel>.FromRGBA(210, 180, 140, 255);
public static readonly TPixel Tan = ColorBuilder<TPixel>.FromRgba(210, 180, 140, 255);
/// <summary>
/// Represents a <see paramref="TPixel"/> matching the W3C definition that has an hex value of #008080.
/// </summary>
public static readonly TPixel Teal = ColorBuilder<TPixel>.FromRGBA(0, 128, 128, 255);
public static readonly TPixel Teal = ColorBuilder<TPixel>.FromRgba(0, 128, 128, 255);
/// <summary>
/// Represents a <see paramref="TPixel"/> matching the W3C definition that has an hex value of #D8BFD8.
/// </summary>
public static readonly TPixel Thistle = ColorBuilder<TPixel>.FromRGBA(216, 191, 216, 255);
public static readonly TPixel Thistle = ColorBuilder<TPixel>.FromRgba(216, 191, 216, 255);
/// <summary>
/// Represents a <see paramref="TPixel"/> matching the W3C definition that has an hex value of #FF6347.
/// </summary>
public static readonly TPixel Tomato = ColorBuilder<TPixel>.FromRGBA(255, 99, 71, 255);
public static readonly TPixel Tomato = ColorBuilder<TPixel>.FromRgba(255, 99, 71, 255);
/// <summary>
/// Represents a <see paramref="TPixel"/> matching the W3C definition that has an hex value of #FFFFFF.
/// </summary>
public static readonly TPixel Transparent = ColorBuilder<TPixel>.FromRGBA(255, 255, 255, 0);
public static readonly TPixel Transparent = ColorBuilder<TPixel>.FromRgba(255, 255, 255, 0);
/// <summary>
/// Represents a <see paramref="TPixel"/> matching the W3C definition that has an hex value of #40E0D0.
/// </summary>
public static readonly TPixel Turquoise = ColorBuilder<TPixel>.FromRGBA(64, 224, 208, 255);
public static readonly TPixel Turquoise = ColorBuilder<TPixel>.FromRgba(64, 224, 208, 255);
/// <summary>
/// Represents a <see paramref="TPixel"/> matching the W3C definition that has an hex value of #EE82EE.
/// </summary>
public static readonly TPixel Violet = ColorBuilder<TPixel>.FromRGBA(238, 130, 238, 255);
public static readonly TPixel Violet = ColorBuilder<TPixel>.FromRgba(238, 130, 238, 255);
/// <summary>
/// Represents a <see paramref="TPixel"/> matching the W3C definition that has an hex value of #F5DEB3.
/// </summary>
public static readonly TPixel Wheat = ColorBuilder<TPixel>.FromRGBA(245, 222, 179, 255);
public static readonly TPixel Wheat = ColorBuilder<TPixel>.FromRgba(245, 222, 179, 255);
/// <summary>
/// Represents a <see paramref="TPixel"/> matching the W3C definition that has an hex value of #FFFFFF.
/// </summary>
public static readonly TPixel White = ColorBuilder<TPixel>.FromRGBA(255, 255, 255, 255);
public static readonly TPixel White = ColorBuilder<TPixel>.FromRgba(255, 255, 255, 255);
/// <summary>
/// Represents a <see paramref="TPixel"/> matching the W3C definition that has an hex value of #F5F5F5.
/// </summary>
public static readonly TPixel WhiteSmoke = ColorBuilder<TPixel>.FromRGBA(245, 245, 245, 255);
public static readonly TPixel WhiteSmoke = ColorBuilder<TPixel>.FromRgba(245, 245, 245, 255);
/// <summary>
/// Represents a <see paramref="TPixel"/> matching the W3C definition that has an hex value of #FFFF00.
/// </summary>
public static readonly TPixel Yellow = ColorBuilder<TPixel>.FromRGBA(255, 255, 0, 255);
public static readonly TPixel Yellow = ColorBuilder<TPixel>.FromRgba(255, 255, 0, 255);
/// <summary>
/// Represents a <see paramref="TPixel"/> matching the W3C definition that has an hex value of #9ACD32.
/// </summary>
public static readonly TPixel YellowGreen = ColorBuilder<TPixel>.FromRGBA(154, 205, 50, 255);
public static readonly TPixel YellowGreen = ColorBuilder<TPixel>.FromRgba(154, 205, 50, 255);
/// <summary>
/// Gets a <see cref="T:TPixel[]"/> collection of web safe, colors as defined in the CSS Color Module Level 4.

16
src/ImageSharp/PixelFormats/PixelImplementations/Argb32.cs

@ -142,6 +142,22 @@ namespace SixLabors.ImageSharp.PixelFormats
set => this.Argb = value;
}
/// <summary>
/// Converts an <see cref="Argb32"/> to <see cref="Color"/>.
/// </summary>
/// <param name="source">The <see cref="Argb32"/>.</param>
/// <returns>The <see cref="Color"/>.</returns>
[MethodImpl(InliningOptions.ShortMethod)]
public static implicit operator Color(Argb32 source) => new Color(source);
/// <summary>
/// Converts a <see cref="Color"/> to <see cref="Argb32"/>.
/// </summary>
/// <param name="color">The <see cref="Color"/>.</param>
/// <returns>The <see cref="Argb32"/>.</returns>
[MethodImpl(InliningOptions.ShortMethod)]
public static implicit operator Argb32(Color color) => color.ToArgb32();
/// <summary>
/// Compares two <see cref="Argb32"/> objects for equality.
/// </summary>

16
src/ImageSharp/PixelFormats/PixelImplementations/Bgr24.cs

@ -50,6 +50,22 @@ namespace SixLabors.ImageSharp.PixelFormats
this.B = b;
}
/// <summary>
/// Converts an <see cref="Bgr24"/> to <see cref="Color"/>.
/// </summary>
/// <param name="source">The <see cref="Bgr24"/>.</param>
/// <returns>The <see cref="Color"/>.</returns>
[MethodImpl(InliningOptions.ShortMethod)]
public static implicit operator Color(Bgr24 source) => new Color(source);
/// <summary>
/// Converts a <see cref="Color"/> to <see cref="Bgr24"/>.
/// </summary>
/// <param name="color">The <see cref="Color"/>.</param>
/// <returns>The <see cref="Bgr24"/>.</returns>
[MethodImpl(InliningOptions.ShortMethod)]
public static implicit operator Bgr24(Color color) => color.ToBgr24();
/// <summary>
/// Compares two <see cref="Bgr24"/> objects for equality.
/// </summary>

16
src/ImageSharp/PixelFormats/PixelImplementations/Bgra32.cs

@ -98,6 +98,22 @@ namespace SixLabors.ImageSharp.PixelFormats
set => this.Bgra = value;
}
/// <summary>
/// Converts an <see cref="Bgra32"/> to <see cref="Color"/>.
/// </summary>
/// <param name="source">The <see cref="Bgra32"/>.</param>
/// <returns>The <see cref="Color"/>.</returns>
[MethodImpl(InliningOptions.ShortMethod)]
public static implicit operator Color(Bgra32 source) => new Color(source);
/// <summary>
/// Converts a <see cref="Color"/> to <see cref="Bgra32"/>.
/// </summary>
/// <param name="color">The <see cref="Color"/>.</param>
/// <returns>The <see cref="Bgra32"/>.</returns>
[MethodImpl(InliningOptions.ShortMethod)]
public static implicit operator Bgra32(Color color) => color.ToBgra32();
/// <summary>
/// Compares two <see cref="Bgra32"/> objects for equality.
/// </summary>

16
src/ImageSharp/PixelFormats/PixelImplementations/Rgb24.cs

@ -53,6 +53,22 @@ namespace SixLabors.ImageSharp.PixelFormats
this.B = b;
}
/// <summary>
/// Converts an <see cref="Rgb24"/> to <see cref="Color"/>.
/// </summary>
/// <param name="source">The <see cref="Rgb24"/>.</param>
/// <returns>The <see cref="Color"/>.</returns>
[MethodImpl(InliningOptions.ShortMethod)]
public static implicit operator Color(Rgb24 source) => new Color(source);
/// <summary>
/// Converts a <see cref="Color"/> to <see cref="Rgb24"/>.
/// </summary>
/// <param name="color">The <see cref="Color"/>.</param>
/// <returns>The <see cref="Rgb24"/>.</returns>
[MethodImpl(InliningOptions.ShortMethod)]
public static implicit operator Rgb24(Color color) => color.ToRgb24();
/// <summary>
/// Allows the implicit conversion of an instance of <see cref="ColorSpaces.Rgb"/> to a
/// <see cref="Rgb24"/>.

16
src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.cs

@ -169,6 +169,22 @@ namespace SixLabors.ImageSharp.PixelFormats
set => this.Rgba = value;
}
/// <summary>
/// Converts an <see cref="Rgba32"/> to <see cref="Color"/>.
/// </summary>
/// <param name="source">The <see cref="Rgba32"/>.</param>
/// <returns>The <see cref="Color"/>.</returns>
[MethodImpl(InliningOptions.ShortMethod)]
public static implicit operator Color(Rgba32 source) => new Color(source);
/// <summary>
/// Converts a <see cref="Color"/> to <see cref="Rgba32"/>.
/// </summary>
/// <param name="color">The <see cref="Color"/>.</param>
/// <returns>The <see cref="Rgba32"/>.</returns>
[MethodImpl(InliningOptions.ShortMethod)]
public static implicit operator Rgba32(Color color) => color.ToRgba32();
/// <summary>
/// Allows the implicit conversion of an instance of <see cref="ColorSpaces.Rgb"/> to a
/// <see cref="Rgba32"/>.

166
src/ImageSharp/PixelFormats/PixelImplementations/Rgba64.cs

@ -46,6 +46,7 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <param name="g">The green component.</param>
/// <param name="b">The blue component.</param>
/// <param name="a">The alpha component.</param>
[MethodImpl(InliningOptions.ShortMethod)]
public Rgba64(ushort r, ushort g, ushort b, ushort a)
{
this.R = r;
@ -55,7 +56,86 @@ namespace SixLabors.ImageSharp.PixelFormats
}
/// <summary>
/// Gets or sets the RGB components of this struct as <see cref="Rgb48"/>
/// Initializes a new instance of the <see cref="Rgba64"/> struct.
/// </summary>
/// <param name="source">A structure of 4 bytes in RGBA byte order.</param>
[MethodImpl(InliningOptions.ShortMethod)]
public Rgba64(Rgba32 source)
{
this.R = ImageMaths.UpscaleFrom8BitTo16Bit(source.R);
this.G = ImageMaths.UpscaleFrom8BitTo16Bit(source.G);
this.B = ImageMaths.UpscaleFrom8BitTo16Bit(source.B);
this.A = ImageMaths.UpscaleFrom8BitTo16Bit(source.A);
}
/// <summary>
/// Initializes a new instance of the <see cref="Rgba64"/> struct.
/// </summary>
/// <param name="source">A structure of 4 bytes in BGRA byte order.</param>
[MethodImpl(InliningOptions.ShortMethod)]
public Rgba64(Bgra32 source)
{
this.R = ImageMaths.UpscaleFrom8BitTo16Bit(source.R);
this.G = ImageMaths.UpscaleFrom8BitTo16Bit(source.G);
this.B = ImageMaths.UpscaleFrom8BitTo16Bit(source.B);
this.A = ImageMaths.UpscaleFrom8BitTo16Bit(source.A);
}
/// <summary>
/// Initializes a new instance of the <see cref="Rgba64"/> struct.
/// </summary>
/// <param name="source">A structure of 4 bytes in ARGB byte order.</param>
[MethodImpl(InliningOptions.ShortMethod)]
public Rgba64(Argb32 source)
{
this.R = ImageMaths.UpscaleFrom8BitTo16Bit(source.R);
this.G = ImageMaths.UpscaleFrom8BitTo16Bit(source.G);
this.B = ImageMaths.UpscaleFrom8BitTo16Bit(source.B);
this.A = ImageMaths.UpscaleFrom8BitTo16Bit(source.A);
}
/// <summary>
/// Initializes a new instance of the <see cref="Rgba64"/> struct.
/// </summary>
/// <param name="source">A structure of 3 bytes in RGB byte order.</param>
[MethodImpl(InliningOptions.ShortMethod)]
public Rgba64(Rgb24 source)
{
this.R = ImageMaths.UpscaleFrom8BitTo16Bit(source.R);
this.G = ImageMaths.UpscaleFrom8BitTo16Bit(source.G);
this.B = ImageMaths.UpscaleFrom8BitTo16Bit(source.B);
this.A = ushort.MaxValue;
}
/// <summary>
/// Initializes a new instance of the <see cref="Rgba64"/> struct.
/// </summary>
/// <param name="source">A structure of 3 bytes in BGR byte order.</param>
[MethodImpl(InliningOptions.ShortMethod)]
public Rgba64(Bgr24 source)
{
this.R = ImageMaths.UpscaleFrom8BitTo16Bit(source.R);
this.G = ImageMaths.UpscaleFrom8BitTo16Bit(source.G);
this.B = ImageMaths.UpscaleFrom8BitTo16Bit(source.B);
this.A = ushort.MaxValue;
}
/// <summary>
/// Initializes a new instance of the <see cref="Rgba64"/> struct.
/// </summary>
/// <param name="vector">The <see cref="Vector4"/>.</param>
[MethodImpl(InliningOptions.ShortMethod)]
public Rgba64(Vector4 vector)
{
vector = Vector4.Clamp(vector, Vector4.Zero, Vector4.One) * Max;
this.R = (ushort)MathF.Round(vector.X);
this.G = (ushort)MathF.Round(vector.Y);
this.B = (ushort)MathF.Round(vector.Z);
this.A = (ushort)MathF.Round(vector.W);
}
/// <summary>
/// Gets or sets the RGB components of this struct as <see cref="Rgb48"/>.
/// </summary>
public Rgb48 Rgb
{
@ -76,6 +156,22 @@ namespace SixLabors.ImageSharp.PixelFormats
set => Unsafe.As<Rgba64, ulong>(ref this) = value;
}
/// <summary>
/// Converts an <see cref="Rgba64"/> to <see cref="Color"/>.
/// </summary>
/// <param name="source">The <see cref="Rgba64"/>.</param>
/// <returns>The <see cref="Color"/>.</returns>
[MethodImpl(InliningOptions.ShortMethod)]
public static implicit operator Color(Rgba64 source) => new Color(source);
/// <summary>
/// Converts a <see cref="Color"/> to <see cref="Rgba64"/>.
/// </summary>
/// <param name="color">The <see cref="Color"/>.</param>
/// <returns>The <see cref="Rgba64"/>.</returns>
[MethodImpl(InliningOptions.ShortMethod)]
public static implicit operator Rgba64(Color color) => color.ToPixel<Rgba64>();
/// <summary>
/// Compares two <see cref="Rgba64"/> objects for equality.
/// </summary>
@ -221,6 +317,74 @@ namespace SixLabors.ImageSharp.PixelFormats
[MethodImpl(InliningOptions.ShortMethod)]
public void FromRgba64(Rgba64 source) => this = source;
/// <summary>
/// Convert to <see cref="Rgba32"/>.
/// </summary>
/// <returns>The <see cref="Rgba32"/>.</returns>
[MethodImpl(InliningOptions.ShortMethod)]
public Rgba32 ToRgba32()
{
byte r = ImageMaths.DownScaleFrom16BitTo8Bit(this.R);
byte g = ImageMaths.DownScaleFrom16BitTo8Bit(this.G);
byte b = ImageMaths.DownScaleFrom16BitTo8Bit(this.B);
byte a = ImageMaths.DownScaleFrom16BitTo8Bit(this.A);
return new Rgba32(r, g, b, a);
}
/// <summary>
/// Convert to <see cref="Bgra32"/>.
/// </summary>
/// <returns>The <see cref="Bgra32"/>.</returns>
[MethodImpl(InliningOptions.ShortMethod)]
public Bgra32 ToBgra32()
{
byte r = ImageMaths.DownScaleFrom16BitTo8Bit(this.R);
byte g = ImageMaths.DownScaleFrom16BitTo8Bit(this.G);
byte b = ImageMaths.DownScaleFrom16BitTo8Bit(this.B);
byte a = ImageMaths.DownScaleFrom16BitTo8Bit(this.A);
return new Bgra32(r, g, b, a);
}
/// <summary>
/// Convert to <see cref="Argb32"/>.
/// </summary>
/// <returns>The <see cref="Argb32"/>.</returns>
[MethodImpl(InliningOptions.ShortMethod)]
public Argb32 ToArgb32()
{
byte r = ImageMaths.DownScaleFrom16BitTo8Bit(this.R);
byte g = ImageMaths.DownScaleFrom16BitTo8Bit(this.G);
byte b = ImageMaths.DownScaleFrom16BitTo8Bit(this.B);
byte a = ImageMaths.DownScaleFrom16BitTo8Bit(this.A);
return new Argb32(r, g, b, a);
}
/// <summary>
/// Convert to <see cref="Rgb24"/>.
/// </summary>
/// <returns>The <see cref="Rgb24"/>.</returns>
[MethodImpl(InliningOptions.ShortMethod)]
public Rgb24 ToRgb24()
{
byte r = ImageMaths.DownScaleFrom16BitTo8Bit(this.R);
byte g = ImageMaths.DownScaleFrom16BitTo8Bit(this.G);
byte b = ImageMaths.DownScaleFrom16BitTo8Bit(this.B);
return new Rgb24(r, g, b);
}
/// <summary>
/// Convert to <see cref="Bgr24"/>.
/// </summary>
/// <returns>The <see cref="Bgr24"/>.</returns>
[MethodImpl(InliningOptions.ShortMethod)]
public Bgr24 ToBgr24()
{
byte r = ImageMaths.DownScaleFrom16BitTo8Bit(this.R);
byte g = ImageMaths.DownScaleFrom16BitTo8Bit(this.G);
byte b = ImageMaths.DownScaleFrom16BitTo8Bit(this.B);
return new Bgr24(r, g, b);
}
/// <inheritdoc />
public override bool Equals(object obj) => obj is Rgba64 rgba64 && this.Equals(rgba64);

2
src/ImageSharp/Primitives/ValueSize.cs

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

78
src/ImageSharp/Processing/DitherExtensions.cs

@ -1,78 +0,0 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing.Processors.Dithering;
using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing
{
/// <summary>
/// Defines dithering extensions to apply on an <see cref="Image{TPixel}"/>
/// using Mutate/Clone.
/// </summary>
public static class DitherExtensions
{
/// <summary>
/// Dithers the image reducing it to a web-safe palette using Bayer4x4 ordered dithering.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <returns>The <see cref="IImageProcessingContext{TPixel}"/> to allow chaining of operations.</returns>
public static IImageProcessingContext<TPixel> Dither<TPixel>(this IImageProcessingContext<TPixel> source)
where TPixel : struct, IPixel<TPixel>
=> Dither(source, KnownDitherers.BayerDither4x4);
/// <summary>
/// Dithers the image reducing it to a web-safe palette using ordered dithering.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="dither">The ordered ditherer.</param>
/// <returns>The <see cref="IImageProcessingContext{TPixel}"/> to allow chaining of operations.</returns>
public static IImageProcessingContext<TPixel> Dither<TPixel>(this IImageProcessingContext<TPixel> source, IOrderedDither dither)
where TPixel : struct, IPixel<TPixel>
=> source.ApplyProcessor(new OrderedDitherPaletteProcessor<TPixel>(dither));
/// <summary>
/// Dithers the image reducing it to the given palette using ordered dithering.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="dither">The ordered ditherer.</param>
/// <param name="palette">The palette to select substitute colors from.</param>
/// <returns>The <see cref="IImageProcessingContext{TPixel}"/> to allow chaining of operations.</returns>
public static IImageProcessingContext<TPixel> Dither<TPixel>(this IImageProcessingContext<TPixel> source, IOrderedDither dither, TPixel[] palette)
where TPixel : struct, IPixel<TPixel>
=> source.ApplyProcessor(new OrderedDitherPaletteProcessor<TPixel>(dither, palette));
/// <summary>
/// Dithers the image reducing it to a web-safe palette using ordered dithering.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="dither">The ordered ditherer.</param>
/// <param name="rectangle">
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to alter.
/// </param>
/// <returns>The <see cref="IImageProcessingContext{TPixel}"/> to allow chaining of operations.</returns>
public static IImageProcessingContext<TPixel> Dither<TPixel>(this IImageProcessingContext<TPixel> source, IOrderedDither dither, Rectangle rectangle)
where TPixel : struct, IPixel<TPixel>
=> source.ApplyProcessor(new OrderedDitherPaletteProcessor<TPixel>(dither), rectangle);
/// <summary>
/// Dithers the image reducing it to the given palette using ordered dithering.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="dither">The ordered ditherer.</param>
/// <param name="palette">The palette to select substitute colors from.</param>
/// <param name="rectangle">
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to alter.
/// </param>
/// <returns>The <see cref="IImageProcessingContext{TPixel}"/> to allow chaining of operations.</returns>
public static IImageProcessingContext<TPixel> Dither<TPixel>(this IImageProcessingContext<TPixel> source, IOrderedDither dither, TPixel[] palette, Rectangle rectangle)
where TPixel : struct, IPixel<TPixel>
=> source.ApplyProcessor(new OrderedDitherPaletteProcessor<TPixel>(dither, palette), rectangle);
}
}

0
src/ImageSharp/Processing/AutoOrientExtensions.cs → src/ImageSharp/Processing/Extensions/AutoOrientExtensions.cs

45
src/ImageSharp/Processing/BackgroundColorExtensions.cs → src/ImageSharp/Processing/Extensions/BackgroundColorExtensions.cs

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

47
src/ImageSharp/Processing/BinaryDiffuseExtensions.cs → src/ImageSharp/Processing/Extensions/BinaryDiffuseExtensions.cs

@ -1,7 +1,6 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing.Processors.Binarization;
using SixLabors.ImageSharp.Processing.Processors.Dithering;
using SixLabors.Primitives;
@ -9,7 +8,7 @@ using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing
{
/// <summary>
/// Defines extension methods to apply binary diffusion on an <see cref="Image{TPixel}"/>
/// Defines extension methods to apply binary diffusion on an <see cref="Image"/>
/// using Mutate/Clone.
/// </summary>
public static class BinaryDiffuseExtensions
@ -17,19 +16,19 @@ namespace SixLabors.ImageSharp.Processing
/// <summary>
/// Dithers the image reducing it to two colors using error diffusion.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="diffuser">The diffusion algorithm to apply.</param>
/// <param name="threshold">The threshold to apply binarization of the image. Must be between 0 and 1.</param>
/// <returns>The <see cref="IImageProcessingContext{TPixel}"/> to allow chaining of operations.</returns>
public static IImageProcessingContext<TPixel> BinaryDiffuse<TPixel>(this IImageProcessingContext<TPixel> source, IErrorDiffuser diffuser, float threshold)
where TPixel : struct, IPixel<TPixel>
=> source.ApplyProcessor(new BinaryErrorDiffusionProcessor<TPixel>(diffuser, threshold));
public static IImageProcessingContext BinaryDiffuse(
this IImageProcessingContext source,
IErrorDiffuser diffuser,
float threshold) =>
source.ApplyProcessor(new BinaryErrorDiffusionProcessor(diffuser, threshold));
/// <summary>
/// Dithers the image reducing it to two colors using error diffusion.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="diffuser">The diffusion algorithm to apply.</param>
/// <param name="threshold">The threshold to apply binarization of the image. Must be between 0 and 1.</param>
@ -37,28 +36,33 @@ namespace SixLabors.ImageSharp.Processing
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to alter.
/// </param>
/// <returns>The <see cref="IImageProcessingContext{TPixel}"/> to allow chaining of operations.</returns>
public static IImageProcessingContext<TPixel> BinaryDiffuse<TPixel>(this IImageProcessingContext<TPixel> source, IErrorDiffuser diffuser, float threshold, Rectangle rectangle)
where TPixel : struct, IPixel<TPixel>
=> source.ApplyProcessor(new BinaryErrorDiffusionProcessor<TPixel>(diffuser, threshold), rectangle);
public static IImageProcessingContext BinaryDiffuse(
this IImageProcessingContext source,
IErrorDiffuser diffuser,
float threshold,
Rectangle rectangle) =>
source.ApplyProcessor(new BinaryErrorDiffusionProcessor(diffuser, threshold), rectangle);
/// <summary>
/// Dithers the image reducing it to two colors using error diffusion.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="diffuser">The diffusion algorithm to apply.</param>
/// <param name="threshold">The threshold to apply binarization of the image. Must be between 0 and 1.</param>
/// <param name="upperColor">The color to use for pixels that are above the threshold.</param>
/// <param name="lowerColor">The color to use for pixels that are below the threshold</param>
/// <returns>The <see cref="IImageProcessingContext{TPixel}"/> to allow chaining of operations.</returns>
public static IImageProcessingContext<TPixel> BinaryDiffuse<TPixel>(this IImageProcessingContext<TPixel> source, IErrorDiffuser diffuser, float threshold, TPixel upperColor, TPixel lowerColor)
where TPixel : struct, IPixel<TPixel>
=> source.ApplyProcessor(new BinaryErrorDiffusionProcessor<TPixel>(diffuser, threshold, upperColor, lowerColor));
public static IImageProcessingContext BinaryDiffuse(
this IImageProcessingContext source,
IErrorDiffuser diffuser,
float threshold,
Color upperColor,
Color lowerColor) =>
source.ApplyProcessor(new BinaryErrorDiffusionProcessor(diffuser, threshold, upperColor, lowerColor));
/// <summary>
/// Dithers the image reducing it to two colors using error diffusion.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="diffuser">The diffusion algorithm to apply.</param>
/// <param name="threshold">The threshold to apply binarization of the image. Must be between 0 and 1.</param>
@ -68,8 +72,15 @@ namespace SixLabors.ImageSharp.Processing
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to alter.
/// </param>
/// <returns>The <see cref="IImageProcessingContext{TPixel}"/> to allow chaining of operations.</returns>
public static IImageProcessingContext<TPixel> BinaryDiffuse<TPixel>(this IImageProcessingContext<TPixel> source, IErrorDiffuser diffuser, float threshold, TPixel upperColor, TPixel lowerColor, Rectangle rectangle)
where TPixel : struct, IPixel<TPixel>
=> source.ApplyProcessor(new BinaryErrorDiffusionProcessor<TPixel>(diffuser, threshold, upperColor, lowerColor), rectangle);
public static IImageProcessingContext BinaryDiffuse(
this IImageProcessingContext source,
IErrorDiffuser diffuser,
float threshold,
Color upperColor,
Color lowerColor,
Rectangle rectangle) =>
source.ApplyProcessor(
new BinaryErrorDiffusionProcessor(diffuser, threshold, upperColor, lowerColor),
rectangle);
}
}

40
src/ImageSharp/Processing/BinaryDitherExtensions.cs → src/ImageSharp/Processing/Extensions/BinaryDitherExtensions.cs

@ -1,7 +1,6 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing.Processors.Binarization;
using SixLabors.ImageSharp.Processing.Processors.Dithering;
using SixLabors.Primitives;
@ -9,7 +8,7 @@ using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing
{
/// <summary>
/// Defines extensions to apply binary dithering on an <see cref="Image{TPixel}"/>
/// Defines extensions to apply binary dithering on an <see cref="Image"/>
/// using Mutate/Clone.
/// </summary>
public static class BinaryDitherExtensions
@ -17,45 +16,46 @@ namespace SixLabors.ImageSharp.Processing
/// <summary>
/// Dithers the image reducing it to two colors using ordered dithering.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="dither">The ordered ditherer.</param>
/// <returns>The <see cref="IImageProcessingContext{TPixel}"/> to allow chaining of operations.</returns>
public static IImageProcessingContext<TPixel> BinaryDither<TPixel>(this IImageProcessingContext<TPixel> source, IOrderedDither dither)
where TPixel : struct, IPixel<TPixel>
=> source.ApplyProcessor(new BinaryOrderedDitherProcessor<TPixel>(dither));
public static IImageProcessingContext
BinaryDither(this IImageProcessingContext source, IOrderedDither dither) =>
source.ApplyProcessor(new BinaryOrderedDitherProcessor(dither));
/// <summary>
/// Dithers the image reducing it to two colors using ordered dithering.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="dither">The ordered ditherer.</param>
/// <param name="upperColor">The color to use for pixels that are above the threshold.</param>
/// <param name="lowerColor">The color to use for pixels that are below the threshold</param>
/// <returns>The <see cref="IImageProcessingContext{TPixel}"/> to allow chaining of operations.</returns>
public static IImageProcessingContext<TPixel> BinaryDither<TPixel>(this IImageProcessingContext<TPixel> source, IOrderedDither dither, TPixel upperColor, TPixel lowerColor)
where TPixel : struct, IPixel<TPixel>
=> source.ApplyProcessor(new BinaryOrderedDitherProcessor<TPixel>(dither, upperColor, lowerColor));
public static IImageProcessingContext BinaryDither(
this IImageProcessingContext source,
IOrderedDither dither,
Color upperColor,
Color lowerColor) =>
source.ApplyProcessor(new BinaryOrderedDitherProcessor(dither, upperColor, lowerColor));
/// <summary>
/// Dithers the image reducing it to two colors using ordered dithering.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="dither">The ordered ditherer.</param>
/// <param name="rectangle">
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to alter.
/// </param>
/// <returns>The <see cref="IImageProcessingContext{TPixel}"/> to allow chaining of operations.</returns>
public static IImageProcessingContext<TPixel> BinaryDither<TPixel>(this IImageProcessingContext<TPixel> source, IOrderedDither dither, Rectangle rectangle)
where TPixel : struct, IPixel<TPixel>
=> source.ApplyProcessor(new BinaryOrderedDitherProcessor<TPixel>(dither), rectangle);
public static IImageProcessingContext BinaryDither(
this IImageProcessingContext source,
IOrderedDither dither,
Rectangle rectangle) =>
source.ApplyProcessor(new BinaryOrderedDitherProcessor(dither), rectangle);
/// <summary>
/// Dithers the image reducing it to two colors using ordered dithering.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="dither">The ordered ditherer.</param>
/// <param name="upperColor">The color to use for pixels that are above the threshold.</param>
@ -64,8 +64,12 @@ namespace SixLabors.ImageSharp.Processing
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to alter.
/// </param>
/// <returns>The <see cref="IImageProcessingContext{TPixel}"/> to allow chaining of operations.</returns>
public static IImageProcessingContext<TPixel> BinaryDither<TPixel>(this IImageProcessingContext<TPixel> source, IOrderedDither dither, TPixel upperColor, TPixel lowerColor, Rectangle rectangle)
where TPixel : struct, IPixel<TPixel>
=> source.ApplyProcessor(new BinaryOrderedDitherProcessor<TPixel>(dither, upperColor, lowerColor), rectangle);
public static IImageProcessingContext BinaryDither(
this IImageProcessingContext source,
IOrderedDither dither,
Color upperColor,
Color lowerColor,
Rectangle rectangle) =>
source.ApplyProcessor(new BinaryOrderedDitherProcessor(dither, upperColor, lowerColor), rectangle);
}
}

49
src/ImageSharp/Processing/BinaryThresholdExtensions.cs → src/ImageSharp/Processing/Extensions/BinaryThresholdExtensions.cs

@ -1,14 +1,13 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing.Processors.Binarization;
using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing
{
/// <summary>
/// Defines extension methods to apply binary thresholding on an <see cref="Image{TPixel}"/>
/// Defines extension methods to apply binary thresholding on an <see cref="Image"/>
/// using Mutate/Clone.
/// </summary>
public static class BinaryThresholdExtensions
@ -16,45 +15,45 @@ namespace SixLabors.ImageSharp.Processing
/// <summary>
/// Applies binarization to the image splitting the pixels at the given threshold.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="threshold">The threshold to apply binarization of the image. Must be between 0 and 1.</param>
/// <returns>The <see cref="IImageProcessingContext{TPixel}"/> to allow chaining of operations.</returns>
public static IImageProcessingContext<TPixel> BinaryThreshold<TPixel>(this IImageProcessingContext<TPixel> source, float threshold)
where TPixel : struct, IPixel<TPixel>
=> source.ApplyProcessor(new BinaryThresholdProcessor<TPixel>(threshold));
/// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
public static IImageProcessingContext BinaryThreshold(this IImageProcessingContext source, float threshold) =>
source.ApplyProcessor(new BinaryThresholdProcessor(threshold));
/// <summary>
/// Applies binarization to the image splitting the pixels at the given threshold.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="threshold">The threshold to apply binarization of the image. Must be between 0 and 1.</param>
/// <param name="rectangle">
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to alter.
/// </param>
/// <returns>The <see cref="IImageProcessingContext{TPixel}"/> to allow chaining of operations.</returns>
public static IImageProcessingContext<TPixel> BinaryThreshold<TPixel>(this IImageProcessingContext<TPixel> source, float threshold, Rectangle rectangle)
where TPixel : struct, IPixel<TPixel>
=> source.ApplyProcessor(new BinaryThresholdProcessor<TPixel>(threshold), rectangle);
/// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
public static IImageProcessingContext BinaryThreshold(
this IImageProcessingContext source,
float threshold,
Rectangle rectangle) =>
source.ApplyProcessor(new BinaryThresholdProcessor(threshold), rectangle);
/// <summary>
/// Applies binarization to the image splitting the pixels at the given threshold.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="threshold">The threshold to apply binarization of the image. Must be between 0 and 1.</param>
/// <param name="upperColor">The color to use for pixels that are above the threshold.</param>
/// <param name="lowerColor">The color to use for pixels that are below the threshold</param>
/// <returns>The <see cref="IImageProcessingContext{TPixel}"/> to allow chaining of operations.</returns>
public static IImageProcessingContext<TPixel> BinaryThreshold<TPixel>(this IImageProcessingContext<TPixel> source, float threshold, TPixel upperColor, TPixel lowerColor)
where TPixel : struct, IPixel<TPixel>
=> source.ApplyProcessor(new BinaryThresholdProcessor<TPixel>(threshold, upperColor, lowerColor));
/// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
public static IImageProcessingContext BinaryThreshold(
this IImageProcessingContext source,
float threshold,
Color upperColor,
Color lowerColor) =>
source.ApplyProcessor(new BinaryThresholdProcessor(threshold, upperColor, lowerColor));
/// <summary>
/// Applies binarization to the image splitting the pixels at the given threshold.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="threshold">The threshold to apply binarization of the image. Must be between 0 and 1.</param>
/// <param name="upperColor">The color to use for pixels that are above the threshold.</param>
@ -62,9 +61,13 @@ namespace SixLabors.ImageSharp.Processing
/// <param name="rectangle">
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to alter.
/// </param>
/// <returns>The <see cref="IImageProcessingContext{TPixel}"/> to allow chaining of operations.</returns>
public static IImageProcessingContext<TPixel> BinaryThreshold<TPixel>(this IImageProcessingContext<TPixel> source, float threshold, TPixel upperColor, TPixel lowerColor, Rectangle rectangle)
where TPixel : struct, IPixel<TPixel>
=> source.ApplyProcessor(new BinaryThresholdProcessor<TPixel>(threshold, upperColor, lowerColor), rectangle);
/// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
public static IImageProcessingContext BinaryThreshold(
this IImageProcessingContext source,
float threshold,
Color upperColor,
Color lowerColor,
Rectangle rectangle) =>
source.ApplyProcessor(new BinaryThresholdProcessor(threshold, upperColor, lowerColor), rectangle);
}
}
}

0
src/ImageSharp/Processing/BlackWhiteExtensions.cs → src/ImageSharp/Processing/Extensions/BlackWhiteExtensions.cs

0
src/ImageSharp/Processing/BoxBlurExtensions.cs → src/ImageSharp/Processing/Extensions/BoxBlurExtensions.cs

0
src/ImageSharp/Processing/BrightnessExtensions.cs → src/ImageSharp/Processing/Extensions/BrightnessExtensions.cs

0
src/ImageSharp/Processing/ColorBlindnessExtensions.cs → src/ImageSharp/Processing/Extensions/ColorBlindnessExtensions.cs

0
src/ImageSharp/Processing/ContrastExtensions.cs → src/ImageSharp/Processing/Extensions/ContrastExtensions.cs

0
src/ImageSharp/Processing/CropExtensions.cs → src/ImageSharp/Processing/Extensions/CropExtensions.cs

0
src/ImageSharp/Processing/DetectEdgesExtensions.cs → src/ImageSharp/Processing/Extensions/DetectEdgesExtensions.cs

69
src/ImageSharp/Processing/DiffuseExtensions.cs → src/ImageSharp/Processing/Extensions/DiffuseExtensions.cs

@ -1,14 +1,15 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.PixelFormats;
using System;
using SixLabors.ImageSharp.Processing.Processors.Dithering;
using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing.Dithering
{
/// <summary>
/// Defines extension methods to apply diffusion to an <see cref="Image{TPixel}"/>
/// Defines extension methods to apply diffusion to an <see cref="Image"/>
/// using Mutate/Clone.
/// </summary>
public static class DiffuseExtensions
@ -16,68 +17,68 @@ namespace SixLabors.ImageSharp.Processing.Dithering
/// <summary>
/// Dithers the image reducing it to a web-safe palette using error diffusion.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <returns>The <see cref="IImageProcessingContext{TPixel}"/> to allow chaining of operations.</returns>
public static IImageProcessingContext<TPixel> Diffuse<TPixel>(this IImageProcessingContext<TPixel> source)
where TPixel : struct, IPixel<TPixel>
=> Diffuse(source, KnownDiffusers.FloydSteinberg, .5F);
/// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
public static IImageProcessingContext Diffuse(this IImageProcessingContext source) =>
Diffuse(source, KnownDiffusers.FloydSteinberg, .5F);
/// <summary>
/// Dithers the image reducing it to a web-safe palette using error diffusion.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="threshold">The threshold to apply binarization of the image. Must be between 0 and 1.</param>
/// <returns>The <see cref="IImageProcessingContext{TPixel}"/> to allow chaining of operations.</returns>
public static IImageProcessingContext<TPixel> Diffuse<TPixel>(this IImageProcessingContext<TPixel> source, float threshold)
where TPixel : struct, IPixel<TPixel>
=> Diffuse(source, KnownDiffusers.FloydSteinberg, threshold);
/// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
public static IImageProcessingContext Diffuse(this IImageProcessingContext source, float threshold) =>
Diffuse(source, KnownDiffusers.FloydSteinberg, threshold);
/// <summary>
/// Dithers the image reducing it to a web-safe palette using error diffusion.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="diffuser">The diffusion algorithm to apply.</param>
/// <param name="threshold">The threshold to apply binarization of the image. Must be between 0 and 1.</param>
/// <returns>The <see cref="IImageProcessingContext{TPixel}"/> to allow chaining of operations.</returns>
public static IImageProcessingContext<TPixel> Diffuse<TPixel>(this IImageProcessingContext<TPixel> source, IErrorDiffuser diffuser, float threshold)
where TPixel : struct, IPixel<TPixel>
=> source.ApplyProcessor(new ErrorDiffusionPaletteProcessor<TPixel>(diffuser, threshold));
/// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
public static IImageProcessingContext Diffuse(
this IImageProcessingContext source,
IErrorDiffuser diffuser,
float threshold) =>
source.ApplyProcessor(new ErrorDiffusionPaletteProcessor(diffuser, threshold));
/// <summary>
/// Dithers the image reducing it to a web-safe palette using error diffusion.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="diffuser">The diffusion algorithm to apply.</param>
/// <param name="threshold">The threshold to apply binarization of the image. Must be between 0 and 1.</param>
/// <param name="rectangle">
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to alter.
/// </param>
/// <returns>The <see cref="IImageProcessingContext{TPixel}"/> to allow chaining of operations.</returns>
public static IImageProcessingContext<TPixel> Diffuse<TPixel>(this IImageProcessingContext<TPixel> source, IErrorDiffuser diffuser, float threshold, Rectangle rectangle)
where TPixel : struct, IPixel<TPixel>
=> source.ApplyProcessor(new ErrorDiffusionPaletteProcessor<TPixel>(diffuser, threshold), rectangle);
/// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
public static IImageProcessingContext Diffuse(
this IImageProcessingContext source,
IErrorDiffuser diffuser,
float threshold,
Rectangle rectangle) =>
source.ApplyProcessor(new ErrorDiffusionPaletteProcessor(diffuser, threshold), rectangle);
/// <summary>
/// Dithers the image reducing it to the given palette using error diffusion.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="diffuser">The diffusion algorithm to apply.</param>
/// <param name="threshold">The threshold to apply binarization of the image. Must be between 0 and 1.</param>
/// <param name="palette">The palette to select substitute colors from.</param>
/// <returns>The <see cref="IImageProcessingContext{TPixel}"/> to allow chaining of operations.</returns>
public static IImageProcessingContext<TPixel> Diffuse<TPixel>(this IImageProcessingContext<TPixel> source, IErrorDiffuser diffuser, float threshold, TPixel[] palette)
where TPixel : struct, IPixel<TPixel>
=> source.ApplyProcessor(new ErrorDiffusionPaletteProcessor<TPixel>(diffuser, threshold, palette));
/// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
public static IImageProcessingContext Diffuse(
this IImageProcessingContext source,
IErrorDiffuser diffuser,
float threshold,
ReadOnlyMemory<Color> palette) =>
source.ApplyProcessor(new ErrorDiffusionPaletteProcessor(diffuser, threshold, palette));
/// <summary>
/// Dithers the image reducing it to the given palette using error diffusion.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="diffuser">The diffusion algorithm to apply.</param>
/// <param name="threshold">The threshold to apply binarization of the image. Must be between 0 and 1.</param>
@ -85,9 +86,13 @@ namespace SixLabors.ImageSharp.Processing.Dithering
/// <param name="rectangle">
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to alter.
/// </param>
/// <returns>The <see cref="IImageProcessingContext{TPixel}"/> to allow chaining of operations.</returns>
public static IImageProcessingContext<TPixel> Diffuse<TPixel>(this IImageProcessingContext<TPixel> source, IErrorDiffuser diffuser, float threshold, TPixel[] palette, Rectangle rectangle)
where TPixel : struct, IPixel<TPixel>
=> source.ApplyProcessor(new ErrorDiffusionPaletteProcessor<TPixel>(diffuser, threshold, palette), rectangle);
/// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
public static IImageProcessingContext Diffuse(
this IImageProcessingContext source,
IErrorDiffuser diffuser,
float threshold,
ReadOnlyMemory<Color> palette,
Rectangle rectangle) =>
source.ApplyProcessor(new ErrorDiffusionPaletteProcessor(diffuser, threshold, palette), rectangle);
}
}

79
src/ImageSharp/Processing/Extensions/DitherExtensions.cs

@ -0,0 +1,79 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
using SixLabors.ImageSharp.Processing.Processors.Dithering;
using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing
{
/// <summary>
/// Defines dithering extensions to apply on an <see cref="Image"/>
/// using Mutate/Clone.
/// </summary>
public static class DitherExtensions
{
/// <summary>
/// Dithers the image reducing it to a web-safe palette using Bayer4x4 ordered dithering.
/// </summary>
/// <param name="source">The image this method extends.</param>
/// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
public static IImageProcessingContext Dither(this IImageProcessingContext source) =>
Dither(source, KnownDitherers.BayerDither4x4);
/// <summary>
/// Dithers the image reducing it to a web-safe palette using ordered dithering.
/// </summary>
/// <param name="source">The image this method extends.</param>
/// <param name="dither">The ordered ditherer.</param>
/// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
public static IImageProcessingContext Dither(this IImageProcessingContext source, IOrderedDither dither) =>
source.ApplyProcessor(new OrderedDitherPaletteProcessor(dither));
/// <summary>
/// Dithers the image reducing it to the given palette using ordered dithering.
/// </summary>
/// <param name="source">The image this method extends.</param>
/// <param name="dither">The ordered ditherer.</param>
/// <param name="palette">The palette to select substitute colors from.</param>
/// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
public static IImageProcessingContext Dither(
this IImageProcessingContext source,
IOrderedDither dither,
ReadOnlyMemory<Color> palette) =>
source.ApplyProcessor(new OrderedDitherPaletteProcessor(dither, palette));
/// <summary>
/// Dithers the image reducing it to a web-safe palette using ordered dithering.
/// </summary>
/// <param name="source">The image this method extends.</param>
/// <param name="dither">The ordered ditherer.</param>
/// <param name="rectangle">
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to alter.
/// </param>
/// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
public static IImageProcessingContext Dither(
this IImageProcessingContext source,
IOrderedDither dither,
Rectangle rectangle) =>
source.ApplyProcessor(new OrderedDitherPaletteProcessor(dither), rectangle);
/// <summary>
/// Dithers the image reducing it to the given palette using ordered dithering.
/// </summary>
/// <param name="source">The image this method extends.</param>
/// <param name="dither">The ordered ditherer.</param>
/// <param name="palette">The palette to select substitute colors from.</param>
/// <param name="rectangle">
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to alter.
/// </param>
/// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
public static IImageProcessingContext Dither(
this IImageProcessingContext source,
IOrderedDither dither,
ReadOnlyMemory<Color> palette,
Rectangle rectangle) =>
source.ApplyProcessor(new OrderedDitherPaletteProcessor(dither, palette), rectangle);
}
}

0
src/ImageSharp/Processing/EntropyCropExtensions.cs → src/ImageSharp/Processing/Extensions/EntropyCropExtensions.cs

0
src/ImageSharp/Processing/FilterExtensions.cs → src/ImageSharp/Processing/Extensions/FilterExtensions.cs

0
src/ImageSharp/Processing/FlipExtensions.cs → src/ImageSharp/Processing/Extensions/FlipExtensions.cs

0
src/ImageSharp/Processing/GaussianBlurExtensions.cs → src/ImageSharp/Processing/Extensions/GaussianBlurExtensions.cs

0
src/ImageSharp/Processing/GaussianSharpenExtensions.cs → src/ImageSharp/Processing/Extensions/GaussianSharpenExtensions.cs

98
src/ImageSharp/Processing/GlowExtensions.cs → src/ImageSharp/Processing/Extensions/GlowExtensions.cs

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

0
src/ImageSharp/Processing/GrayscaleExtensions.cs → src/ImageSharp/Processing/Extensions/GrayscaleExtensions.cs

2
src/ImageSharp/Processing/HistogramEqualizationExtension.cs → src/ImageSharp/Processing/Extensions/HistogramEqualizationExtensions.cs

@ -8,7 +8,7 @@ namespace SixLabors.ImageSharp.Processing
/// <summary>
/// Defines extension that allow the adjustment of the contrast of an image via its histogram.
/// </summary>
public static class HistogramEqualizationExtension
public static class HistogramEqualizationExtensions
{
/// <summary>
/// Equalizes the histogram of an image to increases the contrast.

0
src/ImageSharp/Processing/HueExtensions.cs → src/ImageSharp/Processing/Extensions/HueExtensions.cs

0
src/ImageSharp/Processing/InvertExtensions.cs → src/ImageSharp/Processing/Extensions/InvertExtensions.cs

0
src/ImageSharp/Processing/KodachromeExtensions.cs → src/ImageSharp/Processing/Extensions/KodachromeExtensions.cs

0
src/ImageSharp/Processing/LomographExtensions.cs → src/ImageSharp/Processing/Extensions/LomographExtensions.cs

0
src/ImageSharp/Processing/OilPaintExtensions.cs → src/ImageSharp/Processing/Extensions/OilPaintExtensions.cs

0
src/ImageSharp/Processing/OpacityExtensions.cs → src/ImageSharp/Processing/Extensions/OpacityExtensions.cs

0
src/ImageSharp/Processing/PadExtensions.cs → src/ImageSharp/Processing/Extensions/PadExtensions.cs

0
src/ImageSharp/Processing/PixelateExtensions.cs → src/ImageSharp/Processing/Extensions/PixelateExtensions.cs

0
src/ImageSharp/Processing/PolaroidExtensions.cs → src/ImageSharp/Processing/Extensions/PolaroidExtensions.cs

0
src/ImageSharp/Processing/ProcessingExtensions.cs → src/ImageSharp/Processing/Extensions/ProcessingExtensions.cs

0
src/ImageSharp/Processing/QuantizeExtensions.cs → src/ImageSharp/Processing/Extensions/QuantizeExtensions.cs

0
src/ImageSharp/Processing/ResizeExtensions.cs → src/ImageSharp/Processing/Extensions/ResizeExtensions.cs

0
src/ImageSharp/Processing/RotateExtensions.cs → src/ImageSharp/Processing/Extensions/RotateExtensions.cs

0
src/ImageSharp/Processing/RotateFlipExtensions.cs → src/ImageSharp/Processing/Extensions/RotateFlipExtensions.cs

0
src/ImageSharp/Processing/SaturateExtensions.cs → src/ImageSharp/Processing/Extensions/SaturateExtensions.cs

0
src/ImageSharp/Processing/SepiaExtensions.cs → src/ImageSharp/Processing/Extensions/SepiaExtensions.cs

0
src/ImageSharp/Processing/SkewExtensions.cs → src/ImageSharp/Processing/Extensions/SkewExtensions.cs

0
src/ImageSharp/Processing/TransformExtensions.cs → src/ImageSharp/Processing/Extensions/TransformExtensions.cs

121
src/ImageSharp/Processing/VignetteExtensions.cs → src/ImageSharp/Processing/Extensions/VignetteExtensions.cs

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

68
src/ImageSharp/Processing/Processors/Binarization/BinaryErrorDiffusionProcessor.cs

@ -2,22 +2,19 @@
// Licensed under the Apache License, Version 2.0.
using System;
using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing.Processors.Dithering;
using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing.Processors.Binarization
{
/// <summary>
/// Performs binary threshold filtering against an image using error diffusion.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
internal class BinaryErrorDiffusionProcessor<TPixel> : ImageProcessor<TPixel>
where TPixel : struct, IPixel<TPixel>
public class BinaryErrorDiffusionProcessor : IImageProcessor
{
/// <summary>
/// Initializes a new instance of the <see cref="BinaryErrorDiffusionProcessor{TPixel}"/> class.
/// Initializes a new instance of the <see cref="BinaryErrorDiffusionProcessor"/> class.
/// </summary>
/// <param name="diffuser">The error diffuser</param>
public BinaryErrorDiffusionProcessor(IErrorDiffuser diffuser)
@ -26,23 +23,23 @@ namespace SixLabors.ImageSharp.Processing.Processors.Binarization
}
/// <summary>
/// Initializes a new instance of the <see cref="BinaryErrorDiffusionProcessor{TPixel}"/> class.
/// Initializes a new instance of the <see cref="BinaryErrorDiffusionProcessor"/> class.
/// </summary>
/// <param name="diffuser">The error diffuser</param>
/// <param name="threshold">The threshold to split the image. Must be between 0 and 1.</param>
public BinaryErrorDiffusionProcessor(IErrorDiffuser diffuser, float threshold)
: this(diffuser, threshold, NamedColors<TPixel>.White, NamedColors<TPixel>.Black)
: this(diffuser, threshold, Color.White, Color.Black)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="BinaryErrorDiffusionProcessor{TPixel}"/> class.
/// Initializes a new instance of the <see cref="BinaryErrorDiffusionProcessor"/> class.
/// </summary>
/// <param name="diffuser">The error diffuser</param>
/// <param name="threshold">The threshold to split the image. Must be between 0 and 1.</param>
/// <param name="upperColor">The color to use for pixels that are above the threshold.</param>
/// <param name="lowerColor">The color to use for pixels that are below the threshold.</param>
public BinaryErrorDiffusionProcessor(IErrorDiffuser diffuser, float threshold, TPixel upperColor, TPixel lowerColor)
public BinaryErrorDiffusionProcessor(IErrorDiffuser diffuser, float threshold, Color upperColor, Color lowerColor)
{
Guard.NotNull(diffuser, nameof(diffuser));
Guard.MustBeBetweenOrEqualTo(threshold, 0, 1, nameof(threshold));
@ -66,57 +63,18 @@ namespace SixLabors.ImageSharp.Processing.Processors.Binarization
/// <summary>
/// Gets the color to use for pixels that are above the threshold.
/// </summary>
public TPixel UpperColor { get; }
public Color UpperColor { get; }
/// <summary>
/// Gets the color to use for pixels that fall below the threshold.
/// </summary>
public TPixel LowerColor { get; }
public Color LowerColor { get; }
/// <inheritdoc/>
protected override void OnFrameApply(ImageFrame<TPixel> source, Rectangle sourceRectangle, Configuration configuration)
/// <inheritdoc />
public IImageProcessor<TPixel> CreatePixelSpecificProcessor<TPixel>()
where TPixel : struct, IPixel<TPixel>
{
byte threshold = (byte)MathF.Round(this.Threshold * 255F);
bool isAlphaOnly = typeof(TPixel) == typeof(Alpha8);
var interest = Rectangle.Intersect(sourceRectangle, source.Bounds());
int startY = interest.Y;
int endY = interest.Bottom;
int startX = interest.X;
int endX = interest.Right;
// Collect the values before looping so we can reduce our calculation count for identical sibling pixels
TPixel sourcePixel = source[startX, startY];
TPixel previousPixel = sourcePixel;
Rgba32 rgba = default;
sourcePixel.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);
for (int y = startY; y < endY; y++)
{
Span<TPixel> row = source.GetPixelRowSpan(y);
for (int x = startX; x < endX; x++)
{
sourcePixel = row[x];
// Check if this is the same as the last pixel. If so use that value
// rather than calculating it again. This is an inexpensive optimization.
if (!previousPixel.Equals(sourcePixel))
{
sourcePixel.ToRgba32(ref rgba);
luminance = isAlphaOnly ? rgba.A : ImageMaths.Get8BitBT709Luminance(rgba.R, rgba.G, rgba.B);
// Setup the previous pointer
previousPixel = sourcePixel;
}
TPixel transformedPixel = luminance >= threshold ? this.UpperColor : this.LowerColor;
this.Diffuser.Dither(source, sourcePixel, transformedPixel, x, y, startX, startY, endX, endY);
}
}
return new BinaryErrorDiffusionProcessor<TPixel>(this);
}
}
}

77
src/ImageSharp/Processing/Processors/Binarization/BinaryErrorDiffusionProcessor{TPixel}.cs

@ -0,0 +1,77 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing.Processors.Dithering;
using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing.Processors.Binarization
{
/// <summary>
/// Performs binary threshold filtering against an image using error diffusion.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
internal class BinaryErrorDiffusionProcessor<TPixel> : ImageProcessor<TPixel>
where TPixel : struct, IPixel<TPixel>
{
private readonly BinaryErrorDiffusionProcessor definition;
public BinaryErrorDiffusionProcessor(BinaryErrorDiffusionProcessor definition)
{
this.definition = definition;
}
/// <inheritdoc/>
protected override void OnFrameApply(ImageFrame<TPixel> source, Rectangle sourceRectangle, Configuration configuration)
{
TPixel upperColor = this.definition.UpperColor.ToPixel<TPixel>();
TPixel lowerColor = this.definition.LowerColor.ToPixel<TPixel>();
IErrorDiffuser diffuser = this.definition.Diffuser;
byte threshold = (byte)MathF.Round(this.definition.Threshold * 255F);
bool isAlphaOnly = typeof(TPixel) == typeof(Alpha8);
var interest = Rectangle.Intersect(sourceRectangle, source.Bounds());
int startY = interest.Y;
int endY = interest.Bottom;
int startX = interest.X;
int endX = interest.Right;
// Collect the values before looping so we can reduce our calculation count for identical sibling pixels
TPixel sourcePixel = source[startX, startY];
TPixel previousPixel = sourcePixel;
Rgba32 rgba = default;
sourcePixel.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);
for (int y = startY; y < endY; y++)
{
Span<TPixel> row = source.GetPixelRowSpan(y);
for (int x = startX; x < endX; x++)
{
sourcePixel = row[x];
// Check if this is the same as the last pixel. If so use that value
// rather than calculating it again. This is an inexpensive optimization.
if (!previousPixel.Equals(sourcePixel))
{
sourcePixel.ToRgba32(ref rgba);
luminance = isAlphaOnly ? rgba.A : ImageMaths.Get8BitBT709Luminance(rgba.R, rgba.G, rgba.B);
// Setup the previous pointer
previousPixel = sourcePixel;
}
TPixel transformedPixel = luminance >= threshold ? upperColor : lowerColor;
diffuser.Dither(source, sourcePixel, transformedPixel, x, y, startX, startY, endX, endY);
}
}
}
}
}

66
src/ImageSharp/Processing/Processors/Binarization/BinaryOrderedDitherProcessor.cs

@ -2,36 +2,33 @@
// Licensed under the Apache License, Version 2.0.
using System;
using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing.Processors.Dithering;
using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing.Processors.Binarization
{
/// <summary>
/// Performs binary threshold filtering against an image using ordered dithering.
/// Defines a binary threshold filtering using ordered dithering.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
internal class BinaryOrderedDitherProcessor<TPixel> : ImageProcessor<TPixel>
where TPixel : struct, IPixel<TPixel>
public class BinaryOrderedDitherProcessor : IImageProcessor
{
/// <summary>
/// Initializes a new instance of the <see cref="BinaryOrderedDitherProcessor{TPixel}"/> class.
/// Initializes a new instance of the <see cref="BinaryOrderedDitherProcessor"/> class.
/// </summary>
/// <param name="dither">The ordered ditherer.</param>
public BinaryOrderedDitherProcessor(IOrderedDither dither)
: this(dither, NamedColors<TPixel>.White, NamedColors<TPixel>.Black)
: this(dither, Color.White, Color.Black)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="BinaryOrderedDitherProcessor{TPixel}"/> class.
/// Initializes a new instance of the <see cref="BinaryOrderedDitherProcessor"/> class.
/// </summary>
/// <param name="dither">The ordered ditherer.</param>
/// <param name="upperColor">The color to use for pixels that are above the threshold.</param>
/// <param name="lowerColor">The color to use for pixels that are below the threshold.</param>
public BinaryOrderedDitherProcessor(IOrderedDither dither, TPixel upperColor, TPixel lowerColor)
public BinaryOrderedDitherProcessor(IOrderedDither dither, Color upperColor, Color lowerColor)
{
this.Dither = dither ?? throw new ArgumentNullException(nameof(dither));
this.UpperColor = upperColor;
@ -46,55 +43,18 @@ namespace SixLabors.ImageSharp.Processing.Processors.Binarization
/// <summary>
/// Gets the color to use for pixels that are above the threshold.
/// </summary>
public TPixel UpperColor { get; }
public Color UpperColor { get; }
/// <summary>
/// Gets the color to use for pixels that fall below the threshold.
/// </summary>
public TPixel LowerColor { get; }
public Color LowerColor { get; }
/// <inheritdoc/>
protected override void OnFrameApply(ImageFrame<TPixel> source, Rectangle sourceRectangle, Configuration configuration)
/// <inheritdoc />
public IImageProcessor<TPixel> CreatePixelSpecificProcessor<TPixel>()
where TPixel : struct, IPixel<TPixel>
{
bool isAlphaOnly = typeof(TPixel) == typeof(Alpha8);
var interest = Rectangle.Intersect(sourceRectangle, source.Bounds());
int startY = interest.Y;
int endY = interest.Bottom;
int startX = interest.X;
int endX = interest.Right;
// Collect the values before looping so we can reduce our calculation count for identical sibling pixels
TPixel sourcePixel = source[startX, startY];
TPixel previousPixel = sourcePixel;
Rgba32 rgba = default;
sourcePixel.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);
for (int y = startY; y < endY; y++)
{
Span<TPixel> row = source.GetPixelRowSpan(y);
for (int x = startX; x < endX; x++)
{
sourcePixel = row[x];
// Check if this is the same as the last pixel. If so use that value
// rather than calculating it again. This is an inexpensive optimization.
if (!previousPixel.Equals(sourcePixel))
{
sourcePixel.ToRgba32(ref rgba);
luminance = isAlphaOnly ? rgba.A : ImageMaths.Get8BitBT709Luminance(rgba.R, rgba.G, rgba.B);
// Setup the previous pointer
previousPixel = sourcePixel;
}
this.Dither.Dither(source, sourcePixel, this.UpperColor, this.LowerColor, luminance, x, y);
}
}
return new BinaryOrderedDitherProcessor<TPixel>(this);
}
}
}

75
src/ImageSharp/Processing/Processors/Binarization/BinaryOrderedDitherProcessor{TPixel}.cs

@ -0,0 +1,75 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing.Processors.Dithering;
using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing.Processors.Binarization
{
/// <summary>
/// Performs binary threshold filtering against an image using ordered dithering.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
internal class BinaryOrderedDitherProcessor<TPixel> : ImageProcessor<TPixel>
where TPixel : struct, IPixel<TPixel>
{
private readonly BinaryOrderedDitherProcessor definition;
public BinaryOrderedDitherProcessor(BinaryOrderedDitherProcessor definition)
{
this.definition = definition;
}
/// <inheritdoc/>
protected override void OnFrameApply(ImageFrame<TPixel> source, Rectangle sourceRectangle, Configuration configuration)
{
IOrderedDither dither = this.definition.Dither;
TPixel upperColor = this.definition.UpperColor.ToPixel<TPixel>();
TPixel lowerColor = this.definition.LowerColor.ToPixel<TPixel>();
bool isAlphaOnly = typeof(TPixel) == typeof(Alpha8);
var interest = Rectangle.Intersect(sourceRectangle, source.Bounds());
int startY = interest.Y;
int endY = interest.Bottom;
int startX = interest.X;
int endX = interest.Right;
// Collect the values before looping so we can reduce our calculation count for identical sibling pixels
TPixel sourcePixel = source[startX, startY];
TPixel previousPixel = sourcePixel;
Rgba32 rgba = default;
sourcePixel.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);
for (int y = startY; y < endY; y++)
{
Span<TPixel> row = source.GetPixelRowSpan(y);
for (int x = startX; x < endX; x++)
{
sourcePixel = row[x];
// Check if this is the same as the last pixel. If so use that value
// rather than calculating it again. This is an inexpensive optimization.
if (!previousPixel.Equals(sourcePixel))
{
sourcePixel.ToRgba32(ref rgba);
luminance = isAlphaOnly ? rgba.A : ImageMaths.Get8BitBT709Luminance(rgba.R, rgba.G, rgba.B);
// Setup the previous pointer
previousPixel = sourcePixel;
}
dither.Dither(source, sourcePixel, upperColor, lowerColor, luminance, x, y);
}
}
}
}
}

67
src/ImageSharp/Processing/Processors/Binarization/BinaryThresholdProcessor.cs

@ -3,36 +3,31 @@
using System;
using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.ParallelUtils;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing.Processors.Binarization
{
/// <summary>
/// Performs simple binary threshold filtering against an image.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
internal class BinaryThresholdProcessor<TPixel> : ImageProcessor<TPixel>
where TPixel : struct, IPixel<TPixel>
public class BinaryThresholdProcessor : IImageProcessor
{
/// <summary>
/// Initializes a new instance of the <see cref="BinaryThresholdProcessor{TPixel}"/> class.
/// Initializes a new instance of the <see cref="BinaryThresholdProcessor"/> class.
/// </summary>
/// <param name="threshold">The threshold to split the image. Must be between 0 and 1.</param>
public BinaryThresholdProcessor(float threshold)
: this(threshold, NamedColors<TPixel>.White, NamedColors<TPixel>.Black)
: this(threshold, Color.White, Color.Black)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="BinaryThresholdProcessor{TPixel}"/> class.
/// Initializes a new instance of the <see cref="BinaryThresholdProcessor"/> class.
/// </summary>
/// <param name="threshold">The threshold to split the image. Must be between 0 and 1.</param>
/// <param name="upperColor">The color to use for pixels that are above the threshold.</param>
/// <param name="lowerColor">The color to use for pixels that are below the threshold.</param>
public BinaryThresholdProcessor(float threshold, TPixel upperColor, TPixel lowerColor)
public BinaryThresholdProcessor(float threshold, Color upperColor, Color lowerColor)
{
Guard.MustBeBetweenOrEqualTo(threshold, 0, 1, nameof(threshold));
this.Threshold = threshold;
@ -46,56 +41,20 @@ namespace SixLabors.ImageSharp.Processing.Processors.Binarization
public float Threshold { get; }
/// <summary>
/// Gets or sets the color to use for pixels that are above the threshold.
/// Gets the color to use for pixels that are above the threshold.
/// </summary>
public TPixel UpperColor { get; set; }
public Color UpperColor { get; }
/// <summary>
/// Gets or sets the color to use for pixels that fall below the threshold.
/// Gets the color to use for pixels that fall below the threshold.
/// </summary>
public TPixel LowerColor { get; set; }
public Color LowerColor { get; }
/// <inheritdoc/>
protected override void OnFrameApply(
ImageFrame<TPixel> source,
Rectangle sourceRectangle,
Configuration configuration)
/// <inheritdoc />
public IImageProcessor<TPixel> CreatePixelSpecificProcessor<TPixel>()
where TPixel : struct, IPixel<TPixel>
{
byte threshold = (byte)MathF.Round(this.Threshold * 255F);
TPixel upper = this.UpperColor;
TPixel lower = this.LowerColor;
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(Alpha8);
var workingRect = Rectangle.FromLTRB(startX, startY, endX, endY);
ParallelHelper.IterateRows(
workingRect,
configuration,
rows =>
{
Rgba32 rgba = default;
for (int y = rows.Min; y < rows.Max; y++)
{
Span<TPixel> row = source.GetPixelRowSpan(y);
for (int x = startX; x < endX; 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;
}
}
});
return new BinaryThresholdProcessor<TPixel>(this);
}
}
}

70
src/ImageSharp/Processing/Processors/Binarization/BinaryThresholdProcessor{TPixel}.cs

@ -0,0 +1,70 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.ParallelUtils;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing.Processors.Binarization
{
/// <summary>
/// Performs simple binary threshold filtering against an image.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
internal class BinaryThresholdProcessor<TPixel> : ImageProcessor<TPixel>
where TPixel : struct, IPixel<TPixel>
{
private readonly BinaryThresholdProcessor definition;
public BinaryThresholdProcessor(BinaryThresholdProcessor definition)
{
this.definition = definition;
}
/// <inheritdoc/>
protected override void OnFrameApply(
ImageFrame<TPixel> source,
Rectangle sourceRectangle,
Configuration configuration)
{
byte threshold = (byte)MathF.Round(this.definition.Threshold * 255F);
TPixel upper = this.definition.UpperColor.ToPixel<TPixel>();
TPixel lower = this.definition.LowerColor.ToPixel<TPixel>();
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(Alpha8);
var workingRect = Rectangle.FromLTRB(startX, startY, endX, endY);
ParallelHelper.IterateRows(
workingRect,
configuration,
rows =>
{
Rgba32 rgba = default;
for (int y = rows.Min; y < rows.Max; y++)
{
Span<TPixel> row = source.GetPixelRowSpan(y);
for (int x = startX; x < endX; 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;
}
}
});
}
}
}

2
src/ImageSharp/Processing/Processors/Convolution/EdgeDetector2DProcessor{TPixel}.cs

@ -50,7 +50,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
{
if (this.Grayscale)
{
new GrayscaleBt709Processor(1F).ApplyToFrame(source, sourceRectangle, configuration);
new GrayscaleBt709Processor(1F).Apply(source, sourceRectangle, configuration);
}
}
}

2
src/ImageSharp/Processing/Processors/Convolution/EdgeDetectorCompassProcessor{TPixel}.cs

@ -42,7 +42,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
{
if (this.Grayscale)
{
new GrayscaleBt709Processor(1F).ApplyToFrame(source, sourceRectangle, configuration);
new GrayscaleBt709Processor(1F).Apply(source, sourceRectangle, configuration);
}
}

2
src/ImageSharp/Processing/Processors/Convolution/EdgeDetectorProcessor{TPixel}.cs

@ -38,7 +38,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
{
if (this.Grayscale)
{
new GrayscaleBt709Processor(1F).ApplyToFrame(source, sourceRectangle, configuration);
new GrayscaleBt709Processor(1F).Apply(source, sourceRectangle, configuration);
}
}

8
src/ImageSharp/Processing/Processors/Convolution/SobelProcessor.cs

@ -26,13 +26,5 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
{
return new EdgeDetector2DProcessor<TPixel>(SobelKernels.SobelX, SobelKernels.SobelY, this.Grayscale);
}
// TODO: Move this to an appropriate extension method if possible.
internal void ApplyToFrame<TPixel>(ImageFrame<TPixel> frame, Rectangle sourceRectangle, Configuration configuration)
where TPixel : struct, IPixel<TPixel>
{
var processorImpl = new EdgeDetector2DProcessor<TPixel>(SobelKernels.SobelX, SobelKernels.SobelY, this.Grayscale);
processorImpl.Apply(frame, sourceRectangle, configuration);
}
}
}

77
src/ImageSharp/Processing/Processors/Dithering/ErrorDiffusionPaletteProcessor.cs

@ -2,21 +2,19 @@
// Licensed under the Apache License, Version 2.0.
using System;
using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.Primitives;
using SixLabors.ImageSharp.Processing.Processors.Binarization;
namespace SixLabors.ImageSharp.Processing.Processors.Dithering
{
/// <summary>
/// An <see cref="IImageProcessor{TPixel}"/> that dithers an image using error diffusion.
/// Defines a dither operation using error diffusion.
/// If no palette is given this will default to the web safe colors defined in the CSS Color Module Level 4.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
internal class ErrorDiffusionPaletteProcessor<TPixel> : PaletteDitherProcessorBase<TPixel>
where TPixel : struct, IPixel<TPixel>
public sealed class ErrorDiffusionPaletteProcessor : PaletteDitherProcessor
{
/// <summary>
/// Initializes a new instance of the <see cref="ErrorDiffusionPaletteProcessor{TPixel}"/> class.
/// Initializes a new instance of the <see cref="ErrorDiffusionPaletteProcessor"/> class.
/// </summary>
/// <param name="diffuser">The error diffuser</param>
public ErrorDiffusionPaletteProcessor(IErrorDiffuser diffuser)
@ -25,22 +23,22 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering
}
/// <summary>
/// Initializes a new instance of the <see cref="ErrorDiffusionPaletteProcessor{TPixel}"/> class.
/// Initializes a new instance of the <see cref="ErrorDiffusionPaletteProcessor"/> class.
/// </summary>
/// <param name="diffuser">The error diffuser</param>
/// <param name="threshold">The threshold to split the image. Must be between 0 and 1.</param>
public ErrorDiffusionPaletteProcessor(IErrorDiffuser diffuser, float threshold)
: this(diffuser, threshold, NamedColors<TPixel>.WebSafePalette)
: this(diffuser, threshold, Color.WebSafePalette)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="ErrorDiffusionPaletteProcessor{TPixel}"/> class.
/// Initializes a new instance of the <see cref="ErrorDiffusionPaletteProcessor"/> class.
/// </summary>
/// <param name="diffuser">The error diffuser</param>
/// <param name="threshold">The threshold to split the image. Must be between 0 and 1.</param>
/// <param name="palette">The palette to select substitute colors from.</param>
public ErrorDiffusionPaletteProcessor(IErrorDiffuser diffuser, float threshold, TPixel[] palette)
public ErrorDiffusionPaletteProcessor(IErrorDiffuser diffuser, float threshold, ReadOnlyMemory<Color> palette)
: base(palette)
{
Guard.NotNull(diffuser, nameof(diffuser));
@ -60,59 +58,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering
/// </summary>
public float Threshold { get; }
/// <inheritdoc/>
protected override void OnFrameApply(ImageFrame<TPixel> source, Rectangle sourceRectangle, Configuration configuration)
/// <inheritdoc />
public override IImageProcessor<TPixel> CreatePixelSpecificProcessor<TPixel>()
{
byte threshold = (byte)MathF.Round(this.Threshold * 255F);
bool isAlphaOnly = typeof(TPixel) == typeof(Alpha8);
var interest = Rectangle.Intersect(sourceRectangle, source.Bounds());
int startY = interest.Y;
int endY = interest.Bottom;
int startX = interest.X;
int endX = interest.Right;
// Collect the values before looping so we can reduce our calculation count for identical sibling pixels
TPixel sourcePixel = source[startX, startY];
TPixel previousPixel = sourcePixel;
PixelPair<TPixel> pair = this.GetClosestPixelPair(ref sourcePixel);
Rgba32 rgba = default;
sourcePixel.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);
for (int y = startY; y < endY; y++)
{
Span<TPixel> row = source.GetPixelRowSpan(y);
for (int x = startX; x < endX; x++)
{
sourcePixel = row[x];
// Check if this is the same as the last pixel. If so use that value
// rather than calculating it again. This is an inexpensive optimization.
if (!previousPixel.Equals(sourcePixel))
{
pair = this.GetClosestPixelPair(ref sourcePixel);
// No error to spread, exact match.
if (sourcePixel.Equals(pair.First))
{
continue;
}
sourcePixel.ToRgba32(ref rgba);
luminance = isAlphaOnly ? rgba.A : ImageMaths.Get8BitBT709Luminance(rgba.R, rgba.G, rgba.B);
// Setup the previous pointer
previousPixel = sourcePixel;
}
TPixel transformedPixel = luminance >= threshold ? pair.Second : pair.First;
this.Diffuser.Dither(source, sourcePixel, transformedPixel, x, y, startX, startY, endX, endY);
}
}
return new ErrorDiffusionPaletteProcessor<TPixel>(this);
}
}
}

81
src/ImageSharp/Processing/Processors/Dithering/ErrorDiffusionPaletteProcessor{TPixel}.cs

@ -0,0 +1,81 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing.Processors.Dithering
{
/// <summary>
/// An <see cref="IImageProcessor{TPixel}"/> that dithers an image using error diffusion.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
internal class ErrorDiffusionPaletteProcessor<TPixel> : PaletteDitherProcessor<TPixel>
where TPixel : struct, IPixel<TPixel>
{
public ErrorDiffusionPaletteProcessor(ErrorDiffusionPaletteProcessor definition)
: base(definition)
{
}
private new ErrorDiffusionPaletteProcessor Definition => (ErrorDiffusionPaletteProcessor)base.Definition;
/// <inheritdoc/>
protected override void OnFrameApply(ImageFrame<TPixel> source, Rectangle sourceRectangle, Configuration configuration)
{
byte threshold = (byte)MathF.Round(this.Definition.Threshold * 255F);
bool isAlphaOnly = typeof(TPixel) == typeof(Alpha8);
var interest = Rectangle.Intersect(sourceRectangle, source.Bounds());
int startY = interest.Y;
int endY = interest.Bottom;
int startX = interest.X;
int endX = interest.Right;
// Collect the values before looping so we can reduce our calculation count for identical sibling pixels
TPixel sourcePixel = source[startX, startY];
TPixel previousPixel = sourcePixel;
PixelPair<TPixel> pair = this.GetClosestPixelPair(ref sourcePixel);
Rgba32 rgba = default;
sourcePixel.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);
for (int y = startY; y < endY; y++)
{
Span<TPixel> row = source.GetPixelRowSpan(y);
for (int x = startX; x < endX; x++)
{
sourcePixel = row[x];
// Check if this is the same as the last pixel. If so use that value
// rather than calculating it again. This is an inexpensive optimization.
if (!previousPixel.Equals(sourcePixel))
{
pair = this.GetClosestPixelPair(ref sourcePixel);
// No error to spread, exact match.
if (sourcePixel.Equals(pair.First))
{
continue;
}
sourcePixel.ToRgba32(ref rgba);
luminance = isAlphaOnly ? rgba.A : ImageMaths.Get8BitBT709Luminance(rgba.R, rgba.G, rgba.B);
// Setup the previous pointer
previousPixel = sourcePixel;
}
TPixel transformedPixel = luminance >= threshold ? pair.Second : pair.First;
this.Definition.Diffuser.Dither(source, sourcePixel, transformedPixel, x, y, startX, startY, endX, endY);
}
}
}
}
}

70
src/ImageSharp/Processing/Processors/Dithering/OrderedDitherPaletteProcessor.cs

@ -2,35 +2,30 @@
// Licensed under the Apache License, Version 2.0.
using System;
using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing.Processors.Dithering
{
/// <summary>
/// An <see cref="IImageProcessor{TPixel}"/> that dithers an image using error diffusion.
/// Defines a dithering operation that dithers an image using error diffusion.
/// If no palette is given this will default to the web safe colors defined in the CSS Color Module Level 4.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
internal class OrderedDitherPaletteProcessor<TPixel> : PaletteDitherProcessorBase<TPixel>
where TPixel : struct, IPixel<TPixel>
public sealed class OrderedDitherPaletteProcessor : PaletteDitherProcessor
{
/// <summary>
/// Initializes a new instance of the <see cref="OrderedDitherPaletteProcessor{TPixel}"/> class.
/// Initializes a new instance of the <see cref="OrderedDitherPaletteProcessor"/> class.
/// </summary>
/// <param name="dither">The ordered ditherer.</param>
public OrderedDitherPaletteProcessor(IOrderedDither dither)
: this(dither, NamedColors<TPixel>.WebSafePalette)
: this(dither, Color.WebSafePalette)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="OrderedDitherPaletteProcessor{TPixel}"/> class.
/// Initializes a new instance of the <see cref="OrderedDitherPaletteProcessor"/> class.
/// </summary>
/// <param name="dither">The ordered ditherer.</param>
/// <param name="palette">The palette to select substitute colors from.</param>
public OrderedDitherPaletteProcessor(IOrderedDither dither, TPixel[] palette)
public OrderedDitherPaletteProcessor(IOrderedDither dither, ReadOnlyMemory<Color> palette)
: base(palette) => this.Dither = dither ?? throw new ArgumentNullException(nameof(dither));
/// <summary>
@ -38,57 +33,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering
/// </summary>
public IOrderedDither Dither { get; }
/// <inheritdoc/>
protected override void OnFrameApply(ImageFrame<TPixel> source, Rectangle sourceRectangle, Configuration configuration)
/// <inheritdoc />
public override IImageProcessor<TPixel> CreatePixelSpecificProcessor<TPixel>()
{
bool isAlphaOnly = typeof(TPixel) == typeof(Alpha8);
var interest = Rectangle.Intersect(sourceRectangle, source.Bounds());
int startY = interest.Y;
int endY = interest.Bottom;
int startX = interest.X;
int endX = interest.Right;
// Collect the values before looping so we can reduce our calculation count for identical sibling pixels
TPixel sourcePixel = source[startX, startY];
TPixel previousPixel = sourcePixel;
PixelPair<TPixel> pair = this.GetClosestPixelPair(ref sourcePixel);
Rgba32 rgba = default;
sourcePixel.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);
for (int y = startY; y < endY; y++)
{
Span<TPixel> row = source.GetPixelRowSpan(y);
for (int x = startX; x < endX; x++)
{
sourcePixel = row[x];
// Check if this is the same as the last pixel. If so use that value
// rather than calculating it again. This is an inexpensive optimization.
if (!previousPixel.Equals(sourcePixel))
{
pair = this.GetClosestPixelPair(ref sourcePixel);
// No error to spread, exact match.
if (sourcePixel.Equals(pair.First))
{
continue;
}
sourcePixel.ToRgba32(ref rgba);
luminance = isAlphaOnly ? rgba.A : ImageMaths.Get8BitBT709Luminance(rgba.R, rgba.G, rgba.B);
// Setup the previous pointer
previousPixel = sourcePixel;
}
this.Dither.Dither(source, sourcePixel, pair.Second, pair.First, luminance, x, y);
}
}
return new OrderedDitherPaletteProcessor<TPixel>(this);
}
}
}

79
src/ImageSharp/Processing/Processors/Dithering/OrderedDitherPaletteProcessor{TPixel}.cs

@ -0,0 +1,79 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing.Processors.Dithering
{
/// <summary>
/// An <see cref="IImageProcessor{TPixel}"/> that dithers an image using error diffusion.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
internal class OrderedDitherPaletteProcessor<TPixel> : PaletteDitherProcessor<TPixel>
where TPixel : struct, IPixel<TPixel>
{
public OrderedDitherPaletteProcessor(OrderedDitherPaletteProcessor definition)
: base(definition)
{
}
private new OrderedDitherPaletteProcessor Definition => (OrderedDitherPaletteProcessor)base.Definition;
/// <inheritdoc/>
protected override void OnFrameApply(ImageFrame<TPixel> source, Rectangle sourceRectangle, Configuration configuration)
{
bool isAlphaOnly = typeof(TPixel) == typeof(Alpha8);
var interest = Rectangle.Intersect(sourceRectangle, source.Bounds());
int startY = interest.Y;
int endY = interest.Bottom;
int startX = interest.X;
int endX = interest.Right;
// Collect the values before looping so we can reduce our calculation count for identical sibling pixels
TPixel sourcePixel = source[startX, startY];
TPixel previousPixel = sourcePixel;
PixelPair<TPixel> pair = this.GetClosestPixelPair(ref sourcePixel);
Rgba32 rgba = default;
sourcePixel.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);
for (int y = startY; y < endY; y++)
{
Span<TPixel> row = source.GetPixelRowSpan(y);
for (int x = startX; x < endX; x++)
{
sourcePixel = row[x];
// Check if this is the same as the last pixel. If so use that value
// rather than calculating it again. This is an inexpensive optimization.
if (!previousPixel.Equals(sourcePixel))
{
pair = this.GetClosestPixelPair(ref sourcePixel);
// No error to spread, exact match.
if (sourcePixel.Equals(pair.First))
{
continue;
}
sourcePixel.ToRgba32(ref rgba);
luminance = isAlphaOnly ? rgba.A : ImageMaths.Get8BitBT709Luminance(rgba.R, rgba.G, rgba.B);
// Setup the previous pointer
previousPixel = sourcePixel;
}
this.Definition.Dither.Dither(source, sourcePixel, pair.Second, pair.First, luminance, x, y);
}
}
}
}
}

33
src/ImageSharp/Processing/Processors/Dithering/PaletteDitherProcessor.cs

@ -0,0 +1,33 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Processing.Processors.Dithering
{
/// <summary>
/// The base class for dither and diffusion processors that consume a palette.
/// </summary>
public abstract class PaletteDitherProcessor : IImageProcessor
{
/// <summary>
/// Initializes a new instance of the <see cref="PaletteDitherProcessor"/> class.
/// </summary>
/// <param name="palette">The palette to select substitute colors from.</param>
protected PaletteDitherProcessor(ReadOnlyMemory<Color> palette)
{
this.Palette = palette;
}
/// <summary>
/// Gets the palette to select substitute colors from.
/// </summary>
public ReadOnlyMemory<Color> Palette { get; }
/// <inheritdoc />
public abstract IImageProcessor<TPixel> CreatePixelSpecificProcessor<TPixel>()
where TPixel : struct, IPixel<TPixel>;
}
}

62
src/ImageSharp/Processing/Processors/Dithering/PaletteDitherProcessorBase.cs → src/ImageSharp/Processing/Processors/Dithering/PaletteDitherProcessor{TPixel}.cs

@ -1,10 +1,11 @@
// Copyright (c) Six Labors and contributors.
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
using System.Collections.Generic;
using System.Numerics;
using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.Primitives;
@ -14,29 +15,54 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering
/// The base class for dither and diffusion processors that consume a palette.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
internal abstract class PaletteDitherProcessorBase<TPixel> : ImageProcessor<TPixel>
internal abstract class PaletteDitherProcessor<TPixel> : ImageProcessor<TPixel>
where TPixel : struct, IPixel<TPixel>
{
private readonly Dictionary<TPixel, PixelPair<TPixel>> cache = new Dictionary<TPixel, PixelPair<TPixel>>();
private TPixel[] palette;
/// <summary>
/// The vector representation of the image palette.
/// </summary>
private Vector4[] paletteVector;
/// <summary>
/// Initializes a new instance of the <see cref="PaletteDitherProcessorBase{TPixel}"/> class.
/// Initializes a new instance of the <see cref="PaletteDitherProcessor{TPixel}"/> class.
/// </summary>
/// <param name="palette">The palette to select substitute colors from.</param>
protected PaletteDitherProcessorBase(TPixel[] palette)
protected PaletteDitherProcessor(PaletteDitherProcessor definition)
{
this.Palette = palette ?? throw new ArgumentNullException(nameof(palette));
this.Definition = definition;
}
/// <summary>
/// Gets the palette to select substitute colors from.
/// </summary>
public TPixel[] Palette { get; }
protected PaletteDitherProcessor Definition { get; }
protected override void BeforeFrameApply(
ImageFrame<TPixel> source,
Rectangle sourceRectangle,
Configuration configuration)
{
base.BeforeFrameApply(source, sourceRectangle, configuration);
// Lazy init palette:
if (this.palette is null)
{
ReadOnlySpan<Color> sourcePalette = this.Definition.Palette.Span;
this.palette = new TPixel[sourcePalette.Length];
Color.ToPixel<TPixel>(configuration, sourcePalette, this.palette);
}
// Lazy init paletteVector:
if (this.paletteVector is null)
{
this.paletteVector = new Vector4[this.palette.Length];
PixelOperations<TPixel>.Instance.ToVector4(
configuration,
(ReadOnlySpan<TPixel>)this.palette,
(Span<Vector4>)this.paletteVector,
PixelConversionModifiers.Scale);
}
}
/// <summary>
/// Returns the two closest colors from the palette calculated via Euclidean distance in the Rgba space.
@ -74,12 +100,12 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering
{
leastDistance = distance;
secondClosest = closest;
closest = this.Palette[index];
closest = this.palette[index];
}
else if (distance < secondLeastDistance)
{
secondLeastDistance = distance;
secondClosest = this.Palette[index];
secondClosest = this.palette[index];
}
}
@ -89,17 +115,5 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering
return pair;
}
protected override void BeforeFrameApply(ImageFrame<TPixel> source, Rectangle sourceRectangle, Configuration configuration)
{
base.BeforeFrameApply(source, sourceRectangle, configuration);
// Lazy init paletteVector:
if (this.paletteVector is null)
{
this.paletteVector = new Vector4[this.Palette.Length];
PixelOperations<TPixel>.Instance.ToVector4(configuration, (ReadOnlySpan<TPixel>)this.Palette, (Span<Vector4>)this.paletteVector, PixelConversionModifiers.Scale);
}
}
}
}

8
src/ImageSharp/Processing/Processors/Filters/GrayscaleBt709Processor.cs

@ -25,13 +25,5 @@ namespace SixLabors.ImageSharp.Processing.Processors.Filters
/// Gets the proportion of the conversion.
/// </summary>
public float Amount { get; }
// TODO: Move this to an appropriate extension method if possible.
internal void ApplyToFrame<TPixel>(ImageFrame<TPixel> frame, Rectangle sourceRectangle, Configuration configuration)
where TPixel : struct, IPixel<TPixel>
{
var processorImpl = new FilterProcessor<TPixel>(new GrayscaleBt709Processor(1F));
processorImpl.Apply(frame, sourceRectangle, configuration);
}
}
}

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

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

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

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

15
src/ImageSharp/Processing/Processors/ImageProcessorExtensions.cs

@ -14,6 +14,21 @@ namespace SixLabors.ImageSharp.Processing.Processors
source.AcceptVisitor(visitor);
}
/// <summary>
/// Apply an <see cref="IImageProcessor"/> to a frame.
/// Only works from processors implemented by an <see cref="ImageProcessor{TPixel}"/> subclass.
/// </summary>
internal static void Apply<TPixel>(
this IImageProcessor processor,
ImageFrame<TPixel> frame,
Rectangle sourceRectangle,
Configuration configuration)
where TPixel : struct, IPixel<TPixel>
{
var processorImpl = (ImageProcessor<TPixel>)processor.CreatePixelSpecificProcessor<TPixel>();
processorImpl.Apply(frame, sourceRectangle, configuration);
}
private class ApplyVisitor : IImageVisitor
{
private readonly IImageProcessor processor;

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

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

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

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

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

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

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

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

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

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

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

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

112
src/ImageSharp/Processing/Processors/Quantization/FrameQuantizerBase{TPixel}.cs → src/ImageSharp/Processing/Processors/Quantization/FrameQuantizer{TPixel}.cs

@ -5,6 +5,7 @@ using System;
using System.Collections.Generic;
using System.Numerics;
using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing.Processors.Dithering;
@ -14,7 +15,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization
/// The base class for all <see cref="IFrameQuantizer{TPixel}"/> implementations
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
public abstract class FrameQuantizerBase<TPixel> : IFrameQuantizer<TPixel>
public abstract class FrameQuantizer<TPixel> : IFrameQuantizer<TPixel>
where TPixel : struct, IPixel<TPixel>
{
/// <summary>
@ -33,7 +34,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization
private Vector4[] paletteVector;
/// <summary>
/// Initializes a new instance of the <see cref="FrameQuantizerBase{TPixel}"/> class.
/// Initializes a new instance of the <see cref="FrameQuantizer{TPixel}"/> class.
/// </summary>
/// <param name="quantizer">The quantizer</param>
/// <param name="singlePass">
@ -44,7 +45,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization
/// only call the <see cref="SecondPass(ImageFrame{TPixel}, Span{byte}, ReadOnlySpan{TPixel}, int, int)"/> method.
/// If two passes are required, the code will also call <see cref="FirstPass(ImageFrame{TPixel}, int, int)"/>.
/// </remarks>
protected FrameQuantizerBase(IQuantizer quantizer, bool singlePass)
protected FrameQuantizer(IQuantizer quantizer, bool singlePass)
{
Guard.NotNull(quantizer, nameof(quantizer));
@ -53,14 +54,38 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization
this.singlePass = singlePass;
}
/// <inheritdoc />
public bool Dither { get; }
/// <summary>
/// Initializes a new instance of the <see cref="FrameQuantizer{TPixel}"/> class.
/// </summary>
/// <param name="diffuser">The diffuser</param>
/// <param name="singlePass">
/// If true, the quantization process only needs to loop through the source pixels once
/// </param>
/// <remarks>
/// If you construct this class with a <value>true</value> for <paramref name="singlePass"/>, then the code will
/// only call the <see cref="SecondPass(ImageFrame{TPixel}, Span{byte}, ReadOnlySpan{TPixel}, int, int)"/> method.
/// If two passes are required, the code will also call <see cref="FirstPass(ImageFrame{TPixel}, int, int)"/>.
/// </remarks>
protected FrameQuantizer(IErrorDiffuser diffuser, bool singlePass)
{
this.Diffuser = diffuser;
this.Dither = this.Diffuser != null;
this.singlePass = singlePass;
}
/// <inheritdoc />
public IErrorDiffuser Diffuser { get; }
/// <inheritdoc />
public bool Dither { get; }
/// <inheritdoc/>
public virtual QuantizedFrame<TPixel> QuantizeFrame(ImageFrame<TPixel> image)
public virtual void Dispose()
{
}
/// <inheritdoc/>
public IQuantizedFrame<TPixel> QuantizeFrame(ImageFrame<TPixel> image)
{
Guard.NotNull(image, nameof(image));
@ -77,32 +102,33 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization
}
// Collect the palette. Required before the second pass runs.
TPixel[] palette = this.GetPalette();
ReadOnlyMemory<TPixel> palette = this.GetPalette();
this.paletteVector = new Vector4[palette.Length];
PixelOperations<TPixel>.Instance.ToVector4(image.Configuration, (ReadOnlySpan<TPixel>)palette, (Span<Vector4>)this.paletteVector, PixelConversionModifiers.Scale);
PixelOperations<TPixel>.Instance.ToVector4(
image.Configuration,
palette.Span,
(Span<Vector4>)this.paletteVector,
PixelConversionModifiers.Scale);
var quantizedFrame = new QuantizedFrame<TPixel>(image.MemoryAllocator, width, height, palette);
Span<byte> pixelSpan = quantizedFrame.GetWritablePixelSpan();
if (this.Dither)
{
// We clone the image as we don't want to alter the original via dithering.
using (ImageFrame<TPixel> clone = image.Clone())
{
this.SecondPass(clone, quantizedFrame.GetPixelSpan(), palette, width, height);
this.SecondPass(clone, pixelSpan, palette.Span, width, height);
}
}
else
{
this.SecondPass(image, quantizedFrame.GetPixelSpan(), palette, width, height);
this.SecondPass(image, pixelSpan, palette.Span, width, height);
}
return quantizedFrame;
}
/// <inheritdoc/>
public virtual void Dispose()
{
}
/// <summary>
/// Execute the first pass through the pixels in the image to create the palette.
/// </summary>
@ -114,19 +140,22 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization
}
/// <summary>
/// Execute a second pass through the image to assign the pixels to a palette entry.
/// Returns the closest color from the palette to the given color by calculating the
/// Euclidean distance in the Rgba colorspace.
/// </summary>
/// <param name="source">The source image.</param>
/// <param name="output">The output pixel array.</param>
/// <param name="palette">The output color palette.</param>
/// <param name="width">The width in pixels of the image.</param>
/// <param name="height">The height in pixels of the image.</param>
protected abstract void SecondPass(
ImageFrame<TPixel> source,
Span<byte> output,
ReadOnlySpan<TPixel> palette,
int width,
int height);
/// <param name="pixel">The color.</param>
/// <returns>The <see cref="int"/></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
protected byte GetClosestPixel(ref TPixel pixel)
{
// Check if the color is in the lookup table
if (this.distanceCache.TryGetValue(pixel, out byte value))
{
return value;
}
return this.GetClosestPixelSlow(ref pixel);
}
/// <summary>
/// Retrieve the palette for the quantized image.
@ -134,7 +163,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization
/// <returns>
/// <see cref="T:TPixel[]"/>
/// </returns>
protected abstract TPixel[] GetPalette();
protected abstract ReadOnlyMemory<TPixel> GetPalette();
/// <summary>
/// Returns the index of the first instance of the transparent color in the palette.
@ -160,22 +189,19 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization
}
/// <summary>
/// Returns the closest color from the palette to the given color by calculating the
/// Euclidean distance in the Rgba colorspace.
/// Execute a second pass through the image to assign the pixels to a palette entry.
/// </summary>
/// <param name="pixel">The color.</param>
/// <returns>The <see cref="int"/></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
protected byte GetClosestPixel(ref TPixel pixel)
{
// Check if the color is in the lookup table
if (this.distanceCache.TryGetValue(pixel, out byte value))
{
return value;
}
return this.GetClosestPixelSlow(ref pixel);
}
/// <param name="source">The source image.</param>
/// <param name="output">The output pixel array.</param>
/// <param name="palette">The output color palette.</param>
/// <param name="width">The width in pixels of the image.</param>
/// <param name="height">The height in pixels of the image.</param>
protected abstract void SecondPass(
ImageFrame<TPixel> source,
Span<byte> output,
ReadOnlySpan<TPixel> palette,
int width,
int height);
[MethodImpl(MethodImplOptions.NoInlining)]
private byte GetClosestPixelSlow(ref TPixel pixel)

2
src/ImageSharp/Processing/Processors/Quantization/IFrameQuantizer{TPixel}.cs

@ -31,6 +31,6 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization
/// <returns>
/// A <see cref="QuantizedFrame{TPixel}"/> representing a quantized version of the image pixels.
/// </returns>
QuantizedFrame<TPixel> QuantizeFrame(ImageFrame<TPixel> image);
IQuantizedFrame<TPixel> QuantizeFrame(ImageFrame<TPixel> image);
}
}

38
src/ImageSharp/Processing/Processors/Quantization/IQuantizedFrame{TPixel}.cs

@ -0,0 +1,38 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Processing.Processors.Quantization
{
/// <summary>
/// Defines an abstraction to represent a quantized image frame where the pixels indexed by a color palette.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
public interface IQuantizedFrame<TPixel> : IDisposable
where TPixel : struct, IPixel<TPixel>
{
/// <summary>
/// Gets the width of this <see cref="QuantizedFrame{TPixel}"/>.
/// </summary>
int Width { get; }
/// <summary>
/// Gets the height of this <see cref="QuantizedFrame{TPixel}"/>.
/// </summary>
int Height { get; }
/// <summary>
/// Gets the color palette of this <see cref="QuantizedFrame{TPixel}"/>.
/// </summary>
ReadOnlyMemory<TPixel> Palette { get; }
/// <summary>
/// Gets the pixels of this <see cref="QuantizedFrame{TPixel}"/>.
/// </summary>
/// <returns>The <see cref="Span{T}"/>The pixel span.</returns>
ReadOnlySpan<byte> GetPixelSpan();
}
}

6
src/ImageSharp/Processing/Processors/Quantization/OctreeFrameQuantizer{TPixel}.cs

@ -16,7 +16,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization
/// <see href="http://msdn.microsoft.com/en-us/library/aa479306.aspx"/>
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
internal sealed class OctreeFrameQuantizer<TPixel> : FrameQuantizerBase<TPixel>
internal sealed class OctreeFrameQuantizer<TPixel> : FrameQuantizer<TPixel>
where TPixel : struct, IPixel<TPixel>
{
/// <summary>
@ -136,10 +136,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization
}
}
internal TPixel[] AotGetPalette() => this.GetPalette();
internal ReadOnlyMemory<TPixel> AotGetPalette() => this.GetPalette();
/// <inheritdoc/>
protected override TPixel[] GetPalette() => this.octree.Palletize(this.colors);
protected override ReadOnlyMemory<TPixel> GetPalette() => this.octree.Palletize(this.colors);
/// <summary>
/// Process the pixel in the second pass of the algorithm.

13
src/ImageSharp/Processing/Processors/Quantization/PaletteFrameQuantizer{TPixel}.cs

@ -6,6 +6,7 @@ using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing.Processors.Dithering;
namespace SixLabors.ImageSharp.Processing.Processors.Quantization
{
@ -14,21 +15,21 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization
/// <see href="http://msdn.microsoft.com/en-us/library/aa479306.aspx"/>
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
internal sealed class PaletteFrameQuantizer<TPixel> : FrameQuantizerBase<TPixel>
internal sealed class PaletteFrameQuantizer<TPixel> : FrameQuantizer<TPixel>
where TPixel : struct, IPixel<TPixel>
{
/// <summary>
/// The reduced image palette.
/// </summary>
private readonly TPixel[] palette;
private readonly ReadOnlyMemory<TPixel> palette;
/// <summary>
/// Initializes a new instance of the <see cref="PaletteFrameQuantizer{TPixel}"/> class.
/// </summary>
/// <param name="quantizer">The palette quantizer.</param>
/// <param name="diffuser">The palette quantizer.</param>
/// <param name="colors">An array of all colors in the palette.</param>
public PaletteFrameQuantizer(IQuantizer quantizer, TPixel[] colors)
: base(quantizer, true) => this.palette = colors;
public PaletteFrameQuantizer(IErrorDiffuser diffuser, ReadOnlyMemory<TPixel> colors)
: base(diffuser, true) => this.palette = colors;
/// <inheritdoc/>
protected override void SecondPass(
@ -85,7 +86,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
protected override TPixel[] GetPalette() => this.palette;
protected override ReadOnlyMemory<TPixel> GetPalette() => this.palette;
/// <summary>
/// Process the pixel in the second pass of the algorithm

59
src/ImageSharp/Processing/Processors/Quantization/PaletteQuantizer.cs

@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0.
using System;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing.Processors.Dithering;
@ -14,61 +15,65 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization
/// By default the quantizer uses <see cref="KnownDiffusers.FloydSteinberg"/> dithering.
/// </para>
/// </summary>
public abstract class PaletteQuantizer : IQuantizer
public class PaletteQuantizer : IQuantizer
{
/// <summary>
/// Initializes a new instance of the <see cref="PaletteQuantizer"/> class.
/// </summary>
protected PaletteQuantizer()
: this(true)
/// <param name="palette">The palette.</param>
public PaletteQuantizer(ReadOnlyMemory<Color> palette)
: this(palette, true)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="PaletteQuantizer"/> class.
/// </summary>
/// <param name="palette">The palette.</param>
/// <param name="dither">Whether to apply dithering to the output image</param>
protected PaletteQuantizer(bool dither)
: this(GetDiffuser(dither))
public PaletteQuantizer(ReadOnlyMemory<Color> palette, bool dither)
: this(palette, GetDiffuser(dither))
{
}
/// <summary>
/// Initializes a new instance of the <see cref="PaletteQuantizer"/> class.
/// </summary>
/// <param name="palette">The palette.</param>
/// <param name="diffuser">The error diffusion algorithm, if any, to apply to the output image</param>
protected PaletteQuantizer(IErrorDiffuser diffuser) => this.Diffuser = diffuser;
public PaletteQuantizer(ReadOnlyMemory<Color> palette, IErrorDiffuser diffuser)
{
this.Palette = palette;
this.Diffuser = diffuser;
}
/// <inheritdoc />
public IErrorDiffuser Diffuser { get; }
/// <inheritdoc />
public abstract IFrameQuantizer<TPixel> CreateFrameQuantizer<TPixel>(Configuration configuration)
where TPixel : struct, IPixel<TPixel>;
/// <inheritdoc/>
public abstract IFrameQuantizer<TPixel> CreateFrameQuantizer<TPixel>(Configuration configuration, int maxColors)
where TPixel : struct, IPixel<TPixel>;
/// <summary>
/// Creates the generic frame quantizer.
/// Gets the palette.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="configuration">The <see cref="Configuration"/> to configure internal operations.</param>
/// <param name="palette">The color palette.</param>
/// <param name="maxColors">The maximum number of colors to hold in the color palette.</param>
/// <returns>The <see cref="IFrameQuantizer{TPixel}"/></returns>
protected IFrameQuantizer<TPixel> CreateFrameQuantizer<TPixel>(Configuration configuration, TPixel[] palette, int maxColors)
public ReadOnlyMemory<Color> Palette { get; }
/// <inheritdoc />
public IFrameQuantizer<TPixel> CreateFrameQuantizer<TPixel>(Configuration configuration)
where TPixel : struct, IPixel<TPixel>
{
int max = Math.Min(QuantizerConstants.MaxColors, Math.Min(maxColors, palette.Length));
TPixel[] palette = new TPixel[this.Palette.Length];
Color.ToPixel(configuration, this.Palette.Span, palette.AsSpan());
return new PaletteFrameQuantizer<TPixel>(this.Diffuser, palette);
}
if (max != palette.Length)
{
return new PaletteFrameQuantizer<TPixel>(this, palette.AsSpan(0, max).ToArray());
}
/// <inheritdoc/>
public IFrameQuantizer<TPixel> CreateFrameQuantizer<TPixel>(Configuration configuration, int maxColors)
where TPixel : struct, IPixel<TPixel>
{
maxColors = maxColors.Clamp(QuantizerConstants.MinColors, QuantizerConstants.MaxColors);
int max = Math.Min(maxColors, this.Palette.Length);
return new PaletteFrameQuantizer<TPixel>(this, palette);
TPixel[] palette = new TPixel[max];
Color.ToPixel(configuration, this.Palette.Span.Slice(0, max), palette.AsSpan());
return new PaletteFrameQuantizer<TPixel>(this.Diffuser, palette);
}
private static IErrorDiffuser GetDiffuser(bool dither) => dither ? KnownDiffusers.FloydSteinberg : null;

110
src/ImageSharp/Processing/Processors/Quantization/PaletteQuantizer{TPixel}.cs

@ -1,110 +0,0 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing.Processors.Dithering;
namespace SixLabors.ImageSharp.Processing.Processors.Quantization
{
/// <summary>
/// A generic palette quantizer.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
public class PaletteQuantizer<TPixel> : IQuantizer
where TPixel : struct, IPixel<TPixel>
{
/// <summary>
/// Initializes a new instance of the <see cref="PaletteQuantizer{TPixel}"/> class.
/// </summary>
/// <param name="palette">The color palette to use.</param>
public PaletteQuantizer(TPixel[] palette)
: this(palette, true)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="PaletteQuantizer{TPixel}"/> class.
/// </summary>
/// <param name="palette">The color palette to use.</param>
/// <param name="dither">Whether to apply dithering to the output image</param>
public PaletteQuantizer(TPixel[] palette, bool dither)
: this(palette, GetDiffuser(dither))
{
}
/// <summary>
/// Initializes a new instance of the <see cref="PaletteQuantizer{TPixel}"/> class.
/// </summary>
/// <param name="palette">The color palette to use.</param>
/// <param name="diffuser">The error diffusion algorithm, if any, to apply to the output image</param>
public PaletteQuantizer(TPixel[] palette, IErrorDiffuser diffuser)
{
Guard.MustBeBetweenOrEqualTo(palette.Length, QuantizerConstants.MinColors, QuantizerConstants.MaxColors, nameof(palette));
this.Palette = palette;
this.Diffuser = diffuser;
}
/// <inheritdoc/>
public IErrorDiffuser Diffuser { get; }
/// <summary>
/// Gets the palette.
/// </summary>
public TPixel[] Palette { get; }
/// <summary>
/// Creates the generic frame quantizer.
/// </summary>
/// <param name="configuration">The <see cref="Configuration"/> to configure internal operations.</param>
/// <returns>The <see cref="IFrameQuantizer{TPixel}"/>.</returns>
public IFrameQuantizer<TPixel> CreateFrameQuantizer(Configuration configuration)
=> ((IQuantizer)this).CreateFrameQuantizer<TPixel>(configuration);
/// <summary>
/// Creates the generic frame quantizer.
/// </summary>
/// <param name="configuration">The <see cref="Configuration"/> to configure internal operations.</param>
/// <param name="maxColors">The maximum number of colors to hold in the color palette.</param>
/// <returns>The <see cref="IFrameQuantizer{TPixel}"/>.</returns>
public IFrameQuantizer<TPixel> CreateFrameQuantizer(Configuration configuration, int maxColors)
=> ((IQuantizer)this).CreateFrameQuantizer<TPixel>(configuration, maxColors);
/// <inheritdoc/>
IFrameQuantizer<TPixel1> IQuantizer.CreateFrameQuantizer<TPixel1>(Configuration configuration)
{
if (!typeof(TPixel).Equals(typeof(TPixel1)))
{
throw new InvalidOperationException("Generic method type must be the same as class type.");
}
TPixel[] paletteRef = this.Palette;
return new PaletteFrameQuantizer<TPixel1>(this, Unsafe.As<TPixel[], TPixel1[]>(ref paletteRef));
}
/// <inheritdoc/>
IFrameQuantizer<TPixel1> IQuantizer.CreateFrameQuantizer<TPixel1>(Configuration configuration, int maxColors)
{
if (!typeof(TPixel).Equals(typeof(TPixel1)))
{
throw new InvalidOperationException("Generic method type must be the same as class type.");
}
TPixel[] paletteRef = this.Palette;
TPixel1[] castPalette = Unsafe.As<TPixel[], TPixel1[]>(ref paletteRef);
maxColors = maxColors.Clamp(QuantizerConstants.MinColors, QuantizerConstants.MaxColors);
int max = Math.Min(maxColors, castPalette.Length);
if (max != castPalette.Length)
{
return new PaletteFrameQuantizer<TPixel1>(this, castPalette.AsSpan(0, max).ToArray());
}
return new PaletteFrameQuantizer<TPixel1>(this, castPalette);
}
private static IErrorDiffuser GetDiffuser(bool dither) => dither ? KnownDiffusers.FloydSteinberg : null;
}
}

9
src/ImageSharp/Processing/Processors/Quantization/QuantizeProcessor{TPixel}.cs

@ -31,8 +31,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization
/// <inheritdoc />
protected override void OnFrameApply(ImageFrame<TPixel> source, Rectangle sourceRectangle, Configuration configuration)
{
using (IFrameQuantizer<TPixel> executor = this.quantizer.CreateFrameQuantizer<TPixel>(configuration))
using (QuantizedFrame<TPixel> quantized = executor.QuantizeFrame(source))
using (IFrameQuantizer<TPixel> frameQuantizer = this.quantizer.CreateFrameQuantizer<TPixel>(configuration))
using (IQuantizedFrame<TPixel> quantized = frameQuantizer.QuantizeFrame(source))
{
int paletteCount = quantized.Palette.Length - 1;
@ -43,12 +43,15 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization
{
Span<TPixel> row = source.GetPixelRowSpan(y);
ReadOnlySpan<byte> quantizedPixelSpan = quantized.GetPixelSpan();
ReadOnlySpan<TPixel> paletteSpan = quantized.Palette.Span;
int yy = y * source.Width;
for (int x = 0; x < source.Width; x++)
{
int i = x + yy;
row[x] = quantized.Palette[Math.Min(paletteCount, quantizedPixelSpan[i])];
row[x] = paletteSpan[Math.Min(paletteCount, quantizedPixelSpan[i])];
}
}
}

29
src/ImageSharp/Processing/Processors/Quantization/QuantizedFrameExtensions.cs

@ -0,0 +1,29 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Processing.Processors.Quantization
{
/// <summary>
/// Contains extension methods for <see cref="IQuantizedFrame{TPixel}"/>.
/// </summary>
public static class QuantizedFrameExtensions
{
/// <summary>
/// Gets the representation of the pixels as a <see cref="Span{T}"/> of contiguous memory
/// at row <paramref name="rowIndex"/> beginning from the the first pixel on that row.
/// </summary>
/// <param name="frame">The <see cref="IQuantizedFrame{TPixel}"/>.</param>
/// <param name="rowIndex">The row.</param>
/// <typeparam name="TPixel">The pixel type.</typeparam>
/// <returns>The pixel row as a <see cref="ReadOnlySpan{T}"/>.</returns>
[MethodImpl(InliningOptions.ShortMethod)]
public static ReadOnlySpan<byte> GetRowSpan<TPixel>(this IQuantizedFrame<TPixel> frame, int rowIndex)
where TPixel : struct, IPixel<TPixel>
=> frame.GetPixelSpan().Slice(rowIndex * frame.Width, frame.Width);
}
}

23
src/ImageSharp/Processing/Processors/Quantization/QuantizedFrame{TPixel}.cs

@ -8,14 +8,13 @@ using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.Memory;
// TODO: Consider pooling the TPixel palette also. For Rgba48+ this would end up on th LOH if 256 colors.
namespace SixLabors.ImageSharp.Processing.Processors.Quantization
{
/// <summary>
/// Represents a quantized image frame where the pixels indexed by a color palette.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
public class QuantizedFrame<TPixel> : IDisposable
public class QuantizedFrame<TPixel> : IQuantizedFrame<TPixel>
where TPixel : struct, IPixel<TPixel>
{
private IMemoryOwner<byte> pixels;
@ -27,7 +26,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization
/// <param name="width">The image width.</param>
/// <param name="height">The image height.</param>
/// <param name="palette">The color palette.</param>
public QuantizedFrame(MemoryAllocator memoryAllocator, int width, int height, TPixel[] palette)
internal QuantizedFrame(MemoryAllocator memoryAllocator, int width, int height, ReadOnlyMemory<TPixel> palette)
{
Guard.MustBeGreaterThan(width, 0, nameof(width));
Guard.MustBeGreaterThan(height, 0, nameof(height));
@ -51,23 +50,14 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization
/// <summary>
/// Gets the color palette of this <see cref="QuantizedFrame{TPixel}"/>.
/// </summary>
public TPixel[] Palette { get; private set; }
public ReadOnlyMemory<TPixel> Palette { get; private set; }
/// <summary>
/// Gets the pixels of this <see cref="QuantizedFrame{TPixel}"/>.
/// </summary>
/// <returns>The <see cref="Span{T}"/></returns>
[MethodImpl(InliningOptions.ShortMethod)]
public Span<byte> GetPixelSpan() => this.pixels.GetSpan();
/// <summary>
/// Gets the representation of the pixels as a <see cref="Span{T}"/> of contiguous memory
/// at row <paramref name="rowIndex"/> beginning from the first pixel on that row.
/// </summary>
/// <param name="rowIndex">The row.</param>
/// <returns>The <see cref="Span{T}"/></returns>
[MethodImpl(InliningOptions.ShortMethod)]
public Span<byte> GetRowSpan(int rowIndex) => this.GetPixelSpan().Slice(rowIndex * this.Width, this.Width);
public ReadOnlySpan<byte> GetPixelSpan() => this.pixels.GetSpan();
/// <inheritdoc/>
public void Dispose()
@ -76,5 +66,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization
this.pixels = null;
this.Palette = null;
}
/// <summary>
/// Get the non-readonly span of pixel data so <see cref="FrameQuantizer{TPixel}"/> can fill it.
/// </summary>
internal Span<byte> GetWritablePixelSpan() => this.pixels.GetSpan();
}
}

13
src/ImageSharp/Processing/Processors/Quantization/WebSafePaletteQuantizer.cs

@ -15,6 +15,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization
/// Initializes a new instance of the <see cref="WebSafePaletteQuantizer" /> class.
/// </summary>
public WebSafePaletteQuantizer()
: this(true)
{
}
@ -23,7 +24,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization
/// </summary>
/// <param name="dither">Whether to apply dithering to the output image</param>
public WebSafePaletteQuantizer(bool dither)
: base(dither)
: base(Color.WebSafePalette, dither)
{
}
@ -32,16 +33,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization
/// </summary>
/// <param name="diffuser">The error diffusion algorithm, if any, to apply to the output image</param>
public WebSafePaletteQuantizer(IErrorDiffuser diffuser)
: base(diffuser)
: base(Color.WebSafePalette, diffuser)
{
}
/// <inheritdoc />
public override IFrameQuantizer<TPixel> CreateFrameQuantizer<TPixel>(Configuration configuration)
=> this.CreateFrameQuantizer<TPixel>(configuration, NamedColors<TPixel>.WebSafePalette.Length);
/// <inheritdoc/>
public override IFrameQuantizer<TPixel> CreateFrameQuantizer<TPixel>(Configuration configuration, int maxColors)
=> this.CreateFrameQuantizer(configuration, NamedColors<TPixel>.WebSafePalette, maxColors);
}
}

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save