diff --git a/ImageSharp.sln.DotSettings b/ImageSharp.sln.DotSettings index 5268172429..ece3dddb3c 100644 --- a/ImageSharp.sln.DotSettings +++ b/ImageSharp.sln.DotSettings @@ -388,5 +388,6 @@ True True True + True True \ No newline at end of file diff --git a/src/ImageSharp/Advanced/AotCompilerTools.cs b/src/ImageSharp/Advanced/AotCompilerTools.cs index eb6991e6a1..82df7304e5 100644 --- a/src/ImageSharp/Advanced/AotCompilerTools.cs +++ b/src/ImageSharp/Advanced/AotCompilerTools.cs @@ -104,7 +104,7 @@ private static void AotCompileOctreeQuantizer() private static void AotCompileWuQuantizer() where TPixel : struct, IPixel { - var test = new WuFrameQuantizer(new WuQuantizer(false)); + var test = new WuFrameQuantizer(Configuration.Default.MemoryAllocator, new WuQuantizer(false)); test.QuantizeFrame(new ImageFrame(Configuration.Default, 1, 1)); test.AotGetPalette(); } diff --git a/src/ImageSharp/Color/Color.Conversions.cs b/src/ImageSharp/Color/Color.Conversions.cs new file mode 100644 index 0000000000..a524b9db1b --- /dev/null +++ b/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 +{ + /// + /// Contains constructors and implicit conversion methods. + /// + public readonly partial struct Color + { + /// + /// Initializes a new instance of the struct. + /// + /// The containing the color information. + [MethodImpl(InliningOptions.ShortMethod)] + public Color(Rgba64 pixel) => this.data = pixel; + + /// + /// Initializes a new instance of the struct. + /// + /// The containing the color information. + [MethodImpl(InliningOptions.ShortMethod)] + public Color(Rgba32 pixel) => this.data = new Rgba64(pixel); + + /// + /// Initializes a new instance of the struct. + /// + /// The containing the color information. + [MethodImpl(InliningOptions.ShortMethod)] + public Color(Argb32 pixel) => this.data = new Rgba64(pixel); + + /// + /// Initializes a new instance of the struct. + /// + /// The containing the color information. + [MethodImpl(InliningOptions.ShortMethod)] + public Color(Bgra32 pixel) => this.data = new Rgba64(pixel); + + /// + /// Initializes a new instance of the struct. + /// + /// The containing the color information. + [MethodImpl(InliningOptions.ShortMethod)] + public Color(Rgb24 pixel) => this.data = new Rgba64(pixel); + + /// + /// Initializes a new instance of the struct. + /// + /// The containing the color information. + [MethodImpl(InliningOptions.ShortMethod)] + public Color(Bgr24 pixel) => this.data = new Rgba64(pixel); + + /// + /// Initializes a new instance of the struct. + /// + /// The containing the color information. + [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(); + } +} \ No newline at end of file diff --git a/src/ImageSharp/Color/Color.NamedColors.cs b/src/ImageSharp/Color/Color.NamedColors.cs new file mode 100644 index 0000000000..8811516c1c --- /dev/null +++ b/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 +{ + /// + /// Contains static named color values. + /// + public readonly partial struct Color + { + /// + /// Represents a matching the W3C definition that has an hex value of #F0F8FF. + /// + public static readonly Color AliceBlue = FromRgba(240, 248, 255, 255); + + /// + /// Represents a matching the W3C definition that has an hex value of #FAEBD7. + /// + public static readonly Color AntiqueWhite = FromRgba(250, 235, 215, 255); + + /// + /// Represents a matching the W3C definition that has an hex value of #00FFFF. + /// + public static readonly Color Aqua = FromRgba(0, 255, 255, 255); + + /// + /// Represents a matching the W3C definition that has an hex value of #7FFFD4. + /// + public static readonly Color Aquamarine = FromRgba(127, 255, 212, 255); + + /// + /// Represents a matching the W3C definition that has an hex value of #F0FFFF. + /// + public static readonly Color Azure = FromRgba(240, 255, 255, 255); + + /// + /// Represents a matching the W3C definition that has an hex value of #F5F5DC. + /// + public static readonly Color Beige = FromRgba(245, 245, 220, 255); + + /// + /// Represents a matching the W3C definition that has an hex value of #FFE4C4. + /// + public static readonly Color Bisque = FromRgba(255, 228, 196, 255); + + /// + /// Represents a matching the W3C definition that has an hex value of #000000. + /// + public static readonly Color Black = FromRgba(0, 0, 0, 255); + + /// + /// Represents a matching the W3C definition that has an hex value of #FFEBCD. + /// + public static readonly Color BlanchedAlmond = FromRgba(255, 235, 205, 255); + + /// + /// Represents a matching the W3C definition that has an hex value of #0000FF. + /// + public static readonly Color Blue = FromRgba(0, 0, 255, 255); + + /// + /// Represents a matching the W3C definition that has an hex value of #8A2BE2. + /// + public static readonly Color BlueViolet = FromRgba(138, 43, 226, 255); + + /// + /// Represents a matching the W3C definition that has an hex value of #A52A2A. + /// + public static readonly Color Brown = FromRgba(165, 42, 42, 255); + + /// + /// Represents a matching the W3C definition that has an hex value of #DEB887. + /// + public static readonly Color BurlyWood = FromRgba(222, 184, 135, 255); + + /// + /// Represents a matching the W3C definition that has an hex value of #5F9EA0. + /// + public static readonly Color CadetBlue = FromRgba(95, 158, 160, 255); + + /// + /// Represents a matching the W3C definition that has an hex value of #7FFF00. + /// + public static readonly Color Chartreuse = FromRgba(127, 255, 0, 255); + + /// + /// Represents a matching the W3C definition that has an hex value of #D2691E. + /// + public static readonly Color Chocolate = FromRgba(210, 105, 30, 255); + + /// + /// Represents a matching the W3C definition that has an hex value of #FF7F50. + /// + public static readonly Color Coral = FromRgba(255, 127, 80, 255); + + /// + /// Represents a matching the W3C definition that has an hex value of #6495ED. + /// + public static readonly Color CornflowerBlue = FromRgba(100, 149, 237, 255); + + /// + /// Represents a matching the W3C definition that has an hex value of #FFF8DC. + /// + public static readonly Color Cornsilk = FromRgba(255, 248, 220, 255); + + /// + /// Represents a matching the W3C definition that has an hex value of #DC143C. + /// + public static readonly Color Crimson = FromRgba(220, 20, 60, 255); + + /// + /// Represents a matching the W3C definition that has an hex value of #00FFFF. + /// + public static readonly Color Cyan = FromRgba(0, 255, 255, 255); + + /// + /// Represents a matching the W3C definition that has an hex value of #00008B. + /// + public static readonly Color DarkBlue = FromRgba(0, 0, 139, 255); + + /// + /// Represents a matching the W3C definition that has an hex value of #008B8B. + /// + public static readonly Color DarkCyan = FromRgba(0, 139, 139, 255); + + /// + /// Represents a matching the W3C definition that has an hex value of #B8860B. + /// + public static readonly Color DarkGoldenrod = FromRgba(184, 134, 11, 255); + + /// + /// Represents a matching the W3C definition that has an hex value of #A9A9A9. + /// + public static readonly Color DarkGray = FromRgba(169, 169, 169, 255); + + /// + /// Represents a matching the W3C definition that has an hex value of #006400. + /// + public static readonly Color DarkGreen = FromRgba(0, 100, 0, 255); + + /// + /// Represents a matching the W3C definition that has an hex value of #BDB76B. + /// + public static readonly Color DarkKhaki = FromRgba(189, 183, 107, 255); + + /// + /// Represents a matching the W3C definition that has an hex value of #8B008B. + /// + public static readonly Color DarkMagenta = FromRgba(139, 0, 139, 255); + + /// + /// Represents a matching the W3C definition that has an hex value of #556B2F. + /// + public static readonly Color DarkOliveGreen = FromRgba(85, 107, 47, 255); + + /// + /// Represents a matching the W3C definition that has an hex value of #FF8C00. + /// + public static readonly Color DarkOrange = FromRgba(255, 140, 0, 255); + + /// + /// Represents a matching the W3C definition that has an hex value of #9932CC. + /// + public static readonly Color DarkOrchid = FromRgba(153, 50, 204, 255); + + /// + /// Represents a matching the W3C definition that has an hex value of #8B0000. + /// + public static readonly Color DarkRed = FromRgba(139, 0, 0, 255); + + /// + /// Represents a matching the W3C definition that has an hex value of #E9967A. + /// + public static readonly Color DarkSalmon = FromRgba(233, 150, 122, 255); + + /// + /// Represents a matching the W3C definition that has an hex value of #8FBC8B. + /// + public static readonly Color DarkSeaGreen = FromRgba(143, 188, 139, 255); + + /// + /// Represents a matching the W3C definition that has an hex value of #483D8B. + /// + public static readonly Color DarkSlateBlue = FromRgba(72, 61, 139, 255); + + /// + /// Represents a matching the W3C definition that has an hex value of #2F4F4F. + /// + public static readonly Color DarkSlateGray = FromRgba(47, 79, 79, 255); + + /// + /// Represents a matching the W3C definition that has an hex value of #00CED1. + /// + public static readonly Color DarkTurquoise = FromRgba(0, 206, 209, 255); + + /// + /// Represents a matching the W3C definition that has an hex value of #9400D3. + /// + public static readonly Color DarkViolet = FromRgba(148, 0, 211, 255); + + /// + /// Represents a matching the W3C definition that has an hex value of #FF1493. + /// + public static readonly Color DeepPink = FromRgba(255, 20, 147, 255); + + /// + /// Represents a matching the W3C definition that has an hex value of #00BFFF. + /// + public static readonly Color DeepSkyBlue = FromRgba(0, 191, 255, 255); + + /// + /// Represents a matching the W3C definition that has an hex value of #696969. + /// + public static readonly Color DimGray = FromRgba(105, 105, 105, 255); + + /// + /// Represents a matching the W3C definition that has an hex value of #1E90FF. + /// + public static readonly Color DodgerBlue = FromRgba(30, 144, 255, 255); + + /// + /// Represents a matching the W3C definition that has an hex value of #B22222. + /// + public static readonly Color Firebrick = FromRgba(178, 34, 34, 255); + + /// + /// Represents a matching the W3C definition that has an hex value of #FFFAF0. + /// + public static readonly Color FloralWhite = FromRgba(255, 250, 240, 255); + + /// + /// Represents a matching the W3C definition that has an hex value of #228B22. + /// + public static readonly Color ForestGreen = FromRgba(34, 139, 34, 255); + + /// + /// Represents a matching the W3C definition that has an hex value of #FF00FF. + /// + public static readonly Color Fuchsia = FromRgba(255, 0, 255, 255); + + /// + /// Represents a matching the W3C definition that has an hex value of #DCDCDC. + /// + public static readonly Color Gainsboro = FromRgba(220, 220, 220, 255); + + /// + /// Represents a matching the W3C definition that has an hex value of #F8F8FF. + /// + public static readonly Color GhostWhite = FromRgba(248, 248, 255, 255); + + /// + /// Represents a matching the W3C definition that has an hex value of #FFD700. + /// + public static readonly Color Gold = FromRgba(255, 215, 0, 255); + + /// + /// Represents a matching the W3C definition that has an hex value of #DAA520. + /// + public static readonly Color Goldenrod = FromRgba(218, 165, 32, 255); + + /// + /// Represents a matching the W3C definition that has an hex value of #808080. + /// + public static readonly Color Gray = FromRgba(128, 128, 128, 255); + + /// + /// Represents a matching the W3C definition that has an hex value of #008000. + /// + public static readonly Color Green = FromRgba(0, 128, 0, 255); + + /// + /// Represents a matching the W3C definition that has an hex value of #ADFF2F. + /// + public static readonly Color GreenYellow = FromRgba(173, 255, 47, 255); + + /// + /// Represents a matching the W3C definition that has an hex value of #F0FFF0. + /// + public static readonly Color Honeydew = FromRgba(240, 255, 240, 255); + + /// + /// Represents a matching the W3C definition that has an hex value of #FF69B4. + /// + public static readonly Color HotPink = FromRgba(255, 105, 180, 255); + + /// + /// Represents a matching the W3C definition that has an hex value of #CD5C5C. + /// + public static readonly Color IndianRed = FromRgba(205, 92, 92, 255); + + /// + /// Represents a matching the W3C definition that has an hex value of #4B0082. + /// + public static readonly Color Indigo = FromRgba(75, 0, 130, 255); + + /// + /// Represents a matching the W3C definition that has an hex value of #FFFFF0. + /// + public static readonly Color Ivory = FromRgba(255, 255, 240, 255); + + /// + /// Represents a matching the W3C definition that has an hex value of #F0E68C. + /// + public static readonly Color Khaki = FromRgba(240, 230, 140, 255); + + /// + /// Represents a matching the W3C definition that has an hex value of #E6E6FA. + /// + public static readonly Color Lavender = FromRgba(230, 230, 250, 255); + + /// + /// Represents a matching the W3C definition that has an hex value of #FFF0F5. + /// + public static readonly Color LavenderBlush = FromRgba(255, 240, 245, 255); + + /// + /// Represents a matching the W3C definition that has an hex value of #7CFC00. + /// + public static readonly Color LawnGreen = FromRgba(124, 252, 0, 255); + + /// + /// Represents a matching the W3C definition that has an hex value of #FFFACD. + /// + public static readonly Color LemonChiffon = FromRgba(255, 250, 205, 255); + + /// + /// Represents a matching the W3C definition that has an hex value of #ADD8E6. + /// + public static readonly Color LightBlue = FromRgba(173, 216, 230, 255); + + /// + /// Represents a matching the W3C definition that has an hex value of #F08080. + /// + public static readonly Color LightCoral = FromRgba(240, 128, 128, 255); + + /// + /// Represents a matching the W3C definition that has an hex value of #E0FFFF. + /// + public static readonly Color LightCyan = FromRgba(224, 255, 255, 255); + + /// + /// Represents a matching the W3C definition that has an hex value of #FAFAD2. + /// + public static readonly Color LightGoldenrodYellow = FromRgba(250, 250, 210, 255); + + /// + /// Represents a matching the W3C definition that has an hex value of #D3D3D3. + /// + public static readonly Color LightGray = FromRgba(211, 211, 211, 255); + + /// + /// Represents a matching the W3C definition that has an hex value of #90EE90. + /// + public static readonly Color LightGreen = FromRgba(144, 238, 144, 255); + + /// + /// Represents a matching the W3C definition that has an hex value of #FFB6C1. + /// + public static readonly Color LightPink = FromRgba(255, 182, 193, 255); + + /// + /// Represents a matching the W3C definition that has an hex value of #FFA07A. + /// + public static readonly Color LightSalmon = FromRgba(255, 160, 122, 255); + + /// + /// Represents a matching the W3C definition that has an hex value of #20B2AA. + /// + public static readonly Color LightSeaGreen = FromRgba(32, 178, 170, 255); + + /// + /// Represents a matching the W3C definition that has an hex value of #87CEFA. + /// + public static readonly Color LightSkyBlue = FromRgba(135, 206, 250, 255); + + /// + /// Represents a matching the W3C definition that has an hex value of #778899. + /// + public static readonly Color LightSlateGray = FromRgba(119, 136, 153, 255); + + /// + /// Represents a matching the W3C definition that has an hex value of #B0C4DE. + /// + public static readonly Color LightSteelBlue = FromRgba(176, 196, 222, 255); + + /// + /// Represents a matching the W3C definition that has an hex value of #FFFFE0. + /// + public static readonly Color LightYellow = FromRgba(255, 255, 224, 255); + + /// + /// Represents a matching the W3C definition that has an hex value of #00FF00. + /// + public static readonly Color Lime = FromRgba(0, 255, 0, 255); + + /// + /// Represents a matching the W3C definition that has an hex value of #32CD32. + /// + public static readonly Color LimeGreen = FromRgba(50, 205, 50, 255); + + /// + /// Represents a matching the W3C definition that has an hex value of #FAF0E6. + /// + public static readonly Color Linen = FromRgba(250, 240, 230, 255); + + /// + /// Represents a matching the W3C definition that has an hex value of #FF00FF. + /// + public static readonly Color Magenta = FromRgba(255, 0, 255, 255); + + /// + /// Represents a matching the W3C definition that has an hex value of #800000. + /// + public static readonly Color Maroon = FromRgba(128, 0, 0, 255); + + /// + /// Represents a matching the W3C definition that has an hex value of #66CDAA. + /// + public static readonly Color MediumAquamarine = FromRgba(102, 205, 170, 255); + + /// + /// Represents a matching the W3C definition that has an hex value of #0000CD. + /// + public static readonly Color MediumBlue = FromRgba(0, 0, 205, 255); + + /// + /// Represents a matching the W3C definition that has an hex value of #BA55D3. + /// + public static readonly Color MediumOrchid = FromRgba(186, 85, 211, 255); + + /// + /// Represents a matching the W3C definition that has an hex value of #9370DB. + /// + public static readonly Color MediumPurple = FromRgba(147, 112, 219, 255); + + /// + /// Represents a matching the W3C definition that has an hex value of #3CB371. + /// + public static readonly Color MediumSeaGreen = FromRgba(60, 179, 113, 255); + + /// + /// Represents a matching the W3C definition that has an hex value of #7B68EE. + /// + public static readonly Color MediumSlateBlue = FromRgba(123, 104, 238, 255); + + /// + /// Represents a matching the W3C definition that has an hex value of #00FA9A. + /// + public static readonly Color MediumSpringGreen = FromRgba(0, 250, 154, 255); + + /// + /// Represents a matching the W3C definition that has an hex value of #48D1CC. + /// + public static readonly Color MediumTurquoise = FromRgba(72, 209, 204, 255); + + /// + /// Represents a matching the W3C definition that has an hex value of #C71585. + /// + public static readonly Color MediumVioletRed = FromRgba(199, 21, 133, 255); + + /// + /// Represents a matching the W3C definition that has an hex value of #191970. + /// + public static readonly Color MidnightBlue = FromRgba(25, 25, 112, 255); + + /// + /// Represents a matching the W3C definition that has an hex value of #F5FFFA. + /// + public static readonly Color MintCream = FromRgba(245, 255, 250, 255); + + /// + /// Represents a matching the W3C definition that has an hex value of #FFE4E1. + /// + public static readonly Color MistyRose = FromRgba(255, 228, 225, 255); + + /// + /// Represents a matching the W3C definition that has an hex value of #FFE4B5. + /// + public static readonly Color Moccasin = FromRgba(255, 228, 181, 255); + + /// + /// Represents a matching the W3C definition that has an hex value of #FFDEAD. + /// + public static readonly Color NavajoWhite = FromRgba(255, 222, 173, 255); + + /// + /// Represents a matching the W3C definition that has an hex value of #000080. + /// + public static readonly Color Navy = FromRgba(0, 0, 128, 255); + + /// + /// Represents a matching the W3C definition that has an hex value of #FDF5E6. + /// + public static readonly Color OldLace = FromRgba(253, 245, 230, 255); + + /// + /// Represents a matching the W3C definition that has an hex value of #808000. + /// + public static readonly Color Olive = FromRgba(128, 128, 0, 255); + + /// + /// Represents a matching the W3C definition that has an hex value of #6B8E23. + /// + public static readonly Color OliveDrab = FromRgba(107, 142, 35, 255); + + /// + /// Represents a matching the W3C definition that has an hex value of #FFA500. + /// + public static readonly Color Orange = FromRgba(255, 165, 0, 255); + + /// + /// Represents a matching the W3C definition that has an hex value of #FF4500. + /// + public static readonly Color OrangeRed = FromRgba(255, 69, 0, 255); + + /// + /// Represents a matching the W3C definition that has an hex value of #DA70D6. + /// + public static readonly Color Orchid = FromRgba(218, 112, 214, 255); + + /// + /// Represents a matching the W3C definition that has an hex value of #EEE8AA. + /// + public static readonly Color PaleGoldenrod = FromRgba(238, 232, 170, 255); + + /// + /// Represents a matching the W3C definition that has an hex value of #98FB98. + /// + public static readonly Color PaleGreen = FromRgba(152, 251, 152, 255); + + /// + /// Represents a matching the W3C definition that has an hex value of #AFEEEE. + /// + public static readonly Color PaleTurquoise = FromRgba(175, 238, 238, 255); + + /// + /// Represents a matching the W3C definition that has an hex value of #DB7093. + /// + public static readonly Color PaleVioletRed = FromRgba(219, 112, 147, 255); + + /// + /// Represents a matching the W3C definition that has an hex value of #FFEFD5. + /// + public static readonly Color PapayaWhip = FromRgba(255, 239, 213, 255); + + /// + /// Represents a matching the W3C definition that has an hex value of #FFDAB9. + /// + public static readonly Color PeachPuff = FromRgba(255, 218, 185, 255); + + /// + /// Represents a matching the W3C definition that has an hex value of #CD853F. + /// + public static readonly Color Peru = FromRgba(205, 133, 63, 255); + + /// + /// Represents a matching the W3C definition that has an hex value of #FFC0CB. + /// + public static readonly Color Pink = FromRgba(255, 192, 203, 255); + + /// + /// Represents a matching the W3C definition that has an hex value of #DDA0DD. + /// + public static readonly Color Plum = FromRgba(221, 160, 221, 255); + + /// + /// Represents a matching the W3C definition that has an hex value of #B0E0E6. + /// + public static readonly Color PowderBlue = FromRgba(176, 224, 230, 255); + + /// + /// Represents a matching the W3C definition that has an hex value of #800080. + /// + public static readonly Color Purple = FromRgba(128, 0, 128, 255); + + /// + /// Represents a matching the W3C definition that has an hex value of #663399. + /// + public static readonly Color RebeccaPurple = FromRgba(102, 51, 153, 255); + + /// + /// Represents a matching the W3C definition that has an hex value of #FF0000. + /// + public static readonly Color Red = FromRgba(255, 0, 0, 255); + + /// + /// Represents a matching the W3C definition that has an hex value of #BC8F8F. + /// + public static readonly Color RosyBrown = FromRgba(188, 143, 143, 255); + + /// + /// Represents a matching the W3C definition that has an hex value of #4169E1. + /// + public static readonly Color RoyalBlue = FromRgba(65, 105, 225, 255); + + /// + /// Represents a matching the W3C definition that has an hex value of #8B4513. + /// + public static readonly Color SaddleBrown = FromRgba(139, 69, 19, 255); + + /// + /// Represents a matching the W3C definition that has an hex value of #FA8072. + /// + public static readonly Color Salmon = FromRgba(250, 128, 114, 255); + + /// + /// Represents a matching the W3C definition that has an hex value of #F4A460. + /// + public static readonly Color SandyBrown = FromRgba(244, 164, 96, 255); + + /// + /// Represents a matching the W3C definition that has an hex value of #2E8B57. + /// + public static readonly Color SeaGreen = FromRgba(46, 139, 87, 255); + + /// + /// Represents a matching the W3C definition that has an hex value of #FFF5EE. + /// + public static readonly Color SeaShell = FromRgba(255, 245, 238, 255); + + /// + /// Represents a matching the W3C definition that has an hex value of #A0522D. + /// + public static readonly Color Sienna = FromRgba(160, 82, 45, 255); + + /// + /// Represents a matching the W3C definition that has an hex value of #C0C0C0. + /// + public static readonly Color Silver = FromRgba(192, 192, 192, 255); + + /// + /// Represents a matching the W3C definition that has an hex value of #87CEEB. + /// + public static readonly Color SkyBlue = FromRgba(135, 206, 235, 255); + + /// + /// Represents a matching the W3C definition that has an hex value of #6A5ACD. + /// + public static readonly Color SlateBlue = FromRgba(106, 90, 205, 255); + + /// + /// Represents a matching the W3C definition that has an hex value of #708090. + /// + public static readonly Color SlateGray = FromRgba(112, 128, 144, 255); + + /// + /// Represents a matching the W3C definition that has an hex value of #FFFAFA. + /// + public static readonly Color Snow = FromRgba(255, 250, 250, 255); + + /// + /// Represents a matching the W3C definition that has an hex value of #00FF7F. + /// + public static readonly Color SpringGreen = FromRgba(0, 255, 127, 255); + + /// + /// Represents a matching the W3C definition that has an hex value of #4682B4. + /// + public static readonly Color SteelBlue = FromRgba(70, 130, 180, 255); + + /// + /// Represents a matching the W3C definition that has an hex value of #D2B48C. + /// + public static readonly Color Tan = FromRgba(210, 180, 140, 255); + + /// + /// Represents a matching the W3C definition that has an hex value of #008080. + /// + public static readonly Color Teal = FromRgba(0, 128, 128, 255); + + /// + /// Represents a matching the W3C definition that has an hex value of #D8BFD8. + /// + public static readonly Color Thistle = FromRgba(216, 191, 216, 255); + + /// + /// Represents a matching the W3C definition that has an hex value of #FF6347. + /// + public static readonly Color Tomato = FromRgba(255, 99, 71, 255); + + /// + /// Represents a matching the W3C definition that has an hex value of #FFFFFF. + /// + public static readonly Color Transparent = FromRgba(255, 255, 255, 0); + + /// + /// Represents a matching the W3C definition that has an hex value of #40E0D0. + /// + public static readonly Color Turquoise = FromRgba(64, 224, 208, 255); + + /// + /// Represents a matching the W3C definition that has an hex value of #EE82EE. + /// + public static readonly Color Violet = FromRgba(238, 130, 238, 255); + + /// + /// Represents a matching the W3C definition that has an hex value of #F5DEB3. + /// + public static readonly Color Wheat = FromRgba(245, 222, 179, 255); + + /// + /// Represents a matching the W3C definition that has an hex value of #FFFFFF. + /// + public static readonly Color White = FromRgba(255, 255, 255, 255); + + /// + /// Represents a matching the W3C definition that has an hex value of #F5F5F5. + /// + public static readonly Color WhiteSmoke = FromRgba(245, 245, 245, 255); + + /// + /// Represents a matching the W3C definition that has an hex value of #FFFF00. + /// + public static readonly Color Yellow = FromRgba(255, 255, 0, 255); + + /// + /// Represents a matching the W3C definition that has an hex value of #9ACD32. + /// + public static readonly Color YellowGreen = FromRgba(154, 205, 50, 255); + } +} \ No newline at end of file diff --git a/src/ImageSharp/Color/Color.WebSafePalette.cs b/src/ImageSharp/Color/Color.WebSafePalette.cs new file mode 100644 index 0000000000..8e5fb2a55b --- /dev/null +++ b/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 +{ + /// + /// Contains the definition of . + /// + public partial struct Color + { + private static readonly Lazy WebSafePaletteLazy = new Lazy(CreateWebSafePalette, true); + + /// + /// Gets a collection of named, web safe colors as defined in the CSS Color Module Level 4. + /// + public static ReadOnlyMemory 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 + }; + } +} \ No newline at end of file diff --git a/src/ImageSharp/Color/Color.WernerPalette.cs b/src/ImageSharp/Color/Color.WernerPalette.cs new file mode 100644 index 0000000000..768fe065cd --- /dev/null +++ b/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 +{ + /// + /// Contains the definition of . + /// + public partial struct Color + { + private static readonly Lazy WernerPaletteLazy = new Lazy(CreateWernerPalette, true); + + /// + /// Gets a collection of colors as defined in the original second edition of Werner’s Nomenclature of Colours 1821. + /// The hex codes were collected and defined by Nicholas Rougeux . + /// + public static ReadOnlyMemory 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") + }; + } +} \ No newline at end of file diff --git a/src/ImageSharp/Color/Color.cs b/src/ImageSharp/Color/Color.cs new file mode 100644 index 0000000000..e4640ff632 --- /dev/null +++ b/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 +{ + /// + /// Represents a color value that is convertible to any type. + /// + /// + /// 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, has to be converted to a specific pixel value + /// to query the color components. + /// + public readonly partial struct Color : IEquatable + { + 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); + } + + /// + /// Checks whether two structures are equal. + /// + /// The left hand operand. + /// The right hand operand. + /// + /// True if the parameter is equal to the parameter; + /// otherwise, false. + /// + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator ==(Color left, Color right) + { + return left.Equals(right); + } + + /// + /// Checks whether two structures are equal. + /// + /// The left hand operand. + /// The right hand operand. + /// + /// True if the parameter is not equal to the parameter; + /// otherwise, false. + /// + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator !=(Color left, Color right) + { + return !left.Equals(right); + } + + /// + /// Creates a from RGBA bytes. + /// + /// The red component (0-255). + /// The green component (0-255). + /// The blue component (0-255). + /// The alpha component (0-255). + /// The . + [MethodImpl(InliningOptions.ShortMethod)] + public static Color FromRgba(byte r, byte g, byte b, byte a) => new Color(r, g, b, a); + + /// + /// Creates a from RGB bytes. + /// + /// The red component (0-255). + /// The green component (0-255). + /// The blue component (0-255). + /// The . + [MethodImpl(InliningOptions.ShortMethod)] + public static Color FromRgb(byte r, byte g, byte b) => new Color(r, g, b); + + /// + /// Creates a new instance from the string representing a color in hexadecimal form. + /// + /// + /// The hexadecimal representation of the combined color components arranged + /// in rgb, rgba, rrggbb, or rrggbbaa format to match web syntax. + /// + /// Returns a that represents the color defined by the provided RGBA hex string. + 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); + } + + /// + /// Gets the hexadecimal representation of the color instance in rrggbbaa form. + /// + /// A hexadecimal string representation of the value. + [MethodImpl(InliningOptions.ShortMethod)] + public string ToHex() => this.data.ToRgba32().ToHex(); + + /// + public override string ToString() => this.ToHex(); + + /// + /// Converts the color instance to an + /// implementation defined by . + /// + /// The pixel type to convert to. + /// The pixel value. + [MethodImpl(InliningOptions.ShortMethod)] + public TPixel ToPixel() + where TPixel : struct, IPixel + { + TPixel pixel = default; + pixel.FromRgba64(this.data); + return pixel; + } + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public bool Equals(Color other) + { + return this.data.PackedValue == other.data.PackedValue; + } + + /// + public override bool Equals(object obj) + { + return obj is Color other && this.Equals(other); + } + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public override int GetHashCode() + { + return this.data.PackedValue.GetHashCode(); + } + + /// + /// Bulk convert a span of to a span of a specified pixel type. + /// + [MethodImpl(InliningOptions.ShortMethod)] + internal static void ToPixel( + Configuration configuration, + ReadOnlySpan source, + Span destination) + where TPixel : struct, IPixel + { + ReadOnlySpan rgba64Span = MemoryMarshal.Cast(source); + PixelOperations.Instance.FromRgba64(Configuration.Default, rgba64Span, destination); + } + + /// + /// Converts the specified hex value to an rrggbbaa hex value. + /// + /// The hex value to convert. + /// + /// A rrggbbaa hex value. + /// + 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 }); + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs b/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs index 90ea673d3e..edde7dc893 100644 --- a/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs +++ b/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs @@ -306,12 +306,15 @@ private void Write8Bit(Stream stream, ImageFrame image) where TPixel : struct, IPixel { using (IMemoryOwner colorPaletteBuffer = this.memoryAllocator.AllocateManagedByteBuffer(ColorPaletteSize8Bit, AllocationOptions.Clean)) - using (QuantizedFrame quantized = this.quantizer.CreateFrameQuantizer(this.configuration, 256).QuantizeFrame(image)) + using (IQuantizedFrame quantized = this.quantizer.CreateFrameQuantizer(this.configuration, 256).QuantizeFrame(image)) { Span colorPalette = colorPaletteBuffer.GetSpan(); int idx = 0; var color = default(Rgba32); - foreach (TPixel quantizedColor in quantized.Palette) + ReadOnlySpan 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 @@ private void Write8Bit(Stream stream, ImageFrame image) for (int y = image.Height - 1; y >= 0; y--) { - Span pixelSpan = quantized.GetRowSpan(y); + ReadOnlySpan pixelSpan = quantized.GetRowSpan(y); stream.Write(pixelSpan); for (int i = 0; i < this.padding; i++) diff --git a/src/ImageSharp/Formats/Gif/GifEncoderCore.cs b/src/ImageSharp/Formats/Gif/GifEncoderCore.cs index 12a515cca7..36e27866e9 100644 --- a/src/ImageSharp/Formats/Gif/GifEncoderCore.cs +++ b/src/ImageSharp/Formats/Gif/GifEncoderCore.cs @@ -95,7 +95,7 @@ public void Encode(Image image, Stream stream) bool useGlobalTable = this.colorTableMode == GifColorTableMode.Global; // Quantize the image returning a palette. - QuantizedFrame quantized = null; + IQuantizedFrame quantized = null; using (IFrameQuantizer frameQuantizer = this.quantizer.CreateFrameQuantizer(image.GetConfiguration())) { quantized = frameQuantizer.QuantizeFrame(image.Frames.RootFrame); @@ -141,11 +141,9 @@ public void Encode(Image image, Stream stream) stream.WriteByte(GifConstants.EndIntroducer); } - private void EncodeGlobal(Image image, QuantizedFrame quantized, int transparencyIndex, Stream stream) + private void EncodeGlobal(Image image, IQuantizedFrame quantized, int transparencyIndex, Stream stream) where TPixel : struct, IPixel { - var palleteQuantizer = new PaletteQuantizer(quantized.Palette, this.quantizer.Diffuser); - for (int i = 0; i < image.Frames.Count; i++) { ImageFrame frame = image.Frames[i]; @@ -160,16 +158,19 @@ private void EncodeGlobal(Image image, QuantizedFrame qu } else { - using (IFrameQuantizer palleteFrameQuantizer = palleteQuantizer.CreateFrameQuantizer(image.GetConfiguration())) - using (QuantizedFrame paletteQuantized = palleteFrameQuantizer.QuantizeFrame(frame)) + using (IFrameQuantizer palleteFrameQuantizer = + new PaletteFrameQuantizer(this.quantizer.Diffuser, quantized.Palette)) { - this.WriteImageData(paletteQuantized, stream); + using (IQuantizedFrame paletteQuantized = palleteFrameQuantizer.QuantizeFrame(frame)) + { + this.WriteImageData(paletteQuantized, stream); + } } } } } - private void EncodeLocal(Image image, QuantizedFrame quantized, Stream stream) + private void EncodeLocal(Image image, IQuantizedFrame quantized, Stream stream) where TPixel : struct, IPixel { ImageFrame previousFrame = null; @@ -221,7 +222,7 @@ private void EncodeLocal(Image image, QuantizedFrame qua /// /// The . /// - private int GetTransparentIndex(QuantizedFrame quantized) + private int GetTransparentIndex(IQuantizedFrame quantized) where TPixel : struct, IPixel { // Transparent pixels are much more likely to be found at the end of a palette @@ -232,7 +233,7 @@ private int GetTransparentIndex(QuantizedFrame quantized) { Span rgbaSpan = rgbaBuffer.GetSpan(); ref Rgba32 paletteRef = ref MemoryMarshal.GetReference(rgbaSpan); - PixelOperations.Instance.ToRgba32(this.configuration, quantized.Palette, rgbaSpan); + PixelOperations.Instance.ToRgba32(this.configuration, quantized.Palette.Span, rgbaSpan); for (int i = quantized.Palette.Length - 1; i >= 0; i--) { @@ -424,7 +425,7 @@ private void WriteImageDescriptor(ImageFrame image, bool hasColo /// The pixel format. /// The to encode. /// The stream to write to. - private void WriteColorTable(QuantizedFrame image, Stream stream) + private void WriteColorTable(IQuantizedFrame image, Stream stream) where TPixel : struct, IPixel { // The maximum number of colors for the bit depth @@ -435,7 +436,7 @@ private void WriteColorTable(QuantizedFrame image, Stream stream { PixelOperations.Instance.ToRgb24Bytes( this.configuration, - image.Palette.AsSpan(), + image.Palette.Span, colorTable.GetSpan(), pixelCount); stream.Write(colorTable.Array, 0, colorTableLength); @@ -446,9 +447,9 @@ private void WriteColorTable(QuantizedFrame image, Stream stream /// Writes the image pixel data to the stream. /// /// The pixel format. - /// The containing indexed pixels. + /// The containing indexed pixels. /// The stream to write to. - private void WriteImageData(QuantizedFrame image, Stream stream) + private void WriteImageData(IQuantizedFrame image, Stream stream) where TPixel : struct, IPixel { using (var encoder = new LzwEncoder(this.memoryAllocator, (byte)this.bitDepth)) diff --git a/src/ImageSharp/Formats/Gif/LzwEncoder.cs b/src/ImageSharp/Formats/Gif/LzwEncoder.cs index 2d32fd23aa..b4c80a3da1 100644 --- a/src/ImageSharp/Formats/Gif/LzwEncoder.cs +++ b/src/ImageSharp/Formats/Gif/LzwEncoder.cs @@ -180,7 +180,7 @@ public LzwEncoder(MemoryAllocator memoryAllocator, int colorDepth) /// /// The span of indexed pixels. /// The stream to write to. - public void Encode(Span indexedPixels, Stream stream) + public void Encode(ReadOnlySpan indexedPixels, Stream stream) { // Write "initial code size" byte stream.WriteByte((byte)this.initialCodeSize); @@ -251,7 +251,7 @@ private void ResetCodeTable() /// The span of indexed pixels. /// The initial bits. /// The stream to write to. - private void Compress(Span indexedPixels, int intialBits, Stream stream) + private void Compress(ReadOnlySpan indexedPixels, int intialBits, Stream stream) { int fcode; int c; @@ -375,7 +375,7 @@ private void FlushPacket(Stream outStream) /// The /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - private int NextPixel(Span indexedPixels) + private int NextPixel(ReadOnlySpan indexedPixels) { return indexedPixels[this.position++] & 0xFF; } diff --git a/src/ImageSharp/Formats/Png/PngEncoderCore.cs b/src/ImageSharp/Formats/Png/PngEncoderCore.cs index 7415b07532..cbc35f3c3e 100644 --- a/src/ImageSharp/Formats/Png/PngEncoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngEncoderCore.cs @@ -227,7 +227,7 @@ public void Encode(Image image, Stream stream) stream.Write(PngConstants.HeaderBytes, 0, PngConstants.HeaderBytes.Length); - QuantizedFrame quantized = null; + IQuantizedFrame quantized = null; if (this.pngColorType == PngColorType.Palette) { byte bits = (byte)this.pngBitDepth; @@ -511,7 +511,7 @@ private void CollectTPixelBytes(ReadOnlySpan rowSpan) /// The quantized pixels. Can be null. /// The row. /// The - private IManagedByteBuffer EncodePixelRow(ReadOnlySpan rowSpan, QuantizedFrame quantized, int row) + private IManagedByteBuffer EncodePixelRow(ReadOnlySpan rowSpan, IQuantizedFrame quantized, int row) where TPixel : struct, IPixel { switch (this.pngColorType) @@ -662,11 +662,11 @@ private void WriteHeaderChunk(Stream stream, in PngHeader header) /// The pixel format. /// The containing image data. /// The quantized frame. - private void WritePaletteChunk(Stream stream, QuantizedFrame quantized) + private void WritePaletteChunk(Stream stream, IQuantizedFrame quantized) where TPixel : struct, IPixel { // Grab the palette and write it to the stream. - TPixel[] palette = quantized.Palette; + ReadOnlySpan palette = quantized.Palette.Span; int paletteLength = Math.Min(palette.Length, 256); int colorTableLength = paletteLength * 3; bool anyAlpha = false; @@ -676,7 +676,7 @@ private void WritePaletteChunk(Stream stream, QuantizedFrame qua { ref byte colorTableRef = ref MemoryMarshal.GetReference(colorTable.GetSpan()); ref byte alphaTableRef = ref MemoryMarshal.GetReference(alphaTable.GetSpan()); - Span quantizedSpan = quantized.GetPixelSpan(); + ReadOnlySpan quantizedSpan = quantized.GetPixelSpan(); Rgba32 rgba = default; @@ -808,7 +808,7 @@ private void WriteTransparencyChunk(Stream stream, PngMetadata pngMetadata) /// The image. /// The quantized pixel data. Can be null. /// The stream. - private void WriteDataChunks(ImageFrame pixels, QuantizedFrame quantized, Stream stream) + private void WriteDataChunks(ImageFrame pixels, IQuantizedFrame quantized, Stream stream) where TPixel : struct, IPixel { this.bytesPerScanline = this.CalculateScanlineLength(this.width); diff --git a/src/ImageSharp/ImageSharp.csproj.DotSettings b/src/ImageSharp/ImageSharp.csproj.DotSettings index e446893e94..018ca75cdf 100644 --- a/src/ImageSharp/ImageSharp.csproj.DotSettings +++ b/src/ImageSharp/ImageSharp.csproj.DotSettings @@ -1,4 +1,5 @@  + True True True True @@ -6,6 +7,7 @@ True True True + True True True True \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/ColorBuilder{TPixel}.cs b/src/ImageSharp/PixelFormats/ColorBuilder{TPixel}.cs index 2572b32933..c1fb13e4da 100644 --- a/src/ImageSharp/PixelFormats/ColorBuilder{TPixel}.cs +++ b/src/ImageSharp/PixelFormats/ColorBuilder{TPixel}.cs @@ -47,7 +47,7 @@ public static TPixel FromHex(string hex) /// The green intensity. /// The blue intensity. /// Returns a that represents the color defined by the provided RGB values with 100% opacity. - 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); /// /// Creates a new representation from standard RGBA bytes. @@ -57,7 +57,7 @@ public static TPixel FromHex(string hex) /// The blue intensity. /// The alpha intensity. /// Returns a that represents the color defined by the provided RGBA values. - 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)); diff --git a/src/ImageSharp/PixelFormats/NamedColors{TPixel}.cs b/src/ImageSharp/PixelFormats/NamedColors{TPixel}.cs index 7e093de042..2138e2e2f7 100644 --- a/src/ImageSharp/PixelFormats/NamedColors{TPixel}.cs +++ b/src/ImageSharp/PixelFormats/NamedColors{TPixel}.cs @@ -22,712 +22,712 @@ public static class NamedColors /// /// Represents a matching the W3C definition that has an hex value of #F0F8FF. /// - public static readonly TPixel AliceBlue = ColorBuilder.FromRGBA(240, 248, 255, 255); + public static readonly TPixel AliceBlue = ColorBuilder.FromRgba(240, 248, 255, 255); /// /// Represents a matching the W3C definition that has an hex value of #FAEBD7. /// - public static readonly TPixel AntiqueWhite = ColorBuilder.FromRGBA(250, 235, 215, 255); + public static readonly TPixel AntiqueWhite = ColorBuilder.FromRgba(250, 235, 215, 255); /// /// Represents a matching the W3C definition that has an hex value of #00FFFF. /// - public static readonly TPixel Aqua = ColorBuilder.FromRGBA(0, 255, 255, 255); + public static readonly TPixel Aqua = ColorBuilder.FromRgba(0, 255, 255, 255); /// /// Represents a matching the W3C definition that has an hex value of #7FFFD4. /// - public static readonly TPixel Aquamarine = ColorBuilder.FromRGBA(127, 255, 212, 255); + public static readonly TPixel Aquamarine = ColorBuilder.FromRgba(127, 255, 212, 255); /// /// Represents a matching the W3C definition that has an hex value of #F0FFFF. /// - public static readonly TPixel Azure = ColorBuilder.FromRGBA(240, 255, 255, 255); + public static readonly TPixel Azure = ColorBuilder.FromRgba(240, 255, 255, 255); /// /// Represents a matching the W3C definition that has an hex value of #F5F5DC. /// - public static readonly TPixel Beige = ColorBuilder.FromRGBA(245, 245, 220, 255); + public static readonly TPixel Beige = ColorBuilder.FromRgba(245, 245, 220, 255); /// /// Represents a matching the W3C definition that has an hex value of #FFE4C4. /// - public static readonly TPixel Bisque = ColorBuilder.FromRGBA(255, 228, 196, 255); + public static readonly TPixel Bisque = ColorBuilder.FromRgba(255, 228, 196, 255); /// /// Represents a matching the W3C definition that has an hex value of #000000. /// - public static readonly TPixel Black = ColorBuilder.FromRGBA(0, 0, 0, 255); + public static readonly TPixel Black = ColorBuilder.FromRgba(0, 0, 0, 255); /// /// Represents a matching the W3C definition that has an hex value of #FFEBCD. /// - public static readonly TPixel BlanchedAlmond = ColorBuilder.FromRGBA(255, 235, 205, 255); + public static readonly TPixel BlanchedAlmond = ColorBuilder.FromRgba(255, 235, 205, 255); /// /// Represents a matching the W3C definition that has an hex value of #0000FF. /// - public static readonly TPixel Blue = ColorBuilder.FromRGBA(0, 0, 255, 255); + public static readonly TPixel Blue = ColorBuilder.FromRgba(0, 0, 255, 255); /// /// Represents a matching the W3C definition that has an hex value of #8A2BE2. /// - public static readonly TPixel BlueViolet = ColorBuilder.FromRGBA(138, 43, 226, 255); + public static readonly TPixel BlueViolet = ColorBuilder.FromRgba(138, 43, 226, 255); /// /// Represents a matching the W3C definition that has an hex value of #A52A2A. /// - public static readonly TPixel Brown = ColorBuilder.FromRGBA(165, 42, 42, 255); + public static readonly TPixel Brown = ColorBuilder.FromRgba(165, 42, 42, 255); /// /// Represents a matching the W3C definition that has an hex value of #DEB887. /// - public static readonly TPixel BurlyWood = ColorBuilder.FromRGBA(222, 184, 135, 255); + public static readonly TPixel BurlyWood = ColorBuilder.FromRgba(222, 184, 135, 255); /// /// Represents a matching the W3C definition that has an hex value of #5F9EA0. /// - public static readonly TPixel CadetBlue = ColorBuilder.FromRGBA(95, 158, 160, 255); + public static readonly TPixel CadetBlue = ColorBuilder.FromRgba(95, 158, 160, 255); /// /// Represents a matching the W3C definition that has an hex value of #7FFF00. /// - public static readonly TPixel Chartreuse = ColorBuilder.FromRGBA(127, 255, 0, 255); + public static readonly TPixel Chartreuse = ColorBuilder.FromRgba(127, 255, 0, 255); /// /// Represents a matching the W3C definition that has an hex value of #D2691E. /// - public static readonly TPixel Chocolate = ColorBuilder.FromRGBA(210, 105, 30, 255); + public static readonly TPixel Chocolate = ColorBuilder.FromRgba(210, 105, 30, 255); /// /// Represents a matching the W3C definition that has an hex value of #FF7F50. /// - public static readonly TPixel Coral = ColorBuilder.FromRGBA(255, 127, 80, 255); + public static readonly TPixel Coral = ColorBuilder.FromRgba(255, 127, 80, 255); /// /// Represents a matching the W3C definition that has an hex value of #6495ED. /// - public static readonly TPixel CornflowerBlue = ColorBuilder.FromRGBA(100, 149, 237, 255); + public static readonly TPixel CornflowerBlue = ColorBuilder.FromRgba(100, 149, 237, 255); /// /// Represents a matching the W3C definition that has an hex value of #FFF8DC. /// - public static readonly TPixel Cornsilk = ColorBuilder.FromRGBA(255, 248, 220, 255); + public static readonly TPixel Cornsilk = ColorBuilder.FromRgba(255, 248, 220, 255); /// /// Represents a matching the W3C definition that has an hex value of #DC143C. /// - public static readonly TPixel Crimson = ColorBuilder.FromRGBA(220, 20, 60, 255); + public static readonly TPixel Crimson = ColorBuilder.FromRgba(220, 20, 60, 255); /// /// Represents a matching the W3C definition that has an hex value of #00FFFF. /// - public static readonly TPixel Cyan = ColorBuilder.FromRGBA(0, 255, 255, 255); + public static readonly TPixel Cyan = ColorBuilder.FromRgba(0, 255, 255, 255); /// /// Represents a matching the W3C definition that has an hex value of #00008B. /// - public static readonly TPixel DarkBlue = ColorBuilder.FromRGBA(0, 0, 139, 255); + public static readonly TPixel DarkBlue = ColorBuilder.FromRgba(0, 0, 139, 255); /// /// Represents a matching the W3C definition that has an hex value of #008B8B. /// - public static readonly TPixel DarkCyan = ColorBuilder.FromRGBA(0, 139, 139, 255); + public static readonly TPixel DarkCyan = ColorBuilder.FromRgba(0, 139, 139, 255); /// /// Represents a matching the W3C definition that has an hex value of #B8860B. /// - public static readonly TPixel DarkGoldenrod = ColorBuilder.FromRGBA(184, 134, 11, 255); + public static readonly TPixel DarkGoldenrod = ColorBuilder.FromRgba(184, 134, 11, 255); /// /// Represents a matching the W3C definition that has an hex value of #A9A9A9. /// - public static readonly TPixel DarkGray = ColorBuilder.FromRGBA(169, 169, 169, 255); + public static readonly TPixel DarkGray = ColorBuilder.FromRgba(169, 169, 169, 255); /// /// Represents a matching the W3C definition that has an hex value of #006400. /// - public static readonly TPixel DarkGreen = ColorBuilder.FromRGBA(0, 100, 0, 255); + public static readonly TPixel DarkGreen = ColorBuilder.FromRgba(0, 100, 0, 255); /// /// Represents a matching the W3C definition that has an hex value of #BDB76B. /// - public static readonly TPixel DarkKhaki = ColorBuilder.FromRGBA(189, 183, 107, 255); + public static readonly TPixel DarkKhaki = ColorBuilder.FromRgba(189, 183, 107, 255); /// /// Represents a matching the W3C definition that has an hex value of #8B008B. /// - public static readonly TPixel DarkMagenta = ColorBuilder.FromRGBA(139, 0, 139, 255); + public static readonly TPixel DarkMagenta = ColorBuilder.FromRgba(139, 0, 139, 255); /// /// Represents a matching the W3C definition that has an hex value of #556B2F. /// - public static readonly TPixel DarkOliveGreen = ColorBuilder.FromRGBA(85, 107, 47, 255); + public static readonly TPixel DarkOliveGreen = ColorBuilder.FromRgba(85, 107, 47, 255); /// /// Represents a matching the W3C definition that has an hex value of #FF8C00. /// - public static readonly TPixel DarkOrange = ColorBuilder.FromRGBA(255, 140, 0, 255); + public static readonly TPixel DarkOrange = ColorBuilder.FromRgba(255, 140, 0, 255); /// /// Represents a matching the W3C definition that has an hex value of #9932CC. /// - public static readonly TPixel DarkOrchid = ColorBuilder.FromRGBA(153, 50, 204, 255); + public static readonly TPixel DarkOrchid = ColorBuilder.FromRgba(153, 50, 204, 255); /// /// Represents a matching the W3C definition that has an hex value of #8B0000. /// - public static readonly TPixel DarkRed = ColorBuilder.FromRGBA(139, 0, 0, 255); + public static readonly TPixel DarkRed = ColorBuilder.FromRgba(139, 0, 0, 255); /// /// Represents a matching the W3C definition that has an hex value of #E9967A. /// - public static readonly TPixel DarkSalmon = ColorBuilder.FromRGBA(233, 150, 122, 255); + public static readonly TPixel DarkSalmon = ColorBuilder.FromRgba(233, 150, 122, 255); /// /// Represents a matching the W3C definition that has an hex value of #8FBC8B. /// - public static readonly TPixel DarkSeaGreen = ColorBuilder.FromRGBA(143, 188, 139, 255); + public static readonly TPixel DarkSeaGreen = ColorBuilder.FromRgba(143, 188, 139, 255); /// /// Represents a matching the W3C definition that has an hex value of #483D8B. /// - public static readonly TPixel DarkSlateBlue = ColorBuilder.FromRGBA(72, 61, 139, 255); + public static readonly TPixel DarkSlateBlue = ColorBuilder.FromRgba(72, 61, 139, 255); /// /// Represents a matching the W3C definition that has an hex value of #2F4F4F. /// - public static readonly TPixel DarkSlateGray = ColorBuilder.FromRGBA(47, 79, 79, 255); + public static readonly TPixel DarkSlateGray = ColorBuilder.FromRgba(47, 79, 79, 255); /// /// Represents a matching the W3C definition that has an hex value of #00CED1. /// - public static readonly TPixel DarkTurquoise = ColorBuilder.FromRGBA(0, 206, 209, 255); + public static readonly TPixel DarkTurquoise = ColorBuilder.FromRgba(0, 206, 209, 255); /// /// Represents a matching the W3C definition that has an hex value of #9400D3. /// - public static readonly TPixel DarkViolet = ColorBuilder.FromRGBA(148, 0, 211, 255); + public static readonly TPixel DarkViolet = ColorBuilder.FromRgba(148, 0, 211, 255); /// /// Represents a matching the W3C definition that has an hex value of #FF1493. /// - public static readonly TPixel DeepPink = ColorBuilder.FromRGBA(255, 20, 147, 255); + public static readonly TPixel DeepPink = ColorBuilder.FromRgba(255, 20, 147, 255); /// /// Represents a matching the W3C definition that has an hex value of #00BFFF. /// - public static readonly TPixel DeepSkyBlue = ColorBuilder.FromRGBA(0, 191, 255, 255); + public static readonly TPixel DeepSkyBlue = ColorBuilder.FromRgba(0, 191, 255, 255); /// /// Represents a matching the W3C definition that has an hex value of #696969. /// - public static readonly TPixel DimGray = ColorBuilder.FromRGBA(105, 105, 105, 255); + public static readonly TPixel DimGray = ColorBuilder.FromRgba(105, 105, 105, 255); /// /// Represents a matching the W3C definition that has an hex value of #1E90FF. /// - public static readonly TPixel DodgerBlue = ColorBuilder.FromRGBA(30, 144, 255, 255); + public static readonly TPixel DodgerBlue = ColorBuilder.FromRgba(30, 144, 255, 255); /// /// Represents a matching the W3C definition that has an hex value of #B22222. /// - public static readonly TPixel Firebrick = ColorBuilder.FromRGBA(178, 34, 34, 255); + public static readonly TPixel Firebrick = ColorBuilder.FromRgba(178, 34, 34, 255); /// /// Represents a matching the W3C definition that has an hex value of #FFFAF0. /// - public static readonly TPixel FloralWhite = ColorBuilder.FromRGBA(255, 250, 240, 255); + public static readonly TPixel FloralWhite = ColorBuilder.FromRgba(255, 250, 240, 255); /// /// Represents a matching the W3C definition that has an hex value of #228B22. /// - public static readonly TPixel ForestGreen = ColorBuilder.FromRGBA(34, 139, 34, 255); + public static readonly TPixel ForestGreen = ColorBuilder.FromRgba(34, 139, 34, 255); /// /// Represents a matching the W3C definition that has an hex value of #FF00FF. /// - public static readonly TPixel Fuchsia = ColorBuilder.FromRGBA(255, 0, 255, 255); + public static readonly TPixel Fuchsia = ColorBuilder.FromRgba(255, 0, 255, 255); /// /// Represents a matching the W3C definition that has an hex value of #DCDCDC. /// - public static readonly TPixel Gainsboro = ColorBuilder.FromRGBA(220, 220, 220, 255); + public static readonly TPixel Gainsboro = ColorBuilder.FromRgba(220, 220, 220, 255); /// /// Represents a matching the W3C definition that has an hex value of #F8F8FF. /// - public static readonly TPixel GhostWhite = ColorBuilder.FromRGBA(248, 248, 255, 255); + public static readonly TPixel GhostWhite = ColorBuilder.FromRgba(248, 248, 255, 255); /// /// Represents a matching the W3C definition that has an hex value of #FFD700. /// - public static readonly TPixel Gold = ColorBuilder.FromRGBA(255, 215, 0, 255); + public static readonly TPixel Gold = ColorBuilder.FromRgba(255, 215, 0, 255); /// /// Represents a matching the W3C definition that has an hex value of #DAA520. /// - public static readonly TPixel Goldenrod = ColorBuilder.FromRGBA(218, 165, 32, 255); + public static readonly TPixel Goldenrod = ColorBuilder.FromRgba(218, 165, 32, 255); /// /// Represents a matching the W3C definition that has an hex value of #808080. /// - public static readonly TPixel Gray = ColorBuilder.FromRGBA(128, 128, 128, 255); + public static readonly TPixel Gray = ColorBuilder.FromRgba(128, 128, 128, 255); /// /// Represents a matching the W3C definition that has an hex value of #008000. /// - public static readonly TPixel Green = ColorBuilder.FromRGBA(0, 128, 0, 255); + public static readonly TPixel Green = ColorBuilder.FromRgba(0, 128, 0, 255); /// /// Represents a matching the W3C definition that has an hex value of #ADFF2F. /// - public static readonly TPixel GreenYellow = ColorBuilder.FromRGBA(173, 255, 47, 255); + public static readonly TPixel GreenYellow = ColorBuilder.FromRgba(173, 255, 47, 255); /// /// Represents a matching the W3C definition that has an hex value of #F0FFF0. /// - public static readonly TPixel Honeydew = ColorBuilder.FromRGBA(240, 255, 240, 255); + public static readonly TPixel Honeydew = ColorBuilder.FromRgba(240, 255, 240, 255); /// /// Represents a matching the W3C definition that has an hex value of #FF69B4. /// - public static readonly TPixel HotPink = ColorBuilder.FromRGBA(255, 105, 180, 255); + public static readonly TPixel HotPink = ColorBuilder.FromRgba(255, 105, 180, 255); /// /// Represents a matching the W3C definition that has an hex value of #CD5C5C. /// - public static readonly TPixel IndianRed = ColorBuilder.FromRGBA(205, 92, 92, 255); + public static readonly TPixel IndianRed = ColorBuilder.FromRgba(205, 92, 92, 255); /// /// Represents a matching the W3C definition that has an hex value of #4B0082. /// - public static readonly TPixel Indigo = ColorBuilder.FromRGBA(75, 0, 130, 255); + public static readonly TPixel Indigo = ColorBuilder.FromRgba(75, 0, 130, 255); /// /// Represents a matching the W3C definition that has an hex value of #FFFFF0. /// - public static readonly TPixel Ivory = ColorBuilder.FromRGBA(255, 255, 240, 255); + public static readonly TPixel Ivory = ColorBuilder.FromRgba(255, 255, 240, 255); /// /// Represents a matching the W3C definition that has an hex value of #F0E68C. /// - public static readonly TPixel Khaki = ColorBuilder.FromRGBA(240, 230, 140, 255); + public static readonly TPixel Khaki = ColorBuilder.FromRgba(240, 230, 140, 255); /// /// Represents a matching the W3C definition that has an hex value of #E6E6FA. /// - public static readonly TPixel Lavender = ColorBuilder.FromRGBA(230, 230, 250, 255); + public static readonly TPixel Lavender = ColorBuilder.FromRgba(230, 230, 250, 255); /// /// Represents a matching the W3C definition that has an hex value of #FFF0F5. /// - public static readonly TPixel LavenderBlush = ColorBuilder.FromRGBA(255, 240, 245, 255); + public static readonly TPixel LavenderBlush = ColorBuilder.FromRgba(255, 240, 245, 255); /// /// Represents a matching the W3C definition that has an hex value of #7CFC00. /// - public static readonly TPixel LawnGreen = ColorBuilder.FromRGBA(124, 252, 0, 255); + public static readonly TPixel LawnGreen = ColorBuilder.FromRgba(124, 252, 0, 255); /// /// Represents a matching the W3C definition that has an hex value of #FFFACD. /// - public static readonly TPixel LemonChiffon = ColorBuilder.FromRGBA(255, 250, 205, 255); + public static readonly TPixel LemonChiffon = ColorBuilder.FromRgba(255, 250, 205, 255); /// /// Represents a matching the W3C definition that has an hex value of #ADD8E6. /// - public static readonly TPixel LightBlue = ColorBuilder.FromRGBA(173, 216, 230, 255); + public static readonly TPixel LightBlue = ColorBuilder.FromRgba(173, 216, 230, 255); /// /// Represents a matching the W3C definition that has an hex value of #F08080. /// - public static readonly TPixel LightCoral = ColorBuilder.FromRGBA(240, 128, 128, 255); + public static readonly TPixel LightCoral = ColorBuilder.FromRgba(240, 128, 128, 255); /// /// Represents a matching the W3C definition that has an hex value of #E0FFFF. /// - public static readonly TPixel LightCyan = ColorBuilder.FromRGBA(224, 255, 255, 255); + public static readonly TPixel LightCyan = ColorBuilder.FromRgba(224, 255, 255, 255); /// /// Represents a matching the W3C definition that has an hex value of #FAFAD2. /// - public static readonly TPixel LightGoldenrodYellow = ColorBuilder.FromRGBA(250, 250, 210, 255); + public static readonly TPixel LightGoldenrodYellow = ColorBuilder.FromRgba(250, 250, 210, 255); /// /// Represents a matching the W3C definition that has an hex value of #D3D3D3. /// - public static readonly TPixel LightGray = ColorBuilder.FromRGBA(211, 211, 211, 255); + public static readonly TPixel LightGray = ColorBuilder.FromRgba(211, 211, 211, 255); /// /// Represents a matching the W3C definition that has an hex value of #90EE90. /// - public static readonly TPixel LightGreen = ColorBuilder.FromRGBA(144, 238, 144, 255); + public static readonly TPixel LightGreen = ColorBuilder.FromRgba(144, 238, 144, 255); /// /// Represents a matching the W3C definition that has an hex value of #FFB6C1. /// - public static readonly TPixel LightPink = ColorBuilder.FromRGBA(255, 182, 193, 255); + public static readonly TPixel LightPink = ColorBuilder.FromRgba(255, 182, 193, 255); /// /// Represents a matching the W3C definition that has an hex value of #FFA07A. /// - public static readonly TPixel LightSalmon = ColorBuilder.FromRGBA(255, 160, 122, 255); + public static readonly TPixel LightSalmon = ColorBuilder.FromRgba(255, 160, 122, 255); /// /// Represents a matching the W3C definition that has an hex value of #20B2AA. /// - public static readonly TPixel LightSeaGreen = ColorBuilder.FromRGBA(32, 178, 170, 255); + public static readonly TPixel LightSeaGreen = ColorBuilder.FromRgba(32, 178, 170, 255); /// /// Represents a matching the W3C definition that has an hex value of #87CEFA. /// - public static readonly TPixel LightSkyBlue = ColorBuilder.FromRGBA(135, 206, 250, 255); + public static readonly TPixel LightSkyBlue = ColorBuilder.FromRgba(135, 206, 250, 255); /// /// Represents a matching the W3C definition that has an hex value of #778899. /// - public static readonly TPixel LightSlateGray = ColorBuilder.FromRGBA(119, 136, 153, 255); + public static readonly TPixel LightSlateGray = ColorBuilder.FromRgba(119, 136, 153, 255); /// /// Represents a matching the W3C definition that has an hex value of #B0C4DE. /// - public static readonly TPixel LightSteelBlue = ColorBuilder.FromRGBA(176, 196, 222, 255); + public static readonly TPixel LightSteelBlue = ColorBuilder.FromRgba(176, 196, 222, 255); /// /// Represents a matching the W3C definition that has an hex value of #FFFFE0. /// - public static readonly TPixel LightYellow = ColorBuilder.FromRGBA(255, 255, 224, 255); + public static readonly TPixel LightYellow = ColorBuilder.FromRgba(255, 255, 224, 255); /// /// Represents a matching the W3C definition that has an hex value of #00FF00. /// - public static readonly TPixel Lime = ColorBuilder.FromRGBA(0, 255, 0, 255); + public static readonly TPixel Lime = ColorBuilder.FromRgba(0, 255, 0, 255); /// /// Represents a matching the W3C definition that has an hex value of #32CD32. /// - public static readonly TPixel LimeGreen = ColorBuilder.FromRGBA(50, 205, 50, 255); + public static readonly TPixel LimeGreen = ColorBuilder.FromRgba(50, 205, 50, 255); /// /// Represents a matching the W3C definition that has an hex value of #FAF0E6. /// - public static readonly TPixel Linen = ColorBuilder.FromRGBA(250, 240, 230, 255); + public static readonly TPixel Linen = ColorBuilder.FromRgba(250, 240, 230, 255); /// /// Represents a matching the W3C definition that has an hex value of #FF00FF. /// - public static readonly TPixel Magenta = ColorBuilder.FromRGBA(255, 0, 255, 255); + public static readonly TPixel Magenta = ColorBuilder.FromRgba(255, 0, 255, 255); /// /// Represents a matching the W3C definition that has an hex value of #800000. /// - public static readonly TPixel Maroon = ColorBuilder.FromRGBA(128, 0, 0, 255); + public static readonly TPixel Maroon = ColorBuilder.FromRgba(128, 0, 0, 255); /// /// Represents a matching the W3C definition that has an hex value of #66CDAA. /// - public static readonly TPixel MediumAquamarine = ColorBuilder.FromRGBA(102, 205, 170, 255); + public static readonly TPixel MediumAquamarine = ColorBuilder.FromRgba(102, 205, 170, 255); /// /// Represents a matching the W3C definition that has an hex value of #0000CD. /// - public static readonly TPixel MediumBlue = ColorBuilder.FromRGBA(0, 0, 205, 255); + public static readonly TPixel MediumBlue = ColorBuilder.FromRgba(0, 0, 205, 255); /// /// Represents a matching the W3C definition that has an hex value of #BA55D3. /// - public static readonly TPixel MediumOrchid = ColorBuilder.FromRGBA(186, 85, 211, 255); + public static readonly TPixel MediumOrchid = ColorBuilder.FromRgba(186, 85, 211, 255); /// /// Represents a matching the W3C definition that has an hex value of #9370DB. /// - public static readonly TPixel MediumPurple = ColorBuilder.FromRGBA(147, 112, 219, 255); + public static readonly TPixel MediumPurple = ColorBuilder.FromRgba(147, 112, 219, 255); /// /// Represents a matching the W3C definition that has an hex value of #3CB371. /// - public static readonly TPixel MediumSeaGreen = ColorBuilder.FromRGBA(60, 179, 113, 255); + public static readonly TPixel MediumSeaGreen = ColorBuilder.FromRgba(60, 179, 113, 255); /// /// Represents a matching the W3C definition that has an hex value of #7B68EE. /// - public static readonly TPixel MediumSlateBlue = ColorBuilder.FromRGBA(123, 104, 238, 255); + public static readonly TPixel MediumSlateBlue = ColorBuilder.FromRgba(123, 104, 238, 255); /// /// Represents a matching the W3C definition that has an hex value of #00FA9A. /// - public static readonly TPixel MediumSpringGreen = ColorBuilder.FromRGBA(0, 250, 154, 255); + public static readonly TPixel MediumSpringGreen = ColorBuilder.FromRgba(0, 250, 154, 255); /// /// Represents a matching the W3C definition that has an hex value of #48D1CC. /// - public static readonly TPixel MediumTurquoise = ColorBuilder.FromRGBA(72, 209, 204, 255); + public static readonly TPixel MediumTurquoise = ColorBuilder.FromRgba(72, 209, 204, 255); /// /// Represents a matching the W3C definition that has an hex value of #C71585. /// - public static readonly TPixel MediumVioletRed = ColorBuilder.FromRGBA(199, 21, 133, 255); + public static readonly TPixel MediumVioletRed = ColorBuilder.FromRgba(199, 21, 133, 255); /// /// Represents a matching the W3C definition that has an hex value of #191970. /// - public static readonly TPixel MidnightBlue = ColorBuilder.FromRGBA(25, 25, 112, 255); + public static readonly TPixel MidnightBlue = ColorBuilder.FromRgba(25, 25, 112, 255); /// /// Represents a matching the W3C definition that has an hex value of #F5FFFA. /// - public static readonly TPixel MintCream = ColorBuilder.FromRGBA(245, 255, 250, 255); + public static readonly TPixel MintCream = ColorBuilder.FromRgba(245, 255, 250, 255); /// /// Represents a matching the W3C definition that has an hex value of #FFE4E1. /// - public static readonly TPixel MistyRose = ColorBuilder.FromRGBA(255, 228, 225, 255); + public static readonly TPixel MistyRose = ColorBuilder.FromRgba(255, 228, 225, 255); /// /// Represents a matching the W3C definition that has an hex value of #FFE4B5. /// - public static readonly TPixel Moccasin = ColorBuilder.FromRGBA(255, 228, 181, 255); + public static readonly TPixel Moccasin = ColorBuilder.FromRgba(255, 228, 181, 255); /// /// Represents a matching the W3C definition that has an hex value of #FFDEAD. /// - public static readonly TPixel NavajoWhite = ColorBuilder.FromRGBA(255, 222, 173, 255); + public static readonly TPixel NavajoWhite = ColorBuilder.FromRgba(255, 222, 173, 255); /// /// Represents a matching the W3C definition that has an hex value of #000080. /// - public static readonly TPixel Navy = ColorBuilder.FromRGBA(0, 0, 128, 255); + public static readonly TPixel Navy = ColorBuilder.FromRgba(0, 0, 128, 255); /// /// Represents a matching the W3C definition that has an hex value of #FDF5E6. /// - public static readonly TPixel OldLace = ColorBuilder.FromRGBA(253, 245, 230, 255); + public static readonly TPixel OldLace = ColorBuilder.FromRgba(253, 245, 230, 255); /// /// Represents a matching the W3C definition that has an hex value of #808000. /// - public static readonly TPixel Olive = ColorBuilder.FromRGBA(128, 128, 0, 255); + public static readonly TPixel Olive = ColorBuilder.FromRgba(128, 128, 0, 255); /// /// Represents a matching the W3C definition that has an hex value of #6B8E23. /// - public static readonly TPixel OliveDrab = ColorBuilder.FromRGBA(107, 142, 35, 255); + public static readonly TPixel OliveDrab = ColorBuilder.FromRgba(107, 142, 35, 255); /// /// Represents a matching the W3C definition that has an hex value of #FFA500. /// - public static readonly TPixel Orange = ColorBuilder.FromRGBA(255, 165, 0, 255); + public static readonly TPixel Orange = ColorBuilder.FromRgba(255, 165, 0, 255); /// /// Represents a matching the W3C definition that has an hex value of #FF4500. /// - public static readonly TPixel OrangeRed = ColorBuilder.FromRGBA(255, 69, 0, 255); + public static readonly TPixel OrangeRed = ColorBuilder.FromRgba(255, 69, 0, 255); /// /// Represents a matching the W3C definition that has an hex value of #DA70D6. /// - public static readonly TPixel Orchid = ColorBuilder.FromRGBA(218, 112, 214, 255); + public static readonly TPixel Orchid = ColorBuilder.FromRgba(218, 112, 214, 255); /// /// Represents a matching the W3C definition that has an hex value of #EEE8AA. /// - public static readonly TPixel PaleGoldenrod = ColorBuilder.FromRGBA(238, 232, 170, 255); + public static readonly TPixel PaleGoldenrod = ColorBuilder.FromRgba(238, 232, 170, 255); /// /// Represents a matching the W3C definition that has an hex value of #98FB98. /// - public static readonly TPixel PaleGreen = ColorBuilder.FromRGBA(152, 251, 152, 255); + public static readonly TPixel PaleGreen = ColorBuilder.FromRgba(152, 251, 152, 255); /// /// Represents a matching the W3C definition that has an hex value of #AFEEEE. /// - public static readonly TPixel PaleTurquoise = ColorBuilder.FromRGBA(175, 238, 238, 255); + public static readonly TPixel PaleTurquoise = ColorBuilder.FromRgba(175, 238, 238, 255); /// /// Represents a matching the W3C definition that has an hex value of #DB7093. /// - public static readonly TPixel PaleVioletRed = ColorBuilder.FromRGBA(219, 112, 147, 255); + public static readonly TPixel PaleVioletRed = ColorBuilder.FromRgba(219, 112, 147, 255); /// /// Represents a matching the W3C definition that has an hex value of #FFEFD5. /// - public static readonly TPixel PapayaWhip = ColorBuilder.FromRGBA(255, 239, 213, 255); + public static readonly TPixel PapayaWhip = ColorBuilder.FromRgba(255, 239, 213, 255); /// /// Represents a matching the W3C definition that has an hex value of #FFDAB9. /// - public static readonly TPixel PeachPuff = ColorBuilder.FromRGBA(255, 218, 185, 255); + public static readonly TPixel PeachPuff = ColorBuilder.FromRgba(255, 218, 185, 255); /// /// Represents a matching the W3C definition that has an hex value of #CD853F. /// - public static readonly TPixel Peru = ColorBuilder.FromRGBA(205, 133, 63, 255); + public static readonly TPixel Peru = ColorBuilder.FromRgba(205, 133, 63, 255); /// /// Represents a matching the W3C definition that has an hex value of #FFC0CB. /// - public static readonly TPixel Pink = ColorBuilder.FromRGBA(255, 192, 203, 255); + public static readonly TPixel Pink = ColorBuilder.FromRgba(255, 192, 203, 255); /// /// Represents a matching the W3C definition that has an hex value of #DDA0DD. /// - public static readonly TPixel Plum = ColorBuilder.FromRGBA(221, 160, 221, 255); + public static readonly TPixel Plum = ColorBuilder.FromRgba(221, 160, 221, 255); /// /// Represents a matching the W3C definition that has an hex value of #B0E0E6. /// - public static readonly TPixel PowderBlue = ColorBuilder.FromRGBA(176, 224, 230, 255); + public static readonly TPixel PowderBlue = ColorBuilder.FromRgba(176, 224, 230, 255); /// /// Represents a matching the W3C definition that has an hex value of #800080. /// - public static readonly TPixel Purple = ColorBuilder.FromRGBA(128, 0, 128, 255); + public static readonly TPixel Purple = ColorBuilder.FromRgba(128, 0, 128, 255); /// /// Represents a matching the W3C definition that has an hex value of #663399. /// - public static readonly TPixel RebeccaPurple = ColorBuilder.FromRGBA(102, 51, 153, 255); + public static readonly TPixel RebeccaPurple = ColorBuilder.FromRgba(102, 51, 153, 255); /// /// Represents a matching the W3C definition that has an hex value of #FF0000. /// - public static readonly TPixel Red = ColorBuilder.FromRGBA(255, 0, 0, 255); + public static readonly TPixel Red = ColorBuilder.FromRgba(255, 0, 0, 255); /// /// Represents a matching the W3C definition that has an hex value of #BC8F8F. /// - public static readonly TPixel RosyBrown = ColorBuilder.FromRGBA(188, 143, 143, 255); + public static readonly TPixel RosyBrown = ColorBuilder.FromRgba(188, 143, 143, 255); /// /// Represents a matching the W3C definition that has an hex value of #4169E1. /// - public static readonly TPixel RoyalBlue = ColorBuilder.FromRGBA(65, 105, 225, 255); + public static readonly TPixel RoyalBlue = ColorBuilder.FromRgba(65, 105, 225, 255); /// /// Represents a matching the W3C definition that has an hex value of #8B4513. /// - public static readonly TPixel SaddleBrown = ColorBuilder.FromRGBA(139, 69, 19, 255); + public static readonly TPixel SaddleBrown = ColorBuilder.FromRgba(139, 69, 19, 255); /// /// Represents a matching the W3C definition that has an hex value of #FA8072. /// - public static readonly TPixel Salmon = ColorBuilder.FromRGBA(250, 128, 114, 255); + public static readonly TPixel Salmon = ColorBuilder.FromRgba(250, 128, 114, 255); /// /// Represents a matching the W3C definition that has an hex value of #F4A460. /// - public static readonly TPixel SandyBrown = ColorBuilder.FromRGBA(244, 164, 96, 255); + public static readonly TPixel SandyBrown = ColorBuilder.FromRgba(244, 164, 96, 255); /// /// Represents a matching the W3C definition that has an hex value of #2E8B57. /// - public static readonly TPixel SeaGreen = ColorBuilder.FromRGBA(46, 139, 87, 255); + public static readonly TPixel SeaGreen = ColorBuilder.FromRgba(46, 139, 87, 255); /// /// Represents a matching the W3C definition that has an hex value of #FFF5EE. /// - public static readonly TPixel SeaShell = ColorBuilder.FromRGBA(255, 245, 238, 255); + public static readonly TPixel SeaShell = ColorBuilder.FromRgba(255, 245, 238, 255); /// /// Represents a matching the W3C definition that has an hex value of #A0522D. /// - public static readonly TPixel Sienna = ColorBuilder.FromRGBA(160, 82, 45, 255); + public static readonly TPixel Sienna = ColorBuilder.FromRgba(160, 82, 45, 255); /// /// Represents a matching the W3C definition that has an hex value of #C0C0C0. /// - public static readonly TPixel Silver = ColorBuilder.FromRGBA(192, 192, 192, 255); + public static readonly TPixel Silver = ColorBuilder.FromRgba(192, 192, 192, 255); /// /// Represents a matching the W3C definition that has an hex value of #87CEEB. /// - public static readonly TPixel SkyBlue = ColorBuilder.FromRGBA(135, 206, 235, 255); + public static readonly TPixel SkyBlue = ColorBuilder.FromRgba(135, 206, 235, 255); /// /// Represents a matching the W3C definition that has an hex value of #6A5ACD. /// - public static readonly TPixel SlateBlue = ColorBuilder.FromRGBA(106, 90, 205, 255); + public static readonly TPixel SlateBlue = ColorBuilder.FromRgba(106, 90, 205, 255); /// /// Represents a matching the W3C definition that has an hex value of #708090. /// - public static readonly TPixel SlateGray = ColorBuilder.FromRGBA(112, 128, 144, 255); + public static readonly TPixel SlateGray = ColorBuilder.FromRgba(112, 128, 144, 255); /// /// Represents a matching the W3C definition that has an hex value of #FFFAFA. /// - public static readonly TPixel Snow = ColorBuilder.FromRGBA(255, 250, 250, 255); + public static readonly TPixel Snow = ColorBuilder.FromRgba(255, 250, 250, 255); /// /// Represents a matching the W3C definition that has an hex value of #00FF7F. /// - public static readonly TPixel SpringGreen = ColorBuilder.FromRGBA(0, 255, 127, 255); + public static readonly TPixel SpringGreen = ColorBuilder.FromRgba(0, 255, 127, 255); /// /// Represents a matching the W3C definition that has an hex value of #4682B4. /// - public static readonly TPixel SteelBlue = ColorBuilder.FromRGBA(70, 130, 180, 255); + public static readonly TPixel SteelBlue = ColorBuilder.FromRgba(70, 130, 180, 255); /// /// Represents a matching the W3C definition that has an hex value of #D2B48C. /// - public static readonly TPixel Tan = ColorBuilder.FromRGBA(210, 180, 140, 255); + public static readonly TPixel Tan = ColorBuilder.FromRgba(210, 180, 140, 255); /// /// Represents a matching the W3C definition that has an hex value of #008080. /// - public static readonly TPixel Teal = ColorBuilder.FromRGBA(0, 128, 128, 255); + public static readonly TPixel Teal = ColorBuilder.FromRgba(0, 128, 128, 255); /// /// Represents a matching the W3C definition that has an hex value of #D8BFD8. /// - public static readonly TPixel Thistle = ColorBuilder.FromRGBA(216, 191, 216, 255); + public static readonly TPixel Thistle = ColorBuilder.FromRgba(216, 191, 216, 255); /// /// Represents a matching the W3C definition that has an hex value of #FF6347. /// - public static readonly TPixel Tomato = ColorBuilder.FromRGBA(255, 99, 71, 255); + public static readonly TPixel Tomato = ColorBuilder.FromRgba(255, 99, 71, 255); /// /// Represents a matching the W3C definition that has an hex value of #FFFFFF. /// - public static readonly TPixel Transparent = ColorBuilder.FromRGBA(255, 255, 255, 0); + public static readonly TPixel Transparent = ColorBuilder.FromRgba(255, 255, 255, 0); /// /// Represents a matching the W3C definition that has an hex value of #40E0D0. /// - public static readonly TPixel Turquoise = ColorBuilder.FromRGBA(64, 224, 208, 255); + public static readonly TPixel Turquoise = ColorBuilder.FromRgba(64, 224, 208, 255); /// /// Represents a matching the W3C definition that has an hex value of #EE82EE. /// - public static readonly TPixel Violet = ColorBuilder.FromRGBA(238, 130, 238, 255); + public static readonly TPixel Violet = ColorBuilder.FromRgba(238, 130, 238, 255); /// /// Represents a matching the W3C definition that has an hex value of #F5DEB3. /// - public static readonly TPixel Wheat = ColorBuilder.FromRGBA(245, 222, 179, 255); + public static readonly TPixel Wheat = ColorBuilder.FromRgba(245, 222, 179, 255); /// /// Represents a matching the W3C definition that has an hex value of #FFFFFF. /// - public static readonly TPixel White = ColorBuilder.FromRGBA(255, 255, 255, 255); + public static readonly TPixel White = ColorBuilder.FromRgba(255, 255, 255, 255); /// /// Represents a matching the W3C definition that has an hex value of #F5F5F5. /// - public static readonly TPixel WhiteSmoke = ColorBuilder.FromRGBA(245, 245, 245, 255); + public static readonly TPixel WhiteSmoke = ColorBuilder.FromRgba(245, 245, 245, 255); /// /// Represents a matching the W3C definition that has an hex value of #FFFF00. /// - public static readonly TPixel Yellow = ColorBuilder.FromRGBA(255, 255, 0, 255); + public static readonly TPixel Yellow = ColorBuilder.FromRgba(255, 255, 0, 255); /// /// Represents a matching the W3C definition that has an hex value of #9ACD32. /// - public static readonly TPixel YellowGreen = ColorBuilder.FromRGBA(154, 205, 50, 255); + public static readonly TPixel YellowGreen = ColorBuilder.FromRgba(154, 205, 50, 255); /// /// Gets a collection of web safe, colors as defined in the CSS Color Module Level 4. diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Argb32.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Argb32.cs index 075df01cd2..8981c87458 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Argb32.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Argb32.cs @@ -142,6 +142,22 @@ public uint PackedValue set => this.Argb = value; } + /// + /// Converts an to . + /// + /// The . + /// The . + [MethodImpl(InliningOptions.ShortMethod)] + public static implicit operator Color(Argb32 source) => new Color(source); + + /// + /// Converts a to . + /// + /// The . + /// The . + [MethodImpl(InliningOptions.ShortMethod)] + public static implicit operator Argb32(Color color) => color.ToArgb32(); + /// /// Compares two objects for equality. /// diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Bgr24.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Bgr24.cs index 3ba6436a0b..a0b059dfce 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Bgr24.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Bgr24.cs @@ -50,6 +50,22 @@ public Bgr24(byte r, byte g, byte b) this.B = b; } + /// + /// Converts an to . + /// + /// The . + /// The . + [MethodImpl(InliningOptions.ShortMethod)] + public static implicit operator Color(Bgr24 source) => new Color(source); + + /// + /// Converts a to . + /// + /// The . + /// The . + [MethodImpl(InliningOptions.ShortMethod)] + public static implicit operator Bgr24(Color color) => color.ToBgr24(); + /// /// Compares two objects for equality. /// diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Bgra32.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Bgra32.cs index 758be8043c..ea7a961885 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Bgra32.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Bgra32.cs @@ -98,6 +98,22 @@ public uint PackedValue set => this.Bgra = value; } + /// + /// Converts an to . + /// + /// The . + /// The . + [MethodImpl(InliningOptions.ShortMethod)] + public static implicit operator Color(Bgra32 source) => new Color(source); + + /// + /// Converts a to . + /// + /// The . + /// The . + [MethodImpl(InliningOptions.ShortMethod)] + public static implicit operator Bgra32(Color color) => color.ToBgra32(); + /// /// Compares two objects for equality. /// diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Rgb24.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Rgb24.cs index 1255f66d15..469dbbad4a 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Rgb24.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Rgb24.cs @@ -53,6 +53,22 @@ public Rgb24(byte r, byte g, byte b) this.B = b; } + /// + /// Converts an to . + /// + /// The . + /// The . + [MethodImpl(InliningOptions.ShortMethod)] + public static implicit operator Color(Rgb24 source) => new Color(source); + + /// + /// Converts a to . + /// + /// The . + /// The . + [MethodImpl(InliningOptions.ShortMethod)] + public static implicit operator Rgb24(Color color) => color.ToRgb24(); + /// /// Allows the implicit conversion of an instance of to a /// . diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.cs index 7367c44634..c58d17ef42 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.cs @@ -169,6 +169,22 @@ public uint PackedValue set => this.Rgba = value; } + /// + /// Converts an to . + /// + /// The . + /// The . + [MethodImpl(InliningOptions.ShortMethod)] + public static implicit operator Color(Rgba32 source) => new Color(source); + + /// + /// Converts a to . + /// + /// The . + /// The . + [MethodImpl(InliningOptions.ShortMethod)] + public static implicit operator Rgba32(Color color) => color.ToRgba32(); + /// /// Allows the implicit conversion of an instance of to a /// . diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Rgba64.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba64.cs index 87d1b235bf..978d9b0156 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Rgba64.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba64.cs @@ -46,6 +46,7 @@ public partial struct Rgba64 : IPixel, IPackedVector /// The green component. /// The blue component. /// The alpha component. + [MethodImpl(InliningOptions.ShortMethod)] public Rgba64(ushort r, ushort g, ushort b, ushort a) { this.R = r; @@ -55,7 +56,86 @@ public Rgba64(ushort r, ushort g, ushort b, ushort a) } /// - /// Gets or sets the RGB components of this struct as + /// Initializes a new instance of the struct. + /// + /// A structure of 4 bytes in RGBA byte order. + [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); + } + + /// + /// Initializes a new instance of the struct. + /// + /// A structure of 4 bytes in BGRA byte order. + [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); + } + + /// + /// Initializes a new instance of the struct. + /// + /// A structure of 4 bytes in ARGB byte order. + [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); + } + + /// + /// Initializes a new instance of the struct. + /// + /// A structure of 3 bytes in RGB byte order. + [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; + } + + /// + /// Initializes a new instance of the struct. + /// + /// A structure of 3 bytes in BGR byte order. + [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; + } + + /// + /// Initializes a new instance of the struct. + /// + /// The . + [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); + } + + /// + /// Gets or sets the RGB components of this struct as . /// public Rgb48 Rgb { @@ -76,6 +156,22 @@ public ulong PackedValue set => Unsafe.As(ref this) = value; } + /// + /// Converts an to . + /// + /// The . + /// The . + [MethodImpl(InliningOptions.ShortMethod)] + public static implicit operator Color(Rgba64 source) => new Color(source); + + /// + /// Converts a to . + /// + /// The . + /// The . + [MethodImpl(InliningOptions.ShortMethod)] + public static implicit operator Rgba64(Color color) => color.ToPixel(); + /// /// Compares two objects for equality. /// @@ -221,6 +317,74 @@ public void FromRgb48(Rgb48 source) [MethodImpl(InliningOptions.ShortMethod)] public void FromRgba64(Rgba64 source) => this = source; + /// + /// Convert to . + /// + /// The . + [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); + } + + /// + /// Convert to . + /// + /// The . + [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); + } + + /// + /// Convert to . + /// + /// The . + [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); + } + + /// + /// Convert to . + /// + /// The . + [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); + } + + /// + /// Convert to . + /// + /// The . + [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); + } + /// public override bool Equals(object obj) => obj is Rgba64 rgba64 && this.Equals(rgba64); diff --git a/src/ImageSharp/Primitives/ValueSize.cs b/src/ImageSharp/Primitives/ValueSize.cs index 44bee50309..577e9187a6 100644 --- a/src/ImageSharp/Primitives/ValueSize.cs +++ b/src/ImageSharp/Primitives/ValueSize.cs @@ -7,7 +7,7 @@ namespace SixLabors.ImageSharp.Primitives { /// - /// Represents a value in relation to a value on the image + /// Represents a value in relation to a value on the image. /// internal readonly struct ValueSize : IEquatable { diff --git a/src/ImageSharp/Processing/DitherExtensions.cs b/src/ImageSharp/Processing/DitherExtensions.cs deleted file mode 100644 index aeb975d1c1..0000000000 --- a/src/ImageSharp/Processing/DitherExtensions.cs +++ /dev/null @@ -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 -{ - /// - /// Defines dithering extensions to apply on an - /// using Mutate/Clone. - /// - public static class DitherExtensions - { - /// - /// Dithers the image reducing it to a web-safe palette using Bayer4x4 ordered dithering. - /// - /// The pixel format. - /// The image this method extends. - /// The to allow chaining of operations. - public static IImageProcessingContext Dither(this IImageProcessingContext source) - where TPixel : struct, IPixel - => Dither(source, KnownDitherers.BayerDither4x4); - - /// - /// Dithers the image reducing it to a web-safe palette using ordered dithering. - /// - /// The pixel format. - /// The image this method extends. - /// The ordered ditherer. - /// The to allow chaining of operations. - public static IImageProcessingContext Dither(this IImageProcessingContext source, IOrderedDither dither) - where TPixel : struct, IPixel - => source.ApplyProcessor(new OrderedDitherPaletteProcessor(dither)); - - /// - /// Dithers the image reducing it to the given palette using ordered dithering. - /// - /// The pixel format. - /// The image this method extends. - /// The ordered ditherer. - /// The palette to select substitute colors from. - /// The to allow chaining of operations. - public static IImageProcessingContext Dither(this IImageProcessingContext source, IOrderedDither dither, TPixel[] palette) - where TPixel : struct, IPixel - => source.ApplyProcessor(new OrderedDitherPaletteProcessor(dither, palette)); - - /// - /// Dithers the image reducing it to a web-safe palette using ordered dithering. - /// - /// The pixel format. - /// The image this method extends. - /// The ordered ditherer. - /// - /// The structure that specifies the portion of the image object to alter. - /// - /// The to allow chaining of operations. - public static IImageProcessingContext Dither(this IImageProcessingContext source, IOrderedDither dither, Rectangle rectangle) - where TPixel : struct, IPixel - => source.ApplyProcessor(new OrderedDitherPaletteProcessor(dither), rectangle); - - /// - /// Dithers the image reducing it to the given palette using ordered dithering. - /// - /// The pixel format. - /// The image this method extends. - /// The ordered ditherer. - /// The palette to select substitute colors from. - /// - /// The structure that specifies the portion of the image object to alter. - /// - /// The to allow chaining of operations. - public static IImageProcessingContext Dither(this IImageProcessingContext source, IOrderedDither dither, TPixel[] palette, Rectangle rectangle) - where TPixel : struct, IPixel - => source.ApplyProcessor(new OrderedDitherPaletteProcessor(dither, palette), rectangle); - } -} \ No newline at end of file diff --git a/src/ImageSharp/Processing/AutoOrientExtensions.cs b/src/ImageSharp/Processing/Extensions/AutoOrientExtensions.cs similarity index 100% rename from src/ImageSharp/Processing/AutoOrientExtensions.cs rename to src/ImageSharp/Processing/Extensions/AutoOrientExtensions.cs diff --git a/src/ImageSharp/Processing/BackgroundColorExtensions.cs b/src/ImageSharp/Processing/Extensions/BackgroundColorExtensions.cs similarity index 53% rename from src/ImageSharp/Processing/BackgroundColorExtensions.cs rename to src/ImageSharp/Processing/Extensions/BackgroundColorExtensions.cs index 3b794e3351..dd1cc1ed24 100644 --- a/src/ImageSharp/Processing/BackgroundColorExtensions.cs +++ b/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 @@ public static class BackgroundColorExtensions /// /// Replaces the background color of image with the given one. /// - /// The pixel format. /// The image this method extends. /// The color to set as the background. - /// The . - public static IImageProcessingContext BackgroundColor(this IImageProcessingContext source, TPixel color) - where TPixel : struct, IPixel - => BackgroundColor(source, GraphicsOptions.Default, color); + /// The to allow chaining of operations. + public static IImageProcessingContext BackgroundColor(this IImageProcessingContext source, Color color) => + BackgroundColor(source, GraphicsOptions.Default, color); /// /// Replaces the background color of image with the given one. /// - /// The pixel format. /// The image this method extends. /// The color to set as the background. /// /// The structure that specifies the portion of the image object to alter. /// - /// The . - public static IImageProcessingContext BackgroundColor(this IImageProcessingContext source, TPixel color, Rectangle rectangle) - where TPixel : struct, IPixel - => BackgroundColor(source, GraphicsOptions.Default, color, rectangle); + /// The to allow chaining of operations. + public static IImageProcessingContext BackgroundColor( + this IImageProcessingContext source, + Color color, + Rectangle rectangle) => + BackgroundColor(source, GraphicsOptions.Default, color, rectangle); /// /// Replaces the background color of image with the given one. /// - /// The pixel format. /// The image this method extends. /// The options effecting pixel blending. /// The color to set as the background. - /// The . - public static IImageProcessingContext BackgroundColor(this IImageProcessingContext source, GraphicsOptions options, TPixel color) - where TPixel : struct, IPixel - => source.ApplyProcessor(new BackgroundColorProcessor(color, options)); + /// The to allow chaining of operations. + public static IImageProcessingContext BackgroundColor( + this IImageProcessingContext source, + GraphicsOptions options, + Color color) => + source.ApplyProcessor(new BackgroundColorProcessor(color, options)); /// /// Replaces the background color of image with the given one. /// - /// The pixel format. /// The image this method extends. /// The options effecting pixel blending. /// The color to set as the background. /// /// The structure that specifies the portion of the image object to alter. /// - /// The . - public static IImageProcessingContext BackgroundColor(this IImageProcessingContext source, GraphicsOptions options, TPixel color, Rectangle rectangle) - where TPixel : struct, IPixel - => source.ApplyProcessor(new BackgroundColorProcessor(color, options), rectangle); + /// The to allow chaining of operations. + public static IImageProcessingContext BackgroundColor( + this IImageProcessingContext source, + GraphicsOptions options, + Color color, + Rectangle rectangle) => + source.ApplyProcessor(new BackgroundColorProcessor(color, options), rectangle); } -} +} \ No newline at end of file diff --git a/src/ImageSharp/Processing/BinaryDiffuseExtensions.cs b/src/ImageSharp/Processing/Extensions/BinaryDiffuseExtensions.cs similarity index 64% rename from src/ImageSharp/Processing/BinaryDiffuseExtensions.cs rename to src/ImageSharp/Processing/Extensions/BinaryDiffuseExtensions.cs index 487b64e1c4..7976daf25e 100644 --- a/src/ImageSharp/Processing/BinaryDiffuseExtensions.cs +++ b/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 @@ namespace SixLabors.ImageSharp.Processing { /// - /// Defines extension methods to apply binary diffusion on an + /// Defines extension methods to apply binary diffusion on an /// using Mutate/Clone. /// public static class BinaryDiffuseExtensions @@ -17,19 +16,19 @@ public static class BinaryDiffuseExtensions /// /// Dithers the image reducing it to two colors using error diffusion. /// - /// The pixel format. /// The image this method extends. /// The diffusion algorithm to apply. /// The threshold to apply binarization of the image. Must be between 0 and 1. /// The to allow chaining of operations. - public static IImageProcessingContext BinaryDiffuse(this IImageProcessingContext source, IErrorDiffuser diffuser, float threshold) - where TPixel : struct, IPixel - => source.ApplyProcessor(new BinaryErrorDiffusionProcessor(diffuser, threshold)); + public static IImageProcessingContext BinaryDiffuse( + this IImageProcessingContext source, + IErrorDiffuser diffuser, + float threshold) => + source.ApplyProcessor(new BinaryErrorDiffusionProcessor(diffuser, threshold)); /// /// Dithers the image reducing it to two colors using error diffusion. /// - /// The pixel format. /// The image this method extends. /// The diffusion algorithm to apply. /// The threshold to apply binarization of the image. Must be between 0 and 1. @@ -37,28 +36,33 @@ public static IImageProcessingContext BinaryDiffuse(this IImageP /// The structure that specifies the portion of the image object to alter. /// /// The to allow chaining of operations. - public static IImageProcessingContext BinaryDiffuse(this IImageProcessingContext source, IErrorDiffuser diffuser, float threshold, Rectangle rectangle) - where TPixel : struct, IPixel - => source.ApplyProcessor(new BinaryErrorDiffusionProcessor(diffuser, threshold), rectangle); + public static IImageProcessingContext BinaryDiffuse( + this IImageProcessingContext source, + IErrorDiffuser diffuser, + float threshold, + Rectangle rectangle) => + source.ApplyProcessor(new BinaryErrorDiffusionProcessor(diffuser, threshold), rectangle); /// /// Dithers the image reducing it to two colors using error diffusion. /// - /// The pixel format. /// The image this method extends. /// The diffusion algorithm to apply. /// The threshold to apply binarization of the image. Must be between 0 and 1. /// The color to use for pixels that are above the threshold. /// The color to use for pixels that are below the threshold /// The to allow chaining of operations. - public static IImageProcessingContext BinaryDiffuse(this IImageProcessingContext source, IErrorDiffuser diffuser, float threshold, TPixel upperColor, TPixel lowerColor) - where TPixel : struct, IPixel - => source.ApplyProcessor(new BinaryErrorDiffusionProcessor(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)); /// /// Dithers the image reducing it to two colors using error diffusion. /// - /// The pixel format. /// The image this method extends. /// The diffusion algorithm to apply. /// The threshold to apply binarization of the image. Must be between 0 and 1. @@ -68,8 +72,15 @@ public static IImageProcessingContext BinaryDiffuse(this IImageP /// The structure that specifies the portion of the image object to alter. /// /// The to allow chaining of operations. - public static IImageProcessingContext BinaryDiffuse(this IImageProcessingContext source, IErrorDiffuser diffuser, float threshold, TPixel upperColor, TPixel lowerColor, Rectangle rectangle) - where TPixel : struct, IPixel - => source.ApplyProcessor(new BinaryErrorDiffusionProcessor(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); } } \ No newline at end of file diff --git a/src/ImageSharp/Processing/BinaryDitherExtensions.cs b/src/ImageSharp/Processing/Extensions/BinaryDitherExtensions.cs similarity index 62% rename from src/ImageSharp/Processing/BinaryDitherExtensions.cs rename to src/ImageSharp/Processing/Extensions/BinaryDitherExtensions.cs index d8843dafac..b1e3d562ed 100644 --- a/src/ImageSharp/Processing/BinaryDitherExtensions.cs +++ b/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 @@ namespace SixLabors.ImageSharp.Processing { /// - /// Defines extensions to apply binary dithering on an + /// Defines extensions to apply binary dithering on an /// using Mutate/Clone. /// public static class BinaryDitherExtensions @@ -17,45 +16,46 @@ public static class BinaryDitherExtensions /// /// Dithers the image reducing it to two colors using ordered dithering. /// - /// The pixel format. /// The image this method extends. /// The ordered ditherer. /// The to allow chaining of operations. - public static IImageProcessingContext BinaryDither(this IImageProcessingContext source, IOrderedDither dither) - where TPixel : struct, IPixel - => source.ApplyProcessor(new BinaryOrderedDitherProcessor(dither)); + public static IImageProcessingContext + BinaryDither(this IImageProcessingContext source, IOrderedDither dither) => + source.ApplyProcessor(new BinaryOrderedDitherProcessor(dither)); /// /// Dithers the image reducing it to two colors using ordered dithering. /// - /// The pixel format. /// The image this method extends. /// The ordered ditherer. /// The color to use for pixels that are above the threshold. /// The color to use for pixels that are below the threshold /// The to allow chaining of operations. - public static IImageProcessingContext BinaryDither(this IImageProcessingContext source, IOrderedDither dither, TPixel upperColor, TPixel lowerColor) - where TPixel : struct, IPixel - => source.ApplyProcessor(new BinaryOrderedDitherProcessor(dither, upperColor, lowerColor)); + public static IImageProcessingContext BinaryDither( + this IImageProcessingContext source, + IOrderedDither dither, + Color upperColor, + Color lowerColor) => + source.ApplyProcessor(new BinaryOrderedDitherProcessor(dither, upperColor, lowerColor)); /// /// Dithers the image reducing it to two colors using ordered dithering. /// - /// The pixel format. /// The image this method extends. /// The ordered ditherer. /// /// The structure that specifies the portion of the image object to alter. /// /// The to allow chaining of operations. - public static IImageProcessingContext BinaryDither(this IImageProcessingContext source, IOrderedDither dither, Rectangle rectangle) - where TPixel : struct, IPixel - => source.ApplyProcessor(new BinaryOrderedDitherProcessor(dither), rectangle); + public static IImageProcessingContext BinaryDither( + this IImageProcessingContext source, + IOrderedDither dither, + Rectangle rectangle) => + source.ApplyProcessor(new BinaryOrderedDitherProcessor(dither), rectangle); /// /// Dithers the image reducing it to two colors using ordered dithering. /// - /// The pixel format. /// The image this method extends. /// The ordered ditherer. /// The color to use for pixels that are above the threshold. @@ -64,8 +64,12 @@ public static IImageProcessingContext BinaryDither(this IImagePr /// The structure that specifies the portion of the image object to alter. /// /// The to allow chaining of operations. - public static IImageProcessingContext BinaryDither(this IImageProcessingContext source, IOrderedDither dither, TPixel upperColor, TPixel lowerColor, Rectangle rectangle) - where TPixel : struct, IPixel - => source.ApplyProcessor(new BinaryOrderedDitherProcessor(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); } } \ No newline at end of file diff --git a/src/ImageSharp/Processing/BinaryThresholdExtensions.cs b/src/ImageSharp/Processing/Extensions/BinaryThresholdExtensions.cs similarity index 54% rename from src/ImageSharp/Processing/BinaryThresholdExtensions.cs rename to src/ImageSharp/Processing/Extensions/BinaryThresholdExtensions.cs index aecb784848..35aa681e33 100644 --- a/src/ImageSharp/Processing/BinaryThresholdExtensions.cs +++ b/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 { /// - /// Defines extension methods to apply binary thresholding on an + /// Defines extension methods to apply binary thresholding on an /// using Mutate/Clone. /// public static class BinaryThresholdExtensions @@ -16,45 +15,45 @@ public static class BinaryThresholdExtensions /// /// Applies binarization to the image splitting the pixels at the given threshold. /// - /// The pixel format. /// The image this method extends. /// The threshold to apply binarization of the image. Must be between 0 and 1. - /// The to allow chaining of operations. - public static IImageProcessingContext BinaryThreshold(this IImageProcessingContext source, float threshold) - where TPixel : struct, IPixel - => source.ApplyProcessor(new BinaryThresholdProcessor(threshold)); + /// The to allow chaining of operations. + public static IImageProcessingContext BinaryThreshold(this IImageProcessingContext source, float threshold) => + source.ApplyProcessor(new BinaryThresholdProcessor(threshold)); /// /// Applies binarization to the image splitting the pixels at the given threshold. /// - /// The pixel format. /// The image this method extends. /// The threshold to apply binarization of the image. Must be between 0 and 1. /// /// The structure that specifies the portion of the image object to alter. /// - /// The to allow chaining of operations. - public static IImageProcessingContext BinaryThreshold(this IImageProcessingContext source, float threshold, Rectangle rectangle) - where TPixel : struct, IPixel - => source.ApplyProcessor(new BinaryThresholdProcessor(threshold), rectangle); + /// The to allow chaining of operations. + public static IImageProcessingContext BinaryThreshold( + this IImageProcessingContext source, + float threshold, + Rectangle rectangle) => + source.ApplyProcessor(new BinaryThresholdProcessor(threshold), rectangle); /// /// Applies binarization to the image splitting the pixels at the given threshold. /// - /// The pixel format. /// The image this method extends. /// The threshold to apply binarization of the image. Must be between 0 and 1. /// The color to use for pixels that are above the threshold. /// The color to use for pixels that are below the threshold - /// The to allow chaining of operations. - public static IImageProcessingContext BinaryThreshold(this IImageProcessingContext source, float threshold, TPixel upperColor, TPixel lowerColor) - where TPixel : struct, IPixel - => source.ApplyProcessor(new BinaryThresholdProcessor(threshold, upperColor, lowerColor)); + /// The to allow chaining of operations. + public static IImageProcessingContext BinaryThreshold( + this IImageProcessingContext source, + float threshold, + Color upperColor, + Color lowerColor) => + source.ApplyProcessor(new BinaryThresholdProcessor(threshold, upperColor, lowerColor)); /// /// Applies binarization to the image splitting the pixels at the given threshold. /// - /// The pixel format. /// The image this method extends. /// The threshold to apply binarization of the image. Must be between 0 and 1. /// The color to use for pixels that are above the threshold. @@ -62,9 +61,13 @@ public static IImageProcessingContext BinaryThreshold(this IImag /// /// The structure that specifies the portion of the image object to alter. /// - /// The to allow chaining of operations. - public static IImageProcessingContext BinaryThreshold(this IImageProcessingContext source, float threshold, TPixel upperColor, TPixel lowerColor, Rectangle rectangle) - where TPixel : struct, IPixel - => source.ApplyProcessor(new BinaryThresholdProcessor(threshold, upperColor, lowerColor), rectangle); + /// The to allow chaining of operations. + public static IImageProcessingContext BinaryThreshold( + this IImageProcessingContext source, + float threshold, + Color upperColor, + Color lowerColor, + Rectangle rectangle) => + source.ApplyProcessor(new BinaryThresholdProcessor(threshold, upperColor, lowerColor), rectangle); } -} +} \ No newline at end of file diff --git a/src/ImageSharp/Processing/BlackWhiteExtensions.cs b/src/ImageSharp/Processing/Extensions/BlackWhiteExtensions.cs similarity index 100% rename from src/ImageSharp/Processing/BlackWhiteExtensions.cs rename to src/ImageSharp/Processing/Extensions/BlackWhiteExtensions.cs diff --git a/src/ImageSharp/Processing/BoxBlurExtensions.cs b/src/ImageSharp/Processing/Extensions/BoxBlurExtensions.cs similarity index 100% rename from src/ImageSharp/Processing/BoxBlurExtensions.cs rename to src/ImageSharp/Processing/Extensions/BoxBlurExtensions.cs diff --git a/src/ImageSharp/Processing/BrightnessExtensions.cs b/src/ImageSharp/Processing/Extensions/BrightnessExtensions.cs similarity index 100% rename from src/ImageSharp/Processing/BrightnessExtensions.cs rename to src/ImageSharp/Processing/Extensions/BrightnessExtensions.cs diff --git a/src/ImageSharp/Processing/ColorBlindnessExtensions.cs b/src/ImageSharp/Processing/Extensions/ColorBlindnessExtensions.cs similarity index 100% rename from src/ImageSharp/Processing/ColorBlindnessExtensions.cs rename to src/ImageSharp/Processing/Extensions/ColorBlindnessExtensions.cs diff --git a/src/ImageSharp/Processing/ContrastExtensions.cs b/src/ImageSharp/Processing/Extensions/ContrastExtensions.cs similarity index 100% rename from src/ImageSharp/Processing/ContrastExtensions.cs rename to src/ImageSharp/Processing/Extensions/ContrastExtensions.cs diff --git a/src/ImageSharp/Processing/CropExtensions.cs b/src/ImageSharp/Processing/Extensions/CropExtensions.cs similarity index 100% rename from src/ImageSharp/Processing/CropExtensions.cs rename to src/ImageSharp/Processing/Extensions/CropExtensions.cs diff --git a/src/ImageSharp/Processing/DetectEdgesExtensions.cs b/src/ImageSharp/Processing/Extensions/DetectEdgesExtensions.cs similarity index 100% rename from src/ImageSharp/Processing/DetectEdgesExtensions.cs rename to src/ImageSharp/Processing/Extensions/DetectEdgesExtensions.cs diff --git a/src/ImageSharp/Processing/DiffuseExtensions.cs b/src/ImageSharp/Processing/Extensions/DiffuseExtensions.cs similarity index 50% rename from src/ImageSharp/Processing/DiffuseExtensions.cs rename to src/ImageSharp/Processing/Extensions/DiffuseExtensions.cs index 4668363e9a..f9a1bdde0e 100644 --- a/src/ImageSharp/Processing/DiffuseExtensions.cs +++ b/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 { /// - /// Defines extension methods to apply diffusion to an + /// Defines extension methods to apply diffusion to an /// using Mutate/Clone. /// public static class DiffuseExtensions @@ -16,68 +17,68 @@ public static class DiffuseExtensions /// /// Dithers the image reducing it to a web-safe palette using error diffusion. /// - /// The pixel format. /// The image this method extends. - /// The to allow chaining of operations. - public static IImageProcessingContext Diffuse(this IImageProcessingContext source) - where TPixel : struct, IPixel - => Diffuse(source, KnownDiffusers.FloydSteinberg, .5F); + /// The to allow chaining of operations. + public static IImageProcessingContext Diffuse(this IImageProcessingContext source) => + Diffuse(source, KnownDiffusers.FloydSteinberg, .5F); /// /// Dithers the image reducing it to a web-safe palette using error diffusion. /// - /// The pixel format. /// The image this method extends. /// The threshold to apply binarization of the image. Must be between 0 and 1. - /// The to allow chaining of operations. - public static IImageProcessingContext Diffuse(this IImageProcessingContext source, float threshold) - where TPixel : struct, IPixel - => Diffuse(source, KnownDiffusers.FloydSteinberg, threshold); + /// The to allow chaining of operations. + public static IImageProcessingContext Diffuse(this IImageProcessingContext source, float threshold) => + Diffuse(source, KnownDiffusers.FloydSteinberg, threshold); /// /// Dithers the image reducing it to a web-safe palette using error diffusion. /// - /// The pixel format. /// The image this method extends. /// The diffusion algorithm to apply. /// The threshold to apply binarization of the image. Must be between 0 and 1. - /// The to allow chaining of operations. - public static IImageProcessingContext Diffuse(this IImageProcessingContext source, IErrorDiffuser diffuser, float threshold) - where TPixel : struct, IPixel - => source.ApplyProcessor(new ErrorDiffusionPaletteProcessor(diffuser, threshold)); + /// The to allow chaining of operations. + public static IImageProcessingContext Diffuse( + this IImageProcessingContext source, + IErrorDiffuser diffuser, + float threshold) => + source.ApplyProcessor(new ErrorDiffusionPaletteProcessor(diffuser, threshold)); /// /// Dithers the image reducing it to a web-safe palette using error diffusion. /// - /// The pixel format. /// The image this method extends. /// The diffusion algorithm to apply. /// The threshold to apply binarization of the image. Must be between 0 and 1. /// /// The structure that specifies the portion of the image object to alter. /// - /// The to allow chaining of operations. - public static IImageProcessingContext Diffuse(this IImageProcessingContext source, IErrorDiffuser diffuser, float threshold, Rectangle rectangle) - where TPixel : struct, IPixel - => source.ApplyProcessor(new ErrorDiffusionPaletteProcessor(diffuser, threshold), rectangle); + /// The to allow chaining of operations. + public static IImageProcessingContext Diffuse( + this IImageProcessingContext source, + IErrorDiffuser diffuser, + float threshold, + Rectangle rectangle) => + source.ApplyProcessor(new ErrorDiffusionPaletteProcessor(diffuser, threshold), rectangle); /// /// Dithers the image reducing it to the given palette using error diffusion. /// - /// The pixel format. /// The image this method extends. /// The diffusion algorithm to apply. /// The threshold to apply binarization of the image. Must be between 0 and 1. /// The palette to select substitute colors from. - /// The to allow chaining of operations. - public static IImageProcessingContext Diffuse(this IImageProcessingContext source, IErrorDiffuser diffuser, float threshold, TPixel[] palette) - where TPixel : struct, IPixel - => source.ApplyProcessor(new ErrorDiffusionPaletteProcessor(diffuser, threshold, palette)); + /// The to allow chaining of operations. + public static IImageProcessingContext Diffuse( + this IImageProcessingContext source, + IErrorDiffuser diffuser, + float threshold, + ReadOnlyMemory palette) => + source.ApplyProcessor(new ErrorDiffusionPaletteProcessor(diffuser, threshold, palette)); /// /// Dithers the image reducing it to the given palette using error diffusion. /// - /// The pixel format. /// The image this method extends. /// The diffusion algorithm to apply. /// The threshold to apply binarization of the image. Must be between 0 and 1. @@ -85,9 +86,13 @@ public static IImageProcessingContext Diffuse(this IImageProcess /// /// The structure that specifies the portion of the image object to alter. /// - /// The to allow chaining of operations. - public static IImageProcessingContext Diffuse(this IImageProcessingContext source, IErrorDiffuser diffuser, float threshold, TPixel[] palette, Rectangle rectangle) - where TPixel : struct, IPixel - => source.ApplyProcessor(new ErrorDiffusionPaletteProcessor(diffuser, threshold, palette), rectangle); + /// The to allow chaining of operations. + public static IImageProcessingContext Diffuse( + this IImageProcessingContext source, + IErrorDiffuser diffuser, + float threshold, + ReadOnlyMemory palette, + Rectangle rectangle) => + source.ApplyProcessor(new ErrorDiffusionPaletteProcessor(diffuser, threshold, palette), rectangle); } } \ No newline at end of file diff --git a/src/ImageSharp/Processing/Extensions/DitherExtensions.cs b/src/ImageSharp/Processing/Extensions/DitherExtensions.cs new file mode 100644 index 0000000000..f83a9e9e81 --- /dev/null +++ b/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 +{ + /// + /// Defines dithering extensions to apply on an + /// using Mutate/Clone. + /// + public static class DitherExtensions + { + /// + /// Dithers the image reducing it to a web-safe palette using Bayer4x4 ordered dithering. + /// + /// The image this method extends. + /// The to allow chaining of operations. + public static IImageProcessingContext Dither(this IImageProcessingContext source) => + Dither(source, KnownDitherers.BayerDither4x4); + + /// + /// Dithers the image reducing it to a web-safe palette using ordered dithering. + /// + /// The image this method extends. + /// The ordered ditherer. + /// The to allow chaining of operations. + public static IImageProcessingContext Dither(this IImageProcessingContext source, IOrderedDither dither) => + source.ApplyProcessor(new OrderedDitherPaletteProcessor(dither)); + + /// + /// Dithers the image reducing it to the given palette using ordered dithering. + /// + /// The image this method extends. + /// The ordered ditherer. + /// The palette to select substitute colors from. + /// The to allow chaining of operations. + public static IImageProcessingContext Dither( + this IImageProcessingContext source, + IOrderedDither dither, + ReadOnlyMemory palette) => + source.ApplyProcessor(new OrderedDitherPaletteProcessor(dither, palette)); + + /// + /// Dithers the image reducing it to a web-safe palette using ordered dithering. + /// + /// The image this method extends. + /// The ordered ditherer. + /// + /// The structure that specifies the portion of the image object to alter. + /// + /// The to allow chaining of operations. + public static IImageProcessingContext Dither( + this IImageProcessingContext source, + IOrderedDither dither, + Rectangle rectangle) => + source.ApplyProcessor(new OrderedDitherPaletteProcessor(dither), rectangle); + + /// + /// Dithers the image reducing it to the given palette using ordered dithering. + /// + /// The image this method extends. + /// The ordered ditherer. + /// The palette to select substitute colors from. + /// + /// The structure that specifies the portion of the image object to alter. + /// + /// The to allow chaining of operations. + public static IImageProcessingContext Dither( + this IImageProcessingContext source, + IOrderedDither dither, + ReadOnlyMemory palette, + Rectangle rectangle) => + source.ApplyProcessor(new OrderedDitherPaletteProcessor(dither, palette), rectangle); + } +} \ No newline at end of file diff --git a/src/ImageSharp/Processing/EntropyCropExtensions.cs b/src/ImageSharp/Processing/Extensions/EntropyCropExtensions.cs similarity index 100% rename from src/ImageSharp/Processing/EntropyCropExtensions.cs rename to src/ImageSharp/Processing/Extensions/EntropyCropExtensions.cs diff --git a/src/ImageSharp/Processing/FilterExtensions.cs b/src/ImageSharp/Processing/Extensions/FilterExtensions.cs similarity index 100% rename from src/ImageSharp/Processing/FilterExtensions.cs rename to src/ImageSharp/Processing/Extensions/FilterExtensions.cs diff --git a/src/ImageSharp/Processing/FlipExtensions.cs b/src/ImageSharp/Processing/Extensions/FlipExtensions.cs similarity index 100% rename from src/ImageSharp/Processing/FlipExtensions.cs rename to src/ImageSharp/Processing/Extensions/FlipExtensions.cs diff --git a/src/ImageSharp/Processing/GaussianBlurExtensions.cs b/src/ImageSharp/Processing/Extensions/GaussianBlurExtensions.cs similarity index 100% rename from src/ImageSharp/Processing/GaussianBlurExtensions.cs rename to src/ImageSharp/Processing/Extensions/GaussianBlurExtensions.cs diff --git a/src/ImageSharp/Processing/GaussianSharpenExtensions.cs b/src/ImageSharp/Processing/Extensions/GaussianSharpenExtensions.cs similarity index 100% rename from src/ImageSharp/Processing/GaussianSharpenExtensions.cs rename to src/ImageSharp/Processing/Extensions/GaussianSharpenExtensions.cs diff --git a/src/ImageSharp/Processing/GlowExtensions.cs b/src/ImageSharp/Processing/Extensions/GlowExtensions.cs similarity index 59% rename from src/ImageSharp/Processing/GlowExtensions.cs rename to src/ImageSharp/Processing/Extensions/GlowExtensions.cs index 759fdccbea..39734882b0 100644 --- a/src/ImageSharp/Processing/GlowExtensions.cs +++ b/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 @@ public static class GlowExtensions /// /// Applies a radial glow effect to an image. /// - /// The pixel format. /// The image this method extends. /// The to allow chaining of operations. - public static IImageProcessingContext Glow(this IImageProcessingContext source) - where TPixel : struct, IPixel - => Glow(source, GraphicsOptions.Default); + public static IImageProcessingContext Glow(this IImageProcessingContext source) => + Glow(source, GraphicsOptions.Default); /// /// Applies a radial glow effect to an image. /// - /// The pixel format. /// The image this method extends. /// The color to set as the glow. /// The to allow chaining of operations. - public static IImageProcessingContext Glow(this IImageProcessingContext source, TPixel color) - where TPixel : struct, IPixel + public static IImageProcessingContext Glow(this IImageProcessingContext source, Color color) { return Glow(source, GraphicsOptions.Default, color); } @@ -40,31 +35,26 @@ public static IImageProcessingContext Glow(this IImageProcessing /// /// Applies a radial glow effect to an image. /// - /// The pixel format. /// The image this method extends. /// The the radius. /// The to allow chaining of operations. - public static IImageProcessingContext Glow(this IImageProcessingContext source, float radius) - where TPixel : struct, IPixel - => Glow(source, GraphicsOptions.Default, radius); + public static IImageProcessingContext Glow(this IImageProcessingContext source, float radius) => + Glow(source, GraphicsOptions.Default, radius); /// /// Applies a radial glow effect to an image. /// - /// The pixel format. /// The image this method extends. /// /// The structure that specifies the portion of the image object to alter. /// /// The to allow chaining of operations. - public static IImageProcessingContext Glow(this IImageProcessingContext source, Rectangle rectangle) - where TPixel : struct, IPixel - => source.Glow(GraphicsOptions.Default, rectangle); + public static IImageProcessingContext Glow(this IImageProcessingContext source, Rectangle rectangle) => + source.Glow(GraphicsOptions.Default, rectangle); /// /// Applies a radial glow effect to an image. /// - /// The pixel format. /// The image this method extends. /// The color to set as the glow. /// The the radius. @@ -72,63 +62,66 @@ public static IImageProcessingContext Glow(this IImageProcessing /// The structure that specifies the portion of the image object to alter. /// /// The to allow chaining of operations. - public static IImageProcessingContext Glow(this IImageProcessingContext source, TPixel color, float radius, Rectangle rectangle) - where TPixel : struct, IPixel - => 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); /// /// Applies a radial glow effect to an image. /// - /// The pixel format. /// The image this method extends. /// The options effecting things like blending. /// The to allow chaining of operations. - public static IImageProcessingContext Glow(this IImageProcessingContext source, GraphicsOptions options) - where TPixel : struct, IPixel - => source.Glow(options, NamedColors.Black, ValueSize.PercentageOfWidth(0.5f)); + public static IImageProcessingContext Glow(this IImageProcessingContext source, GraphicsOptions options) => + source.Glow(options, Color.Black, ValueSize.PercentageOfWidth(0.5f)); /// /// Applies a radial glow effect to an image. /// - /// The pixel format. /// The image this method extends. /// The options effecting things like blending. /// The color to set as the glow. /// The to allow chaining of operations. - public static IImageProcessingContext Glow(this IImageProcessingContext source, GraphicsOptions options, TPixel color) - where TPixel : struct, IPixel - => 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)); /// /// Applies a radial glow effect to an image. /// - /// The pixel format. /// The image this method extends. /// The options effecting things like blending. /// The the radius. /// The to allow chaining of operations. - public static IImageProcessingContext Glow(this IImageProcessingContext source, GraphicsOptions options, float radius) - where TPixel : struct, IPixel - => source.Glow(options, NamedColors.Black, ValueSize.Absolute(radius)); + public static IImageProcessingContext Glow( + this IImageProcessingContext source, + GraphicsOptions options, + float radius) => + source.Glow(options, Color.Black, ValueSize.Absolute(radius)); /// /// Applies a radial glow effect to an image. /// - /// The pixel format. /// The image this method extends. /// The options effecting things like blending. /// /// The structure that specifies the portion of the image object to alter. /// /// The to allow chaining of operations. - public static IImageProcessingContext Glow(this IImageProcessingContext source, GraphicsOptions options, Rectangle rectangle) - where TPixel : struct, IPixel - => source.Glow(options, NamedColors.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); /// /// Applies a radial glow effect to an image. /// - /// The pixel format. /// The image this method extends. /// The options effecting things like blending. /// The color to set as the glow. @@ -137,14 +130,17 @@ public static IImageProcessingContext Glow(this IImageProcessing /// The structure that specifies the portion of the image object to alter. /// /// The to allow chaining of operations. - public static IImageProcessingContext Glow(this IImageProcessingContext source, GraphicsOptions options, TPixel color, float radius, Rectangle rectangle) - where TPixel : struct, IPixel - => 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); /// /// Applies a radial glow effect to an image. /// - /// The pixel format. /// The image this method extends. /// The options effecting things like blending. /// The color to set as the glow. @@ -153,21 +149,27 @@ public static IImageProcessingContext Glow(this IImageProcessing /// The structure that specifies the portion of the image object to alter. /// /// The to allow chaining of operations. - private static IImageProcessingContext Glow(this IImageProcessingContext source, GraphicsOptions options, TPixel color, ValueSize radius, Rectangle rectangle) - where TPixel : struct, IPixel - => source.ApplyProcessor(new GlowProcessor(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); /// /// Applies a radial glow effect to an image. /// - /// The pixel format. /// The image this method extends. /// The options effecting things like blending. /// The color to set as the glow. /// The the radius. /// The to allow chaining of operations. - private static IImageProcessingContext Glow(this IImageProcessingContext source, GraphicsOptions options, TPixel color, ValueSize radius) - where TPixel : struct, IPixel - => source.ApplyProcessor(new GlowProcessor(color, radius, options)); + private static IImageProcessingContext Glow( + this IImageProcessingContext source, + GraphicsOptions options, + Color color, + ValueSize radius) => + source.ApplyProcessor(new GlowProcessor(color, radius, options)); } } \ No newline at end of file diff --git a/src/ImageSharp/Processing/GrayscaleExtensions.cs b/src/ImageSharp/Processing/Extensions/GrayscaleExtensions.cs similarity index 100% rename from src/ImageSharp/Processing/GrayscaleExtensions.cs rename to src/ImageSharp/Processing/Extensions/GrayscaleExtensions.cs diff --git a/src/ImageSharp/Processing/HistogramEqualizationExtension.cs b/src/ImageSharp/Processing/Extensions/HistogramEqualizationExtensions.cs similarity index 96% rename from src/ImageSharp/Processing/HistogramEqualizationExtension.cs rename to src/ImageSharp/Processing/Extensions/HistogramEqualizationExtensions.cs index 01c14fc093..72962a3f9f 100644 --- a/src/ImageSharp/Processing/HistogramEqualizationExtension.cs +++ b/src/ImageSharp/Processing/Extensions/HistogramEqualizationExtensions.cs @@ -8,7 +8,7 @@ namespace SixLabors.ImageSharp.Processing /// /// Defines extension that allow the adjustment of the contrast of an image via its histogram. /// - public static class HistogramEqualizationExtension + public static class HistogramEqualizationExtensions { /// /// Equalizes the histogram of an image to increases the contrast. diff --git a/src/ImageSharp/Processing/HueExtensions.cs b/src/ImageSharp/Processing/Extensions/HueExtensions.cs similarity index 100% rename from src/ImageSharp/Processing/HueExtensions.cs rename to src/ImageSharp/Processing/Extensions/HueExtensions.cs diff --git a/src/ImageSharp/Processing/InvertExtensions.cs b/src/ImageSharp/Processing/Extensions/InvertExtensions.cs similarity index 100% rename from src/ImageSharp/Processing/InvertExtensions.cs rename to src/ImageSharp/Processing/Extensions/InvertExtensions.cs diff --git a/src/ImageSharp/Processing/KodachromeExtensions.cs b/src/ImageSharp/Processing/Extensions/KodachromeExtensions.cs similarity index 100% rename from src/ImageSharp/Processing/KodachromeExtensions.cs rename to src/ImageSharp/Processing/Extensions/KodachromeExtensions.cs diff --git a/src/ImageSharp/Processing/LomographExtensions.cs b/src/ImageSharp/Processing/Extensions/LomographExtensions.cs similarity index 100% rename from src/ImageSharp/Processing/LomographExtensions.cs rename to src/ImageSharp/Processing/Extensions/LomographExtensions.cs diff --git a/src/ImageSharp/Processing/OilPaintExtensions.cs b/src/ImageSharp/Processing/Extensions/OilPaintExtensions.cs similarity index 100% rename from src/ImageSharp/Processing/OilPaintExtensions.cs rename to src/ImageSharp/Processing/Extensions/OilPaintExtensions.cs diff --git a/src/ImageSharp/Processing/OpacityExtensions.cs b/src/ImageSharp/Processing/Extensions/OpacityExtensions.cs similarity index 100% rename from src/ImageSharp/Processing/OpacityExtensions.cs rename to src/ImageSharp/Processing/Extensions/OpacityExtensions.cs diff --git a/src/ImageSharp/Processing/PadExtensions.cs b/src/ImageSharp/Processing/Extensions/PadExtensions.cs similarity index 100% rename from src/ImageSharp/Processing/PadExtensions.cs rename to src/ImageSharp/Processing/Extensions/PadExtensions.cs diff --git a/src/ImageSharp/Processing/PixelateExtensions.cs b/src/ImageSharp/Processing/Extensions/PixelateExtensions.cs similarity index 100% rename from src/ImageSharp/Processing/PixelateExtensions.cs rename to src/ImageSharp/Processing/Extensions/PixelateExtensions.cs diff --git a/src/ImageSharp/Processing/PolaroidExtensions.cs b/src/ImageSharp/Processing/Extensions/PolaroidExtensions.cs similarity index 100% rename from src/ImageSharp/Processing/PolaroidExtensions.cs rename to src/ImageSharp/Processing/Extensions/PolaroidExtensions.cs diff --git a/src/ImageSharp/Processing/ProcessingExtensions.cs b/src/ImageSharp/Processing/Extensions/ProcessingExtensions.cs similarity index 100% rename from src/ImageSharp/Processing/ProcessingExtensions.cs rename to src/ImageSharp/Processing/Extensions/ProcessingExtensions.cs diff --git a/src/ImageSharp/Processing/QuantizeExtensions.cs b/src/ImageSharp/Processing/Extensions/QuantizeExtensions.cs similarity index 100% rename from src/ImageSharp/Processing/QuantizeExtensions.cs rename to src/ImageSharp/Processing/Extensions/QuantizeExtensions.cs diff --git a/src/ImageSharp/Processing/ResizeExtensions.cs b/src/ImageSharp/Processing/Extensions/ResizeExtensions.cs similarity index 100% rename from src/ImageSharp/Processing/ResizeExtensions.cs rename to src/ImageSharp/Processing/Extensions/ResizeExtensions.cs diff --git a/src/ImageSharp/Processing/RotateExtensions.cs b/src/ImageSharp/Processing/Extensions/RotateExtensions.cs similarity index 100% rename from src/ImageSharp/Processing/RotateExtensions.cs rename to src/ImageSharp/Processing/Extensions/RotateExtensions.cs diff --git a/src/ImageSharp/Processing/RotateFlipExtensions.cs b/src/ImageSharp/Processing/Extensions/RotateFlipExtensions.cs similarity index 100% rename from src/ImageSharp/Processing/RotateFlipExtensions.cs rename to src/ImageSharp/Processing/Extensions/RotateFlipExtensions.cs diff --git a/src/ImageSharp/Processing/SaturateExtensions.cs b/src/ImageSharp/Processing/Extensions/SaturateExtensions.cs similarity index 100% rename from src/ImageSharp/Processing/SaturateExtensions.cs rename to src/ImageSharp/Processing/Extensions/SaturateExtensions.cs diff --git a/src/ImageSharp/Processing/SepiaExtensions.cs b/src/ImageSharp/Processing/Extensions/SepiaExtensions.cs similarity index 100% rename from src/ImageSharp/Processing/SepiaExtensions.cs rename to src/ImageSharp/Processing/Extensions/SepiaExtensions.cs diff --git a/src/ImageSharp/Processing/SkewExtensions.cs b/src/ImageSharp/Processing/Extensions/SkewExtensions.cs similarity index 100% rename from src/ImageSharp/Processing/SkewExtensions.cs rename to src/ImageSharp/Processing/Extensions/SkewExtensions.cs diff --git a/src/ImageSharp/Processing/TransformExtensions.cs b/src/ImageSharp/Processing/Extensions/TransformExtensions.cs similarity index 100% rename from src/ImageSharp/Processing/TransformExtensions.cs rename to src/ImageSharp/Processing/Extensions/TransformExtensions.cs diff --git a/src/ImageSharp/Processing/VignetteExtensions.cs b/src/ImageSharp/Processing/Extensions/VignetteExtensions.cs similarity index 53% rename from src/ImageSharp/Processing/VignetteExtensions.cs rename to src/ImageSharp/Processing/Extensions/VignetteExtensions.cs index 63cdee3f83..74a59d3e13 100644 --- a/src/ImageSharp/Processing/VignetteExtensions.cs +++ b/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 @@ namespace SixLabors.ImageSharp.Processing { /// - /// Defines extensions that allow the application of a radial glow to an + /// Defines extensions that allow the application of a radial glow to an /// using Mutate/Clone. /// public static class VignetteExtensions @@ -17,53 +16,47 @@ public static class VignetteExtensions /// /// Applies a radial vignette effect to an image. /// - /// The pixel format. /// The image this method extends. /// The to allow chaining of operations. - public static IImageProcessingContext Vignette(this IImageProcessingContext source) - where TPixel : struct, IPixel - => Vignette(source, GraphicsOptions.Default); + public static IImageProcessingContext Vignette(this IImageProcessingContext source) => + Vignette(source, GraphicsOptions.Default); /// /// Applies a radial vignette effect to an image. /// - /// The pixel format. /// The image this method extends. /// The color to set as the vignette. /// The to allow chaining of operations. - public static IImageProcessingContext Vignette(this IImageProcessingContext source, TPixel color) - where TPixel : struct, IPixel - => Vignette(source, GraphicsOptions.Default, color); + public static IImageProcessingContext Vignette(this IImageProcessingContext source, Color color) => + Vignette(source, GraphicsOptions.Default, color); /// /// Applies a radial vignette effect to an image. /// - /// The pixel format. /// The image this method extends. /// The the x-radius. /// The the y-radius. /// The to allow chaining of operations. - public static IImageProcessingContext Vignette(this IImageProcessingContext source, float radiusX, float radiusY) - where TPixel : struct, IPixel - => Vignette(source, GraphicsOptions.Default, radiusX, radiusY); + public static IImageProcessingContext Vignette( + this IImageProcessingContext source, + float radiusX, + float radiusY) => + Vignette(source, GraphicsOptions.Default, radiusX, radiusY); /// /// Applies a radial vignette effect to an image. /// - /// The pixel format. /// The image this method extends. /// /// The structure that specifies the portion of the image object to alter. /// /// The to allow chaining of operations. - public static IImageProcessingContext Vignette(this IImageProcessingContext source, Rectangle rectangle) - where TPixel : struct, IPixel - => Vignette(source, GraphicsOptions.Default, rectangle); + public static IImageProcessingContext Vignette(this IImageProcessingContext source, Rectangle rectangle) => + Vignette(source, GraphicsOptions.Default, rectangle); /// /// Applies a radial vignette effect to an image. /// - /// The pixel format. /// The image this method extends. /// The color to set as the vignette. /// The the x-radius. @@ -72,64 +65,82 @@ public static IImageProcessingContext Vignette(this IImageProces /// The structure that specifies the portion of the image object to alter. /// /// The to allow chaining of operations. - public static IImageProcessingContext Vignette(this IImageProcessingContext source, TPixel color, float radiusX, float radiusY, Rectangle rectangle) - where TPixel : struct, IPixel - => 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); /// /// Applies a radial vignette effect to an image. /// - /// The pixel format. /// The image this method extends. /// The options effecting pixel blending. /// The to allow chaining of operations. - public static IImageProcessingContext Vignette(this IImageProcessingContext source, GraphicsOptions options) - where TPixel : struct, IPixel - => source.VignetteInternal(options, NamedColors.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)); /// /// Applies a radial vignette effect to an image. /// - /// The pixel format. /// The image this method extends. /// The options effecting pixel blending. /// The color to set as the vignette. /// The to allow chaining of operations. - public static IImageProcessingContext Vignette(this IImageProcessingContext source, GraphicsOptions options, TPixel color) - where TPixel : struct, IPixel - => 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)); /// /// Applies a radial vignette effect to an image. /// - /// The pixel format. /// The image this method extends. /// The options effecting pixel blending. /// The the x-radius. /// The the y-radius. /// The to allow chaining of operations. - public static IImageProcessingContext Vignette(this IImageProcessingContext source, GraphicsOptions options, float radiusX, float radiusY) - where TPixel : struct, IPixel - => source.VignetteInternal(options, NamedColors.Black, radiusX, radiusY); + public static IImageProcessingContext Vignette( + this IImageProcessingContext source, + GraphicsOptions options, + float radiusX, + float radiusY) => + source.VignetteInternal(options, Color.Black, radiusX, radiusY); /// /// Applies a radial vignette effect to an image. /// - /// The pixel format. /// The image this method extends. /// The options effecting pixel blending. /// /// The structure that specifies the portion of the image object to alter. /// /// The to allow chaining of operations. - public static IImageProcessingContext Vignette(this IImageProcessingContext source, GraphicsOptions options, Rectangle rectangle) - where TPixel : struct, IPixel - => source.VignetteInternal(options, NamedColors.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); /// /// Applies a radial vignette effect to an image. /// - /// The pixel format. /// The image this method extends. /// The options effecting pixel blending. /// The color to set as the vignette. @@ -139,16 +150,30 @@ public static IImageProcessingContext Vignette(this IImageProces /// The structure that specifies the portion of the image object to alter. /// /// The to allow chaining of operations. - public static IImageProcessingContext Vignette(this IImageProcessingContext source, GraphicsOptions options, TPixel color, float radiusX, float radiusY, Rectangle rectangle) - where TPixel : struct, IPixel - => 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 VignetteInternal(this IImageProcessingContext source, GraphicsOptions options, TPixel color, ValueSize radiusX, ValueSize radiusY, Rectangle rectangle) - where TPixel : struct, IPixel - => source.ApplyProcessor(new VignetteProcessor(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 VignetteInternal(this IImageProcessingContext source, GraphicsOptions options, TPixel color, ValueSize radiusX, ValueSize radiusY) - where TPixel : struct, IPixel - => source.ApplyProcessor(new VignetteProcessor(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)); } } \ No newline at end of file diff --git a/src/ImageSharp/Processing/Processors/Binarization/BinaryErrorDiffusionProcessor.cs b/src/ImageSharp/Processing/Processors/Binarization/BinaryErrorDiffusionProcessor.cs index 32cc2f434b..8129836641 100644 --- a/src/ImageSharp/Processing/Processors/Binarization/BinaryErrorDiffusionProcessor.cs +++ b/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 { /// /// Performs binary threshold filtering against an image using error diffusion. /// - /// The pixel format. - internal class BinaryErrorDiffusionProcessor : ImageProcessor - where TPixel : struct, IPixel + public class BinaryErrorDiffusionProcessor : IImageProcessor { /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// /// The error diffuser public BinaryErrorDiffusionProcessor(IErrorDiffuser diffuser) @@ -26,23 +23,23 @@ public BinaryErrorDiffusionProcessor(IErrorDiffuser diffuser) } /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// /// The error diffuser /// The threshold to split the image. Must be between 0 and 1. public BinaryErrorDiffusionProcessor(IErrorDiffuser diffuser, float threshold) - : this(diffuser, threshold, NamedColors.White, NamedColors.Black) + : this(diffuser, threshold, Color.White, Color.Black) { } /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// /// The error diffuser /// The threshold to split the image. Must be between 0 and 1. /// The color to use for pixels that are above the threshold. /// The color to use for pixels that are below the threshold. - 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 @@ public BinaryErrorDiffusionProcessor(IErrorDiffuser diffuser, float threshold, T /// /// Gets the color to use for pixels that are above the threshold. /// - public TPixel UpperColor { get; } + public Color UpperColor { get; } /// /// Gets the color to use for pixels that fall below the threshold. /// - public TPixel LowerColor { get; } + public Color LowerColor { get; } - /// - protected override void OnFrameApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) + /// + public IImageProcessor CreatePixelSpecificProcessor() + where TPixel : struct, IPixel { - 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 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(this); } } } \ No newline at end of file diff --git a/src/ImageSharp/Processing/Processors/Binarization/BinaryErrorDiffusionProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Binarization/BinaryErrorDiffusionProcessor{TPixel}.cs new file mode 100644 index 0000000000..e3828aeb60 --- /dev/null +++ b/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 +{ + /// + /// Performs binary threshold filtering against an image using error diffusion. + /// + /// The pixel format. + internal class BinaryErrorDiffusionProcessor : ImageProcessor + where TPixel : struct, IPixel + { + private readonly BinaryErrorDiffusionProcessor definition; + + public BinaryErrorDiffusionProcessor(BinaryErrorDiffusionProcessor definition) + { + this.definition = definition; + } + + /// + protected override void OnFrameApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) + { + TPixel upperColor = this.definition.UpperColor.ToPixel(); + TPixel lowerColor = this.definition.LowerColor.ToPixel(); + 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 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); + } + } + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/Processing/Processors/Binarization/BinaryOrderedDitherProcessor.cs b/src/ImageSharp/Processing/Processors/Binarization/BinaryOrderedDitherProcessor.cs index cfdaf107c3..6cf1a95266 100644 --- a/src/ImageSharp/Processing/Processors/Binarization/BinaryOrderedDitherProcessor.cs +++ b/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 { /// - /// Performs binary threshold filtering against an image using ordered dithering. + /// Defines a binary threshold filtering using ordered dithering. /// - /// The pixel format. - internal class BinaryOrderedDitherProcessor : ImageProcessor - where TPixel : struct, IPixel + public class BinaryOrderedDitherProcessor : IImageProcessor { /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// /// The ordered ditherer. public BinaryOrderedDitherProcessor(IOrderedDither dither) - : this(dither, NamedColors.White, NamedColors.Black) + : this(dither, Color.White, Color.Black) { } /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// /// The ordered ditherer. /// The color to use for pixels that are above the threshold. /// The color to use for pixels that are below the threshold. - 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 @@ public BinaryOrderedDitherProcessor(IOrderedDither dither, TPixel upperColor, TP /// /// Gets the color to use for pixels that are above the threshold. /// - public TPixel UpperColor { get; } + public Color UpperColor { get; } /// /// Gets the color to use for pixels that fall below the threshold. /// - public TPixel LowerColor { get; } + public Color LowerColor { get; } - /// - protected override void OnFrameApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) + /// + public IImageProcessor CreatePixelSpecificProcessor() + where TPixel : struct, IPixel { - 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 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(this); } } } \ No newline at end of file diff --git a/src/ImageSharp/Processing/Processors/Binarization/BinaryOrderedDitherProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Binarization/BinaryOrderedDitherProcessor{TPixel}.cs new file mode 100644 index 0000000000..b3d174dfbe --- /dev/null +++ b/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 +{ + /// + /// Performs binary threshold filtering against an image using ordered dithering. + /// + /// The pixel format. + internal class BinaryOrderedDitherProcessor : ImageProcessor + where TPixel : struct, IPixel + { + private readonly BinaryOrderedDitherProcessor definition; + + public BinaryOrderedDitherProcessor(BinaryOrderedDitherProcessor definition) + { + this.definition = definition; + } + + /// + protected override void OnFrameApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) + { + IOrderedDither dither = this.definition.Dither; + TPixel upperColor = this.definition.UpperColor.ToPixel(); + TPixel lowerColor = this.definition.LowerColor.ToPixel(); + + 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 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); + } + } + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/Processing/Processors/Binarization/BinaryThresholdProcessor.cs b/src/ImageSharp/Processing/Processors/Binarization/BinaryThresholdProcessor.cs index 67dcfc7f1b..83701aa8a2 100644 --- a/src/ImageSharp/Processing/Processors/Binarization/BinaryThresholdProcessor.cs +++ b/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 { /// /// Performs simple binary threshold filtering against an image. /// - /// The pixel format. - internal class BinaryThresholdProcessor : ImageProcessor - where TPixel : struct, IPixel + public class BinaryThresholdProcessor : IImageProcessor { /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// /// The threshold to split the image. Must be between 0 and 1. public BinaryThresholdProcessor(float threshold) - : this(threshold, NamedColors.White, NamedColors.Black) + : this(threshold, Color.White, Color.Black) { } /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// /// The threshold to split the image. Must be between 0 and 1. /// The color to use for pixels that are above the threshold. /// The color to use for pixels that are below the threshold. - 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 @@ public BinaryThresholdProcessor(float threshold, TPixel upperColor, TPixel lower public float Threshold { get; } /// - /// 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. /// - public TPixel UpperColor { get; set; } + public Color UpperColor { get; } /// - /// 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. /// - public TPixel LowerColor { get; set; } + public Color LowerColor { get; } - /// - protected override void OnFrameApply( - ImageFrame source, - Rectangle sourceRectangle, - Configuration configuration) + /// + public IImageProcessor CreatePixelSpecificProcessor() + where TPixel : struct, IPixel { - 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 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(this); } } } \ No newline at end of file diff --git a/src/ImageSharp/Processing/Processors/Binarization/BinaryThresholdProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Binarization/BinaryThresholdProcessor{TPixel}.cs new file mode 100644 index 0000000000..0d90d3647d --- /dev/null +++ b/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 +{ + /// + /// Performs simple binary threshold filtering against an image. + /// + /// The pixel format. + internal class BinaryThresholdProcessor : ImageProcessor + where TPixel : struct, IPixel + { + private readonly BinaryThresholdProcessor definition; + + public BinaryThresholdProcessor(BinaryThresholdProcessor definition) + { + this.definition = definition; + } + + /// + protected override void OnFrameApply( + ImageFrame source, + Rectangle sourceRectangle, + Configuration configuration) + { + byte threshold = (byte)MathF.Round(this.definition.Threshold * 255F); + TPixel upper = this.definition.UpperColor.ToPixel(); + TPixel lower = this.definition.LowerColor.ToPixel(); + + 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 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; + } + } + }); + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/Processing/Processors/Convolution/EdgeDetector2DProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Convolution/EdgeDetector2DProcessor{TPixel}.cs index 5daf14fc32..f6771288fe 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/EdgeDetector2DProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/EdgeDetector2DProcessor{TPixel}.cs @@ -50,7 +50,7 @@ protected override void BeforeFrameApply(ImageFrame source, Rectangle so { if (this.Grayscale) { - new GrayscaleBt709Processor(1F).ApplyToFrame(source, sourceRectangle, configuration); + new GrayscaleBt709Processor(1F).Apply(source, sourceRectangle, configuration); } } } diff --git a/src/ImageSharp/Processing/Processors/Convolution/EdgeDetectorCompassProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Convolution/EdgeDetectorCompassProcessor{TPixel}.cs index 227003195d..5995ac844f 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/EdgeDetectorCompassProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/EdgeDetectorCompassProcessor{TPixel}.cs @@ -42,7 +42,7 @@ protected override void BeforeFrameApply(ImageFrame source, Rectangle so { if (this.Grayscale) { - new GrayscaleBt709Processor(1F).ApplyToFrame(source, sourceRectangle, configuration); + new GrayscaleBt709Processor(1F).Apply(source, sourceRectangle, configuration); } } diff --git a/src/ImageSharp/Processing/Processors/Convolution/EdgeDetectorProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Convolution/EdgeDetectorProcessor{TPixel}.cs index 026313cc12..041c548032 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/EdgeDetectorProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/EdgeDetectorProcessor{TPixel}.cs @@ -38,7 +38,7 @@ protected override void BeforeFrameApply(ImageFrame source, Rectangle so { if (this.Grayscale) { - new GrayscaleBt709Processor(1F).ApplyToFrame(source, sourceRectangle, configuration); + new GrayscaleBt709Processor(1F).Apply(source, sourceRectangle, configuration); } } diff --git a/src/ImageSharp/Processing/Processors/Convolution/SobelProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/SobelProcessor.cs index bc4339e052..3d5d1e7bf1 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/SobelProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/SobelProcessor.cs @@ -26,13 +26,5 @@ public override IImageProcessor CreatePixelSpecificProcessor() { return new EdgeDetector2DProcessor(SobelKernels.SobelX, SobelKernels.SobelY, this.Grayscale); } - - // TODO: Move this to an appropriate extension method if possible. - internal void ApplyToFrame(ImageFrame frame, Rectangle sourceRectangle, Configuration configuration) - where TPixel : struct, IPixel - { - var processorImpl = new EdgeDetector2DProcessor(SobelKernels.SobelX, SobelKernels.SobelY, this.Grayscale); - processorImpl.Apply(frame, sourceRectangle, configuration); - } } } \ No newline at end of file diff --git a/src/ImageSharp/Processing/Processors/Dithering/ErrorDiffusionPaletteProcessor.cs b/src/ImageSharp/Processing/Processors/Dithering/ErrorDiffusionPaletteProcessor.cs index 911d3e8fdc..e0b79c2b20 100644 --- a/src/ImageSharp/Processing/Processors/Dithering/ErrorDiffusionPaletteProcessor.cs +++ b/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 { /// - /// An 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. /// - /// The pixel format. - internal class ErrorDiffusionPaletteProcessor : PaletteDitherProcessorBase - where TPixel : struct, IPixel + public sealed class ErrorDiffusionPaletteProcessor : PaletteDitherProcessor { /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// /// The error diffuser public ErrorDiffusionPaletteProcessor(IErrorDiffuser diffuser) @@ -25,22 +23,22 @@ public ErrorDiffusionPaletteProcessor(IErrorDiffuser diffuser) } /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// /// The error diffuser /// The threshold to split the image. Must be between 0 and 1. public ErrorDiffusionPaletteProcessor(IErrorDiffuser diffuser, float threshold) - : this(diffuser, threshold, NamedColors.WebSafePalette) + : this(diffuser, threshold, Color.WebSafePalette) { } /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// /// The error diffuser /// The threshold to split the image. Must be between 0 and 1. /// The palette to select substitute colors from. - public ErrorDiffusionPaletteProcessor(IErrorDiffuser diffuser, float threshold, TPixel[] palette) + public ErrorDiffusionPaletteProcessor(IErrorDiffuser diffuser, float threshold, ReadOnlyMemory palette) : base(palette) { Guard.NotNull(diffuser, nameof(diffuser)); @@ -60,59 +58,10 @@ public ErrorDiffusionPaletteProcessor(IErrorDiffuser diffuser, float threshold, /// public float Threshold { get; } - /// - protected override void OnFrameApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) + /// + public override IImageProcessor CreatePixelSpecificProcessor() { - 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 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 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(this); } } } \ No newline at end of file diff --git a/src/ImageSharp/Processing/Processors/Dithering/ErrorDiffusionPaletteProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Dithering/ErrorDiffusionPaletteProcessor{TPixel}.cs new file mode 100644 index 0000000000..7edf287e85 --- /dev/null +++ b/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 +{ + /// + /// An that dithers an image using error diffusion. + /// + /// The pixel format. + internal class ErrorDiffusionPaletteProcessor : PaletteDitherProcessor + where TPixel : struct, IPixel + { + public ErrorDiffusionPaletteProcessor(ErrorDiffusionPaletteProcessor definition) + : base(definition) + { + } + + private new ErrorDiffusionPaletteProcessor Definition => (ErrorDiffusionPaletteProcessor)base.Definition; + + /// + protected override void OnFrameApply(ImageFrame 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 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 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); + } + } + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/Processing/Processors/Dithering/OrderedDitherPaletteProcessor.cs b/src/ImageSharp/Processing/Processors/Dithering/OrderedDitherPaletteProcessor.cs index 1b4910a147..ac6554d4c1 100644 --- a/src/ImageSharp/Processing/Processors/Dithering/OrderedDitherPaletteProcessor.cs +++ b/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 { /// - /// An 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. /// - /// The pixel format. - internal class OrderedDitherPaletteProcessor : PaletteDitherProcessorBase - where TPixel : struct, IPixel + public sealed class OrderedDitherPaletteProcessor : PaletteDitherProcessor { /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// /// The ordered ditherer. public OrderedDitherPaletteProcessor(IOrderedDither dither) - : this(dither, NamedColors.WebSafePalette) + : this(dither, Color.WebSafePalette) { } /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// /// The ordered ditherer. /// The palette to select substitute colors from. - public OrderedDitherPaletteProcessor(IOrderedDither dither, TPixel[] palette) + public OrderedDitherPaletteProcessor(IOrderedDither dither, ReadOnlyMemory palette) : base(palette) => this.Dither = dither ?? throw new ArgumentNullException(nameof(dither)); /// @@ -38,57 +33,10 @@ public OrderedDitherPaletteProcessor(IOrderedDither dither, TPixel[] palette) /// public IOrderedDither Dither { get; } - /// - protected override void OnFrameApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) + /// + public override IImageProcessor CreatePixelSpecificProcessor() { - 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 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 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(this); } } } \ No newline at end of file diff --git a/src/ImageSharp/Processing/Processors/Dithering/OrderedDitherPaletteProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Dithering/OrderedDitherPaletteProcessor{TPixel}.cs new file mode 100644 index 0000000000..eefa6e5229 --- /dev/null +++ b/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 +{ + /// + /// An that dithers an image using error diffusion. + /// + /// The pixel format. + internal class OrderedDitherPaletteProcessor : PaletteDitherProcessor + where TPixel : struct, IPixel + { + public OrderedDitherPaletteProcessor(OrderedDitherPaletteProcessor definition) + : base(definition) + { + } + + private new OrderedDitherPaletteProcessor Definition => (OrderedDitherPaletteProcessor)base.Definition; + + /// + protected override void OnFrameApply(ImageFrame 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 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 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); + } + } + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/Processing/Processors/Dithering/PaletteDitherProcessor.cs b/src/ImageSharp/Processing/Processors/Dithering/PaletteDitherProcessor.cs new file mode 100644 index 0000000000..de798b64bc --- /dev/null +++ b/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 +{ + /// + /// The base class for dither and diffusion processors that consume a palette. + /// + public abstract class PaletteDitherProcessor : IImageProcessor + { + /// + /// Initializes a new instance of the class. + /// + /// The palette to select substitute colors from. + protected PaletteDitherProcessor(ReadOnlyMemory palette) + { + this.Palette = palette; + } + + /// + /// Gets the palette to select substitute colors from. + /// + public ReadOnlyMemory Palette { get; } + + /// + public abstract IImageProcessor CreatePixelSpecificProcessor() + where TPixel : struct, IPixel; + } +} \ No newline at end of file diff --git a/src/ImageSharp/Processing/Processors/Dithering/PaletteDitherProcessorBase.cs b/src/ImageSharp/Processing/Processors/Dithering/PaletteDitherProcessor{TPixel}.cs similarity index 70% rename from src/ImageSharp/Processing/Processors/Dithering/PaletteDitherProcessorBase.cs rename to src/ImageSharp/Processing/Processors/Dithering/PaletteDitherProcessor{TPixel}.cs index 6313b74c94..205b589b1e 100644 --- a/src/ImageSharp/Processing/Processors/Dithering/PaletteDitherProcessorBase.cs +++ b/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. /// /// The pixel format. - internal abstract class PaletteDitherProcessorBase : ImageProcessor + internal abstract class PaletteDitherProcessor : ImageProcessor where TPixel : struct, IPixel { private readonly Dictionary> cache = new Dictionary>(); + private TPixel[] palette; + /// /// The vector representation of the image palette. /// private Vector4[] paletteVector; /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// - /// The palette to select substitute colors from. - protected PaletteDitherProcessorBase(TPixel[] palette) + protected PaletteDitherProcessor(PaletteDitherProcessor definition) { - this.Palette = palette ?? throw new ArgumentNullException(nameof(palette)); + this.Definition = definition; } - /// - /// Gets the palette to select substitute colors from. - /// - public TPixel[] Palette { get; } + protected PaletteDitherProcessor Definition { get; } + + protected override void BeforeFrameApply( + ImageFrame source, + Rectangle sourceRectangle, + Configuration configuration) + { + base.BeforeFrameApply(source, sourceRectangle, configuration); + + // Lazy init palette: + if (this.palette is null) + { + ReadOnlySpan sourcePalette = this.Definition.Palette.Span; + this.palette = new TPixel[sourcePalette.Length]; + Color.ToPixel(configuration, sourcePalette, this.palette); + } + + // Lazy init paletteVector: + if (this.paletteVector is null) + { + this.paletteVector = new Vector4[this.palette.Length]; + PixelOperations.Instance.ToVector4( + configuration, + (ReadOnlySpan)this.palette, + (Span)this.paletteVector, + PixelConversionModifiers.Scale); + } + } /// /// Returns the two closest colors from the palette calculated via Euclidean distance in the Rgba space. @@ -74,12 +100,12 @@ private PixelPair GetClosestPixelPairSlow(ref TPixel pixel) { 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 @@ private PixelPair GetClosestPixelPairSlow(ref TPixel pixel) return pair; } - - protected override void BeforeFrameApply(ImageFrame 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.Instance.ToVector4(configuration, (ReadOnlySpan)this.Palette, (Span)this.paletteVector, PixelConversionModifiers.Scale); - } - } } } \ No newline at end of file diff --git a/src/ImageSharp/Processing/Processors/Filters/GrayscaleBt709Processor.cs b/src/ImageSharp/Processing/Processors/Filters/GrayscaleBt709Processor.cs index 2d7d2a1eaa..ae6d5f6f79 100644 --- a/src/ImageSharp/Processing/Processors/Filters/GrayscaleBt709Processor.cs +++ b/src/ImageSharp/Processing/Processors/Filters/GrayscaleBt709Processor.cs @@ -25,13 +25,5 @@ public GrayscaleBt709Processor(float amount) /// Gets the proportion of the conversion. /// public float Amount { get; } - - // TODO: Move this to an appropriate extension method if possible. - internal void ApplyToFrame(ImageFrame frame, Rectangle sourceRectangle, Configuration configuration) - where TPixel : struct, IPixel - { - var processorImpl = new FilterProcessor(new GrayscaleBt709Processor(1F)); - processorImpl.Apply(frame, sourceRectangle, configuration); - } } } \ No newline at end of file diff --git a/src/ImageSharp/Processing/Processors/Filters/LomographProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Filters/LomographProcessor{TPixel}.cs index c15cf6fc90..e0f85945aa 100644 --- a/src/ImageSharp/Processing/Processors/Filters/LomographProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Filters/LomographProcessor{TPixel}.cs @@ -13,7 +13,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Filters internal class LomographProcessor : FilterProcessor where TPixel : struct, IPixel { - private static readonly TPixel VeryDarkGreen = ColorBuilder.FromRGBA(0, 10, 0, 255); + private static readonly Color VeryDarkGreen = Color.FromRgba(0, 10, 0, 255); /// /// Initializes a new instance of the class. @@ -27,7 +27,7 @@ public LomographProcessor(LomographProcessor definition) /// protected override void AfterFrameApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) { - new VignetteProcessor(VeryDarkGreen).Apply(source, sourceRectangle, configuration); + new VignetteProcessor(VeryDarkGreen).Apply(source, sourceRectangle, configuration); } } } \ No newline at end of file diff --git a/src/ImageSharp/Processing/Processors/Filters/PolaroidProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Filters/PolaroidProcessor{TPixel}.cs index befcfc1f42..0f511ee296 100644 --- a/src/ImageSharp/Processing/Processors/Filters/PolaroidProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Filters/PolaroidProcessor{TPixel}.cs @@ -13,8 +13,9 @@ namespace SixLabors.ImageSharp.Processing.Processors.Filters internal class PolaroidProcessor : FilterProcessor where TPixel : struct, IPixel { - private static readonly TPixel VeryDarkOrange = ColorBuilder.FromRGB(102, 34, 0); - private static readonly TPixel LightOrange = ColorBuilder.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); /// /// Initializes a new instance of the class. @@ -26,10 +27,13 @@ public PolaroidProcessor(PolaroidProcessor definition) } /// - protected override void AfterFrameApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) + protected override void AfterFrameApply( + ImageFrame source, + Rectangle sourceRectangle, + Configuration configuration) { - new VignetteProcessor(VeryDarkOrange).Apply(source, sourceRectangle, configuration); - new GlowProcessor(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); } } } \ No newline at end of file diff --git a/src/ImageSharp/Processing/Processors/ImageProcessorExtensions.cs b/src/ImageSharp/Processing/Processors/ImageProcessorExtensions.cs index 762d761c6c..91b2b30d02 100644 --- a/src/ImageSharp/Processing/Processors/ImageProcessorExtensions.cs +++ b/src/ImageSharp/Processing/Processors/ImageProcessorExtensions.cs @@ -14,6 +14,21 @@ public static void Apply(this IImageProcessor processor, Image source, Rectangle source.AcceptVisitor(visitor); } + /// + /// Apply an to a frame. + /// Only works from processors implemented by an subclass. + /// + internal static void Apply( + this IImageProcessor processor, + ImageFrame frame, + Rectangle sourceRectangle, + Configuration configuration) + where TPixel : struct, IPixel + { + var processorImpl = (ImageProcessor)processor.CreatePixelSpecificProcessor(); + processorImpl.Apply(frame, sourceRectangle, configuration); + } + private class ApplyVisitor : IImageVisitor { private readonly IImageProcessor processor; diff --git a/src/ImageSharp/Processing/Processors/Overlays/BackgroundColorProcessor.cs b/src/ImageSharp/Processing/Processors/Overlays/BackgroundColorProcessor.cs index 25787ff922..62848172a1 100644 --- a/src/ImageSharp/Processing/Processors/Overlays/BackgroundColorProcessor.cs +++ b/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 { /// - /// Sets the background color of the image. + /// Defines a processing operation to replace the background color of an . /// - /// The pixel format. - internal class BackgroundColorProcessor : ImageProcessor - where TPixel : struct, IPixel + public sealed class BackgroundColorProcessor : IImageProcessor { /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// - /// The to set the background color to. + /// The to set the background color to. /// The options defining blending algorithm and amount. - public BackgroundColorProcessor(TPixel color, GraphicsOptions options) + public BackgroundColorProcessor(Color color, GraphicsOptions options) { this.Color = color; this.GraphicsOptions = options; @@ -39,69 +29,13 @@ public BackgroundColorProcessor(TPixel color, GraphicsOptions options) /// /// Gets the background color value. /// - public TPixel Color { get; } + public Color Color { get; } - /// - protected override void OnFrameApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) + /// + public IImageProcessor CreatePixelSpecificProcessor() + where TPixel : struct, IPixel { - 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 colors = source.MemoryAllocator.Allocate(width)) - using (IMemoryOwner amount = source.MemoryAllocator.Allocate(width)) - { - // Be careful! Do not capture colorSpan & amountSpan in the lambda below! - Span colorSpan = colors.GetSpan(); - Span amountSpan = amount.GetSpan(); - - colorSpan.Fill(this.Color); - amountSpan.Fill(this.GraphicsOptions.BlendPercentage); - - PixelBlender blender = PixelOperations.Instance.GetPixelBlender(this.GraphicsOptions); - - ParallelHelper.IterateRows( - workingRect, - configuration, - rows => - { - for (int y = rows.Min; y < rows.Max; y++) - { - Span 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(this); } } } \ No newline at end of file diff --git a/src/ImageSharp/Processing/Processors/Overlays/BackgroundColorProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Overlays/BackgroundColorProcessor{TPixel}.cs new file mode 100644 index 0000000000..c4af59fecb --- /dev/null +++ b/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 +{ + /// + /// Sets the background color of the image. + /// + /// The pixel format. + internal class BackgroundColorProcessor : ImageProcessor + where TPixel : struct, IPixel + { + private readonly BackgroundColorProcessor definition; + + /// + /// Initializes a new instance of the class. + /// + public BackgroundColorProcessor(BackgroundColorProcessor definition) + { + this.definition = definition; + } + + /// + protected override void OnFrameApply( + ImageFrame source, + Rectangle sourceRectangle, + Configuration configuration) + { + TPixel color = this.definition.Color.ToPixel(); + 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 colors = source.MemoryAllocator.Allocate(width)) + using (IMemoryOwner amount = source.MemoryAllocator.Allocate(width)) + { + // Be careful! Do not capture colorSpan & amountSpan in the lambda below! + Span colorSpan = colors.GetSpan(); + Span amountSpan = amount.GetSpan(); + + colorSpan.Fill(color); + amountSpan.Fill(graphicsOptions.BlendPercentage); + + PixelBlender blender = PixelOperations.Instance.GetPixelBlender(graphicsOptions); + + ParallelHelper.IterateRows( + workingRect, + configuration, + rows => + { + for (int y = rows.Min; y < rows.Max; y++) + { + Span 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()); + } + }); + } + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/Processing/Processors/Overlays/GlowProcessor.cs b/src/ImageSharp/Processing/Processors/Overlays/GlowProcessor.cs index 21f6be69f8..255be5ed59 100644 --- a/src/ImageSharp/Processing/Processors/Overlays/GlowProcessor.cs +++ b/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 { /// - /// An that applies a radial glow effect an . + /// Defines a radial glow effect applicable to an . /// - /// The pixel format. - internal class GlowProcessor : ImageProcessor - where TPixel : struct, IPixel + public sealed class GlowProcessor : IImageProcessor { - private readonly PixelBlender blender; - /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// /// The color or the glow. - public GlowProcessor(TPixel color) + public GlowProcessor(Color color) : this(color, 0) { } /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// /// The color or the glow. - /// The radius of the glow. - public GlowProcessor(TPixel color, ValueSize radius) - : this(color, radius, GraphicsOptions.Default) + /// The options effecting blending and composition. + public GlowProcessor(Color color, GraphicsOptions options) + : this(color, 0, options) { } /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// /// The color or the glow. - /// The options effecting blending and composition. - public GlowProcessor(TPixel color, GraphicsOptions options) - : this(color, 0, options) + /// The radius of the glow. + internal GlowProcessor(Color color, ValueSize radius) + : this(color, radius, GraphicsOptions.Default) { } /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// /// The color or the glow. /// The radius of the glow. /// The options effecting blending and composition. - 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.Instance.GetPixelBlender(options); this.GraphicsOptions = options; } /// - /// Gets the options effecting blending and composition + /// Gets the options effecting blending and composition. /// public GraphicsOptions GraphicsOptions { get; } /// - /// Gets or sets the glow color to apply. + /// Gets the glow color to apply. /// - public TPixel GlowColor { get; set; } + public Color GlowColor { get; } /// - /// Gets or sets the the radius. + /// Gets the the radius. /// - public ValueSize Radius { get; set; } + internal ValueSize Radius { get; } - /// - protected override void OnFrameApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) + /// + public IImageProcessor CreatePixelSpecificProcessor() + where TPixel : struct, IPixel { - // 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 rowColors = source.MemoryAllocator.Allocate(width)) - { - rowColors.GetSpan().Fill(glowColor); - - ParallelHelper.IterateRowsWithTempBuffer( - workingRect, - configuration, - (rows, amounts) => - { - Span 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 destination = source.GetPixelRowSpan(offsetY).Slice(offsetX, width); - - this.blender.Blend( - source.Configuration, - destination, - destination, - rowColors.GetSpan(), - amountsSpan); - } - }); - } + return new GlowProcessor(this); } } } \ No newline at end of file diff --git a/src/ImageSharp/Processing/Processors/Overlays/GlowProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Overlays/GlowProcessor{TPixel}.cs new file mode 100644 index 0000000000..3201fcbfee --- /dev/null +++ b/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 +{ + /// + /// An that applies a radial glow effect an . + /// + /// The pixel format. + internal class GlowProcessor : ImageProcessor + where TPixel : struct, IPixel + { + private readonly PixelBlender blender; + + private readonly GlowProcessor definition; + + public GlowProcessor(GlowProcessor definition) + { + this.definition = definition; + this.blender = PixelOperations.Instance.GetPixelBlender(definition.GraphicsOptions); + } + + /// + protected override void OnFrameApply( + ImageFrame 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(); + 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 rowColors = source.MemoryAllocator.Allocate(width)) + { + rowColors.GetSpan().Fill(glowColor); + + ParallelHelper.IterateRowsWithTempBuffer( + workingRect, + configuration, + (rows, amounts) => + { + Span 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 destination = source.GetPixelRowSpan(offsetY).Slice(offsetX, width); + + this.blender.Blend( + source.Configuration, + destination, + destination, + rowColors.GetSpan(), + amountsSpan); + } + }); + } + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/Processing/Processors/Overlays/VignetteProcessor.cs b/src/ImageSharp/Processing/Processors/Overlays/VignetteProcessor.cs index a8fa1d65c1..66bf9f1af7 100644 --- a/src/ImageSharp/Processing/Processors/Overlays/VignetteProcessor.cs +++ b/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 { /// - /// An that applies a radial vignette effect to an . + /// Defines a radial vignette effect applicable to an . /// - /// The pixel format. - internal class VignetteProcessor : ImageProcessor - where TPixel : struct, IPixel + public sealed class VignetteProcessor : IImageProcessor { - private readonly PixelBlender blender; - /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// /// The color of the vignette. - public VignetteProcessor(TPixel color) + public VignetteProcessor(Color color) : this(color, GraphicsOptions.Default) { } /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// /// The color of the vignette. /// The options effecting blending and composition. - public VignetteProcessor(TPixel color, GraphicsOptions options) + public VignetteProcessor(Color color, GraphicsOptions options) { this.VignetteColor = color; this.GraphicsOptions = options; - this.blender = PixelOperations.Instance.GetPixelBlender(options); } /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// /// The color of the vignette. /// The x-radius. /// The y-radius. /// The options effecting blending and composition. - 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.Instance.GetPixelBlender(options); this.GraphicsOptions = options; } @@ -67,94 +52,25 @@ public VignetteProcessor(TPixel color, ValueSize radiusX, ValueSize radiusY, Gra public GraphicsOptions GraphicsOptions { get; } /// - /// Gets or sets the vignette color to apply. + /// Gets the vignette color to apply. /// - public TPixel VignetteColor { get; set; } + public Color VignetteColor { get; } /// - /// Gets or sets the the x-radius. + /// Gets the the x-radius. /// - public ValueSize RadiusX { get; set; } + internal ValueSize RadiusX { get; } /// - /// Gets or sets the the y-radius. + /// Gets the the y-radius. /// - public ValueSize RadiusY { get; set; } + internal ValueSize RadiusY { get; } - /// - protected override void OnFrameApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) + /// + public IImageProcessor CreatePixelSpecificProcessor() + where TPixel : struct, IPixel { - 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 rowColors = source.MemoryAllocator.Allocate(width)) - { - rowColors.GetSpan().Fill(vignetteColor); - - ParallelHelper.IterateRowsWithTempBuffer( - workingRect, - configuration, - (rows, amounts) => - { - Span 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 destination = source.GetPixelRowSpan(offsetY).Slice(offsetX, width); - - this.blender.Blend( - source.Configuration, - destination, - destination, - rowColors.GetSpan(), - amountsSpan); - } - }); - } + return new VignetteProcessor(this); } } } \ No newline at end of file diff --git a/src/ImageSharp/Processing/Processors/Overlays/VignetteProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Overlays/VignetteProcessor{TPixel}.cs new file mode 100644 index 0000000000..78c3cec5e7 --- /dev/null +++ b/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 +{ + /// + /// An that applies a radial vignette effect to an . + /// + /// The pixel format. + internal class VignetteProcessor : ImageProcessor + where TPixel : struct, IPixel + { + private readonly PixelBlender blender; + + private readonly VignetteProcessor definition; + + public VignetteProcessor(VignetteProcessor definition) + { + this.definition = definition; + this.blender = PixelOperations.Instance.GetPixelBlender(definition.GraphicsOptions); + } + + /// + protected override void OnFrameApply( + ImageFrame 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(); + 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 rowColors = source.MemoryAllocator.Allocate(width)) + { + rowColors.GetSpan().Fill(vignetteColor); + + ParallelHelper.IterateRowsWithTempBuffer( + workingRect, + configuration, + (rows, amounts) => + { + Span 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 destination = source.GetPixelRowSpan(offsetY).Slice(offsetX, width); + + this.blender.Blend( + source.Configuration, + destination, + destination, + rowColors.GetSpan(), + amountsSpan); + } + }); + } + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/Processing/Processors/Quantization/FrameQuantizerBase{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/FrameQuantizer{TPixel}.cs similarity index 80% rename from src/ImageSharp/Processing/Processors/Quantization/FrameQuantizerBase{TPixel}.cs rename to src/ImageSharp/Processing/Processors/Quantization/FrameQuantizer{TPixel}.cs index f23343f6d7..e6ffecc84d 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/FrameQuantizerBase{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/FrameQuantizer{TPixel}.cs @@ -5,6 +5,7 @@ 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 implementations /// /// The pixel format. - public abstract class FrameQuantizerBase : IFrameQuantizer + public abstract class FrameQuantizer : IFrameQuantizer where TPixel : struct, IPixel { /// @@ -33,7 +34,7 @@ public abstract class FrameQuantizerBase : IFrameQuantizer private Vector4[] paletteVector; /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// /// The quantizer /// @@ -44,7 +45,7 @@ public abstract class FrameQuantizerBase : IFrameQuantizer /// only call the method. /// If two passes are required, the code will also call . /// - protected FrameQuantizerBase(IQuantizer quantizer, bool singlePass) + protected FrameQuantizer(IQuantizer quantizer, bool singlePass) { Guard.NotNull(quantizer, nameof(quantizer)); @@ -53,14 +54,38 @@ protected FrameQuantizerBase(IQuantizer quantizer, bool singlePass) this.singlePass = singlePass; } - /// - public bool Dither { get; } + /// + /// Initializes a new instance of the class. + /// + /// The diffuser + /// + /// If true, the quantization process only needs to loop through the source pixels once + /// + /// + /// If you construct this class with a true for , then the code will + /// only call the method. + /// If two passes are required, the code will also call . + /// + protected FrameQuantizer(IErrorDiffuser diffuser, bool singlePass) + { + this.Diffuser = diffuser; + this.Dither = this.Diffuser != null; + this.singlePass = singlePass; + } /// public IErrorDiffuser Diffuser { get; } + /// + public bool Dither { get; } + /// - public virtual QuantizedFrame QuantizeFrame(ImageFrame image) + public virtual void Dispose() + { + } + + /// + public IQuantizedFrame QuantizeFrame(ImageFrame image) { Guard.NotNull(image, nameof(image)); @@ -77,32 +102,33 @@ public virtual QuantizedFrame QuantizeFrame(ImageFrame image) } // Collect the palette. Required before the second pass runs. - TPixel[] palette = this.GetPalette(); + ReadOnlyMemory palette = this.GetPalette(); this.paletteVector = new Vector4[palette.Length]; - PixelOperations.Instance.ToVector4(image.Configuration, (ReadOnlySpan)palette, (Span)this.paletteVector, PixelConversionModifiers.Scale); + PixelOperations.Instance.ToVector4( + image.Configuration, + palette.Span, + (Span)this.paletteVector, + PixelConversionModifiers.Scale); + var quantizedFrame = new QuantizedFrame(image.MemoryAllocator, width, height, palette); + Span pixelSpan = quantizedFrame.GetWritablePixelSpan(); if (this.Dither) { // We clone the image as we don't want to alter the original via dithering. using (ImageFrame 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; } - /// - public virtual void Dispose() - { - } - /// /// Execute the first pass through the pixels in the image to create the palette. /// @@ -114,19 +140,22 @@ protected virtual void FirstPass(ImageFrame source, int width, int heigh } /// - /// 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. /// - /// The source image. - /// The output pixel array. - /// The output color palette. - /// The width in pixels of the image. - /// The height in pixels of the image. - protected abstract void SecondPass( - ImageFrame source, - Span output, - ReadOnlySpan palette, - int width, - int height); + /// The color. + /// The + [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); + } /// /// Retrieve the palette for the quantized image. @@ -134,7 +163,7 @@ protected abstract void SecondPass( /// /// /// - protected abstract TPixel[] GetPalette(); + protected abstract ReadOnlyMemory GetPalette(); /// /// Returns the index of the first instance of the transparent color in the palette. @@ -160,22 +189,19 @@ protected byte GetTransparentIndex() } /// - /// 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. /// - /// The color. - /// The - [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); - } + /// The source image. + /// The output pixel array. + /// The output color palette. + /// The width in pixels of the image. + /// The height in pixels of the image. + protected abstract void SecondPass( + ImageFrame source, + Span output, + ReadOnlySpan palette, + int width, + int height); [MethodImpl(MethodImplOptions.NoInlining)] private byte GetClosestPixelSlow(ref TPixel pixel) diff --git a/src/ImageSharp/Processing/Processors/Quantization/IFrameQuantizer{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/IFrameQuantizer{TPixel}.cs index f0b68b3a08..54dabab0ae 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/IFrameQuantizer{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/IFrameQuantizer{TPixel}.cs @@ -31,6 +31,6 @@ public interface IFrameQuantizer : IDisposable /// /// A representing a quantized version of the image pixels. /// - QuantizedFrame QuantizeFrame(ImageFrame image); + IQuantizedFrame QuantizeFrame(ImageFrame image); } } \ No newline at end of file diff --git a/src/ImageSharp/Processing/Processors/Quantization/IQuantizedFrame{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/IQuantizedFrame{TPixel}.cs new file mode 100644 index 0000000000..42016459be --- /dev/null +++ b/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 +{ + /// + /// Defines an abstraction to represent a quantized image frame where the pixels indexed by a color palette. + /// + /// The pixel format. + public interface IQuantizedFrame : IDisposable + where TPixel : struct, IPixel + { + /// + /// Gets the width of this . + /// + int Width { get; } + + /// + /// Gets the height of this . + /// + int Height { get; } + + /// + /// Gets the color palette of this . + /// + ReadOnlyMemory Palette { get; } + + /// + /// Gets the pixels of this . + /// + /// The The pixel span. + ReadOnlySpan GetPixelSpan(); + } +} \ No newline at end of file diff --git a/src/ImageSharp/Processing/Processors/Quantization/OctreeFrameQuantizer{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/OctreeFrameQuantizer{TPixel}.cs index dd56375f63..85a4d20295 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/OctreeFrameQuantizer{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/OctreeFrameQuantizer{TPixel}.cs @@ -16,7 +16,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// /// /// The pixel format. - internal sealed class OctreeFrameQuantizer : FrameQuantizerBase + internal sealed class OctreeFrameQuantizer : FrameQuantizer where TPixel : struct, IPixel { /// @@ -136,10 +136,10 @@ protected override void SecondPass( } } - internal TPixel[] AotGetPalette() => this.GetPalette(); + internal ReadOnlyMemory AotGetPalette() => this.GetPalette(); /// - protected override TPixel[] GetPalette() => this.octree.Palletize(this.colors); + protected override ReadOnlyMemory GetPalette() => this.octree.Palletize(this.colors); /// /// Process the pixel in the second pass of the algorithm. diff --git a/src/ImageSharp/Processing/Processors/Quantization/PaletteFrameQuantizer{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/PaletteFrameQuantizer{TPixel}.cs index f8a19f8c40..265c343e68 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/PaletteFrameQuantizer{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/PaletteFrameQuantizer{TPixel}.cs @@ -6,6 +6,7 @@ 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 /// /// /// The pixel format. - internal sealed class PaletteFrameQuantizer : FrameQuantizerBase + internal sealed class PaletteFrameQuantizer : FrameQuantizer where TPixel : struct, IPixel { /// /// The reduced image palette. /// - private readonly TPixel[] palette; + private readonly ReadOnlyMemory palette; /// /// Initializes a new instance of the class. /// - /// The palette quantizer. + /// The palette quantizer. /// An array of all colors in the palette. - public PaletteFrameQuantizer(IQuantizer quantizer, TPixel[] colors) - : base(quantizer, true) => this.palette = colors; + public PaletteFrameQuantizer(IErrorDiffuser diffuser, ReadOnlyMemory colors) + : base(diffuser, true) => this.palette = colors; /// protected override void SecondPass( @@ -85,7 +86,7 @@ protected override void SecondPass( /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - protected override TPixel[] GetPalette() => this.palette; + protected override ReadOnlyMemory GetPalette() => this.palette; /// /// Process the pixel in the second pass of the algorithm diff --git a/src/ImageSharp/Processing/Processors/Quantization/PaletteQuantizer.cs b/src/ImageSharp/Processing/Processors/Quantization/PaletteQuantizer.cs index 6b2be3d038..ba434a4b21 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/PaletteQuantizer.cs +++ b/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 dithering. /// /// - public abstract class PaletteQuantizer : IQuantizer + public class PaletteQuantizer : IQuantizer { /// /// Initializes a new instance of the class. /// - protected PaletteQuantizer() - : this(true) + /// The palette. + public PaletteQuantizer(ReadOnlyMemory palette) + : this(palette, true) { } /// /// Initializes a new instance of the class. /// + /// The palette. /// Whether to apply dithering to the output image - protected PaletteQuantizer(bool dither) - : this(GetDiffuser(dither)) + public PaletteQuantizer(ReadOnlyMemory palette, bool dither) + : this(palette, GetDiffuser(dither)) { } /// /// Initializes a new instance of the class. /// + /// The palette. /// The error diffusion algorithm, if any, to apply to the output image - protected PaletteQuantizer(IErrorDiffuser diffuser) => this.Diffuser = diffuser; + public PaletteQuantizer(ReadOnlyMemory palette, IErrorDiffuser diffuser) + { + this.Palette = palette; + this.Diffuser = diffuser; + } /// public IErrorDiffuser Diffuser { get; } - /// - public abstract IFrameQuantizer CreateFrameQuantizer(Configuration configuration) - where TPixel : struct, IPixel; - - /// - public abstract IFrameQuantizer CreateFrameQuantizer(Configuration configuration, int maxColors) - where TPixel : struct, IPixel; - /// - /// Creates the generic frame quantizer. + /// Gets the palette. /// - /// The pixel format. - /// The to configure internal operations. - /// The color palette. - /// The maximum number of colors to hold in the color palette. - /// The - protected IFrameQuantizer CreateFrameQuantizer(Configuration configuration, TPixel[] palette, int maxColors) + public ReadOnlyMemory Palette { get; } + + /// + public IFrameQuantizer CreateFrameQuantizer(Configuration configuration) where TPixel : struct, IPixel { - 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(this.Diffuser, palette); + } - if (max != palette.Length) - { - return new PaletteFrameQuantizer(this, palette.AsSpan(0, max).ToArray()); - } + /// + public IFrameQuantizer CreateFrameQuantizer(Configuration configuration, int maxColors) + where TPixel : struct, IPixel + { + maxColors = maxColors.Clamp(QuantizerConstants.MinColors, QuantizerConstants.MaxColors); + int max = Math.Min(maxColors, this.Palette.Length); - return new PaletteFrameQuantizer(this, palette); + TPixel[] palette = new TPixel[max]; + Color.ToPixel(configuration, this.Palette.Span.Slice(0, max), palette.AsSpan()); + return new PaletteFrameQuantizer(this.Diffuser, palette); } private static IErrorDiffuser GetDiffuser(bool dither) => dither ? KnownDiffusers.FloydSteinberg : null; diff --git a/src/ImageSharp/Processing/Processors/Quantization/PaletteQuantizer{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/PaletteQuantizer{TPixel}.cs deleted file mode 100644 index a350adfc0c..0000000000 --- a/src/ImageSharp/Processing/Processors/Quantization/PaletteQuantizer{TPixel}.cs +++ /dev/null @@ -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 -{ - /// - /// A generic palette quantizer. - /// - /// The pixel format. - public class PaletteQuantizer : IQuantizer - where TPixel : struct, IPixel - { - /// - /// Initializes a new instance of the class. - /// - /// The color palette to use. - public PaletteQuantizer(TPixel[] palette) - : this(palette, true) - { - } - - /// - /// Initializes a new instance of the class. - /// - /// The color palette to use. - /// Whether to apply dithering to the output image - public PaletteQuantizer(TPixel[] palette, bool dither) - : this(palette, GetDiffuser(dither)) - { - } - - /// - /// Initializes a new instance of the class. - /// - /// The color palette to use. - /// The error diffusion algorithm, if any, to apply to the output image - public PaletteQuantizer(TPixel[] palette, IErrorDiffuser diffuser) - { - Guard.MustBeBetweenOrEqualTo(palette.Length, QuantizerConstants.MinColors, QuantizerConstants.MaxColors, nameof(palette)); - this.Palette = palette; - this.Diffuser = diffuser; - } - - /// - public IErrorDiffuser Diffuser { get; } - - /// - /// Gets the palette. - /// - public TPixel[] Palette { get; } - - /// - /// Creates the generic frame quantizer. - /// - /// The to configure internal operations. - /// The . - public IFrameQuantizer CreateFrameQuantizer(Configuration configuration) - => ((IQuantizer)this).CreateFrameQuantizer(configuration); - - /// - /// Creates the generic frame quantizer. - /// - /// The to configure internal operations. - /// The maximum number of colors to hold in the color palette. - /// The . - public IFrameQuantizer CreateFrameQuantizer(Configuration configuration, int maxColors) - => ((IQuantizer)this).CreateFrameQuantizer(configuration, maxColors); - - /// - IFrameQuantizer IQuantizer.CreateFrameQuantizer(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(this, Unsafe.As(ref paletteRef)); - } - - /// - IFrameQuantizer IQuantizer.CreateFrameQuantizer(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(ref paletteRef); - - maxColors = maxColors.Clamp(QuantizerConstants.MinColors, QuantizerConstants.MaxColors); - int max = Math.Min(maxColors, castPalette.Length); - - if (max != castPalette.Length) - { - return new PaletteFrameQuantizer(this, castPalette.AsSpan(0, max).ToArray()); - } - - return new PaletteFrameQuantizer(this, castPalette); - } - - private static IErrorDiffuser GetDiffuser(bool dither) => dither ? KnownDiffusers.FloydSteinberg : null; - } -} \ No newline at end of file diff --git a/src/ImageSharp/Processing/Processors/Quantization/QuantizeProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/QuantizeProcessor{TPixel}.cs index b52343a2ae..5cb45e8d70 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/QuantizeProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/QuantizeProcessor{TPixel}.cs @@ -31,8 +31,8 @@ public QuantizeProcessor(IQuantizer quantizer) /// protected override void OnFrameApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) { - using (IFrameQuantizer executor = this.quantizer.CreateFrameQuantizer(configuration)) - using (QuantizedFrame quantized = executor.QuantizeFrame(source)) + using (IFrameQuantizer frameQuantizer = this.quantizer.CreateFrameQuantizer(configuration)) + using (IQuantizedFrame quantized = frameQuantizer.QuantizeFrame(source)) { int paletteCount = quantized.Palette.Length - 1; @@ -43,12 +43,15 @@ protected override void OnFrameApply(ImageFrame source, Rectangle source { Span row = source.GetPixelRowSpan(y); ReadOnlySpan quantizedPixelSpan = quantized.GetPixelSpan(); + + ReadOnlySpan 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])]; } } } diff --git a/src/ImageSharp/Processing/Processors/Quantization/QuantizedFrameExtensions.cs b/src/ImageSharp/Processing/Processors/Quantization/QuantizedFrameExtensions.cs new file mode 100644 index 0000000000..fa3d36e10a --- /dev/null +++ b/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 +{ + /// + /// Contains extension methods for . + /// + public static class QuantizedFrameExtensions + { + /// + /// Gets the representation of the pixels as a of contiguous memory + /// at row beginning from the the first pixel on that row. + /// + /// The . + /// The row. + /// The pixel type. + /// The pixel row as a . + [MethodImpl(InliningOptions.ShortMethod)] + public static ReadOnlySpan GetRowSpan(this IQuantizedFrame frame, int rowIndex) + where TPixel : struct, IPixel + => frame.GetPixelSpan().Slice(rowIndex * frame.Width, frame.Width); + } +} \ No newline at end of file diff --git a/src/ImageSharp/Processing/Processors/Quantization/QuantizedFrame{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/QuantizedFrame{TPixel}.cs index 30b8bc8469..cbea82c1f3 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/QuantizedFrame{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/QuantizedFrame{TPixel}.cs @@ -8,14 +8,13 @@ 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 { /// /// Represents a quantized image frame where the pixels indexed by a color palette. /// /// The pixel format. - public class QuantizedFrame : IDisposable + public class QuantizedFrame : IQuantizedFrame where TPixel : struct, IPixel { private IMemoryOwner pixels; @@ -27,7 +26,7 @@ public class QuantizedFrame : IDisposable /// The image width. /// The image height. /// The color palette. - public QuantizedFrame(MemoryAllocator memoryAllocator, int width, int height, TPixel[] palette) + internal QuantizedFrame(MemoryAllocator memoryAllocator, int width, int height, ReadOnlyMemory palette) { Guard.MustBeGreaterThan(width, 0, nameof(width)); Guard.MustBeGreaterThan(height, 0, nameof(height)); @@ -51,23 +50,14 @@ public QuantizedFrame(MemoryAllocator memoryAllocator, int width, int height, TP /// /// Gets the color palette of this . /// - public TPixel[] Palette { get; private set; } + public ReadOnlyMemory Palette { get; private set; } /// /// Gets the pixels of this . /// /// The [MethodImpl(InliningOptions.ShortMethod)] - public Span GetPixelSpan() => this.pixels.GetSpan(); - - /// - /// Gets the representation of the pixels as a of contiguous memory - /// at row beginning from the first pixel on that row. - /// - /// The row. - /// The - [MethodImpl(InliningOptions.ShortMethod)] - public Span GetRowSpan(int rowIndex) => this.GetPixelSpan().Slice(rowIndex * this.Width, this.Width); + public ReadOnlySpan GetPixelSpan() => this.pixels.GetSpan(); /// public void Dispose() @@ -76,5 +66,10 @@ public void Dispose() this.pixels = null; this.Palette = null; } + + /// + /// Get the non-readonly span of pixel data so can fill it. + /// + internal Span GetWritablePixelSpan() => this.pixels.GetSpan(); } } \ No newline at end of file diff --git a/src/ImageSharp/Processing/Processors/Quantization/WebSafePaletteQuantizer.cs b/src/ImageSharp/Processing/Processors/Quantization/WebSafePaletteQuantizer.cs index 93630a9166..3f6dfde281 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/WebSafePaletteQuantizer.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/WebSafePaletteQuantizer.cs @@ -15,6 +15,7 @@ public class WebSafePaletteQuantizer : PaletteQuantizer /// Initializes a new instance of the class. /// public WebSafePaletteQuantizer() + : this(true) { } @@ -23,7 +24,7 @@ public WebSafePaletteQuantizer() /// /// Whether to apply dithering to the output image public WebSafePaletteQuantizer(bool dither) - : base(dither) + : base(Color.WebSafePalette, dither) { } @@ -32,16 +33,8 @@ public WebSafePaletteQuantizer(bool dither) /// /// The error diffusion algorithm, if any, to apply to the output image public WebSafePaletteQuantizer(IErrorDiffuser diffuser) - : base(diffuser) + : base(Color.WebSafePalette, diffuser) { } - - /// - public override IFrameQuantizer CreateFrameQuantizer(Configuration configuration) - => this.CreateFrameQuantizer(configuration, NamedColors.WebSafePalette.Length); - - /// - public override IFrameQuantizer CreateFrameQuantizer(Configuration configuration, int maxColors) - => this.CreateFrameQuantizer(configuration, NamedColors.WebSafePalette, maxColors); } } \ No newline at end of file diff --git a/src/ImageSharp/Processing/Processors/Quantization/WernerPaletteQuantizer.cs b/src/ImageSharp/Processing/Processors/Quantization/WernerPaletteQuantizer.cs index 2ff9f5090c..d659ecabf7 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/WernerPaletteQuantizer.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/WernerPaletteQuantizer.cs @@ -16,6 +16,7 @@ public class WernerPaletteQuantizer : PaletteQuantizer /// Initializes a new instance of the class. /// public WernerPaletteQuantizer() + : this(true) { } @@ -24,7 +25,7 @@ public WernerPaletteQuantizer() /// /// Whether to apply dithering to the output image public WernerPaletteQuantizer(bool dither) - : base(dither) + : base(Color.WernerPalette, dither) { } @@ -33,16 +34,8 @@ public WernerPaletteQuantizer(bool dither) /// /// The error diffusion algorithm, if any, to apply to the output image public WernerPaletteQuantizer(IErrorDiffuser diffuser) - : base(diffuser) + : base(Color.WernerPalette, diffuser) { } - - /// - public override IFrameQuantizer CreateFrameQuantizer(Configuration configuration) - => this.CreateFrameQuantizer(configuration, NamedColors.WernerPalette.Length); - - /// - public override IFrameQuantizer CreateFrameQuantizer(Configuration configuration, int maxColors) - => this.CreateFrameQuantizer(configuration, NamedColors.WernerPalette, maxColors); } } \ No newline at end of file diff --git a/src/ImageSharp/Processing/Processors/Quantization/WuFrameQuantizer{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/WuFrameQuantizer{TPixel}.cs index 1f1513adf1..2b1a24aee5 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/WuFrameQuantizer{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/WuFrameQuantizer{TPixel}.cs @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// /// /// The pixel format. - internal sealed class WuFrameQuantizer : FrameQuantizerBase + internal sealed class WuFrameQuantizer : FrameQuantizer where TPixel : struct, IPixel { // The following two variables determine the amount of bits to preserve when calculating the histogram. @@ -120,33 +120,31 @@ internal sealed class WuFrameQuantizer : FrameQuantizerBase /// /// Initializes a new instance of the class. /// + /// The . /// The wu quantizer /// /// The Wu quantizer is a two pass algorithm. The initial pass sets up the 3-D color histogram, /// the second pass quantizes a color based on the position in the histogram. /// - public WuFrameQuantizer(WuQuantizer quantizer) - : this(quantizer, quantizer.MaxColors) + public WuFrameQuantizer(MemoryAllocator memoryAllocator, WuQuantizer quantizer) + : this(memoryAllocator, quantizer, quantizer.MaxColors) { } /// /// Initializes a new instance of the class. /// + /// The . /// The wu quantizer. /// The maximum number of colors to hold in the color palette. /// /// The Wu quantizer is a two pass algorithm. The initial pass sets up the 3-D color histogram, /// the second pass quantizes a color based on the position in the histogram. /// - public WuFrameQuantizer(WuQuantizer quantizer, int maxColors) - : base(quantizer, false) => this.colors = maxColors; - - /// - public override QuantizedFrame QuantizeFrame(ImageFrame image) + public WuFrameQuantizer(MemoryAllocator memoryAllocator, WuQuantizer quantizer, int maxColors) + : base(quantizer, false) { - Guard.NotNull(image, nameof(image)); - MemoryAllocator memoryAllocator = image.MemoryAllocator; + Guard.NotNull(memoryAllocator, nameof(memoryAllocator)); this.vwt = memoryAllocator.Allocate(TableLength, AllocationOptions.Clean); this.vmr = memoryAllocator.Allocate(TableLength, AllocationOptions.Clean); @@ -156,7 +154,7 @@ public override QuantizedFrame QuantizeFrame(ImageFrame image) this.m2 = memoryAllocator.Allocate(TableLength, AllocationOptions.Clean); this.tag = memoryAllocator.Allocate(TableLength, AllocationOptions.Clean); - return base.QuantizeFrame(image); + this.colors = maxColors; } /// @@ -169,12 +167,20 @@ public override void Dispose() this.vma?.Dispose(); this.m2?.Dispose(); this.tag?.Dispose(); + + this.vwt = null; + this.vmr = null; + this.vmg = null; + this.vmb = null; + this.vma = null; + this.m2 = null; + this.tag = null; } - internal TPixel[] AotGetPalette() => this.GetPalette(); + internal ReadOnlyMemory AotGetPalette() => this.GetPalette(); /// - protected override TPixel[] GetPalette() + protected override ReadOnlyMemory GetPalette() { if (this.palette is null) { diff --git a/src/ImageSharp/Processing/Processors/Quantization/WuQuantizer.cs b/src/ImageSharp/Processing/Processors/Quantization/WuQuantizer.cs index eb8b0fec91..b80cedeb39 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/WuQuantizer.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/WuQuantizer.cs @@ -72,14 +72,18 @@ public WuQuantizer(IErrorDiffuser diffuser, int maxColors) /// public IFrameQuantizer CreateFrameQuantizer(Configuration configuration) where TPixel : struct, IPixel - => new WuFrameQuantizer(this); + { + Guard.NotNull(configuration, nameof(configuration)); + return new WuFrameQuantizer(configuration.MemoryAllocator, this); + } /// public IFrameQuantizer CreateFrameQuantizer(Configuration configuration, int maxColors) where TPixel : struct, IPixel { + Guard.NotNull(configuration, nameof(configuration)); maxColors = maxColors.Clamp(QuantizerConstants.MinColors, QuantizerConstants.MaxColors); - return new WuFrameQuantizer(this, maxColors); + return new WuFrameQuantizer(configuration.MemoryAllocator, this, maxColors); } private static IErrorDiffuser GetDiffuser(bool dither) => dither ? KnownDiffusers.FloydSteinberg : null; diff --git a/src/ImageSharp/Processing/Processors/Transforms/EntropyCropProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Transforms/EntropyCropProcessor{TPixel}.cs index eaeb6939ec..4bfeb25198 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/EntropyCropProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/EntropyCropProcessor{TPixel}.cs @@ -38,10 +38,10 @@ protected override void BeforeImageApply(Image source, Rectangle sourceR Configuration configuration = source.GetConfiguration(); // Detect the edges. - new SobelProcessor(false).ApplyToFrame(temp, sourceRectangle, configuration); + new SobelProcessor(false).Apply(temp, sourceRectangle, configuration); // Apply threshold binarization filter. - new BinaryThresholdProcessor(this.definition.Threshold).Apply(temp, sourceRectangle, configuration); + new BinaryThresholdProcessor(this.definition.Threshold).Apply(temp, sourceRectangle, configuration); // Search for the first white pixels rectangle = ImageMaths.GetFilteredBoundingRectangle(temp, 0); diff --git a/tests/ImageSharp.Benchmarks/Codecs/GetSetPixel.cs b/tests/ImageSharp.Benchmarks/Codecs/GetSetPixel.cs index a51ce8ebc6..f0d7a54d08 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/GetSetPixel.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/GetSetPixel.cs @@ -10,11 +10,11 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs public class GetSetPixel : BenchmarkBase { [Benchmark(Baseline = true, Description = "System.Drawing GetSet pixel")] - public Color ResizeSystemDrawing() + public System.Drawing.Color ResizeSystemDrawing() { using (var source = new Bitmap(400, 400)) { - source.SetPixel(200, 200, Color.White); + source.SetPixel(200, 200, System.Drawing.Color.White); return source.GetPixel(200, 200); } } diff --git a/tests/ImageSharp.Benchmarks/Drawing/DrawBeziers.cs b/tests/ImageSharp.Benchmarks/Drawing/DrawBeziers.cs index bc9c1c96d2..0a343864d8 100644 --- a/tests/ImageSharp.Benchmarks/Drawing/DrawBeziers.cs +++ b/tests/ImageSharp.Benchmarks/Drawing/DrawBeziers.cs @@ -23,7 +23,7 @@ public void DrawPathSystemDrawing() graphics.InterpolationMode = InterpolationMode.Default; graphics.SmoothingMode = SmoothingMode.AntiAlias; - using (var pen = new Pen(Color.HotPink, 10)) + using (var pen = new Pen(System.Drawing.Color.HotPink, 10)) { graphics.DrawBeziers(pen, new[] { new PointF(10, 500), diff --git a/tests/ImageSharp.Benchmarks/Drawing/DrawLines.cs b/tests/ImageSharp.Benchmarks/Drawing/DrawLines.cs index 4265525e5b..00942cc364 100644 --- a/tests/ImageSharp.Benchmarks/Drawing/DrawLines.cs +++ b/tests/ImageSharp.Benchmarks/Drawing/DrawLines.cs @@ -24,7 +24,7 @@ public void DrawPathSystemDrawing() graphics.InterpolationMode = InterpolationMode.Default; graphics.SmoothingMode = SmoothingMode.AntiAlias; - using (var pen = new Pen(Color.HotPink, 10)) + using (var pen = new Pen(System.Drawing.Color.HotPink, 10)) { graphics.DrawLines(pen, new[] { new PointF(10, 10), diff --git a/tests/ImageSharp.Benchmarks/Drawing/DrawPolygon.cs b/tests/ImageSharp.Benchmarks/Drawing/DrawPolygon.cs index 4172b3c38f..dcaf4bae60 100644 --- a/tests/ImageSharp.Benchmarks/Drawing/DrawPolygon.cs +++ b/tests/ImageSharp.Benchmarks/Drawing/DrawPolygon.cs @@ -22,7 +22,7 @@ public void DrawPolygonSystemDrawing() { graphics.InterpolationMode = InterpolationMode.Default; graphics.SmoothingMode = SmoothingMode.AntiAlias; - using (var pen = new Pen(Color.HotPink, 10)) + using (var pen = new Pen(System.Drawing.Color.HotPink, 10)) { graphics.DrawPolygon(pen, new[] { new PointF(10, 10), diff --git a/tests/ImageSharp.Benchmarks/Drawing/DrawTextOutline.cs b/tests/ImageSharp.Benchmarks/Drawing/DrawTextOutline.cs index b99c47960b..ee17adbb55 100644 --- a/tests/ImageSharp.Benchmarks/Drawing/DrawTextOutline.cs +++ b/tests/ImageSharp.Benchmarks/Drawing/DrawTextOutline.cs @@ -27,7 +27,7 @@ public void DrawTextSystemDrawing() { graphics.InterpolationMode = InterpolationMode.Default; graphics.SmoothingMode = SmoothingMode.AntiAlias; - using (var pen = new Pen(Color.HotPink, 10)) + using (var pen = new Pen(System.Drawing.Color.HotPink, 10)) using (var font = new Font("Arial", 12, GraphicsUnit.Point)) using (var gp = new GraphicsPath()) { diff --git a/tests/ImageSharp.Benchmarks/Drawing/FillWithPattern.cs b/tests/ImageSharp.Benchmarks/Drawing/FillWithPattern.cs index 3c9cfd7e34..411f8210a9 100644 --- a/tests/ImageSharp.Benchmarks/Drawing/FillWithPattern.cs +++ b/tests/ImageSharp.Benchmarks/Drawing/FillWithPattern.cs @@ -24,7 +24,7 @@ public void DrawPatternPolygonSystemDrawing() { graphics.SmoothingMode = SmoothingMode.AntiAlias; - using (var brush = new HatchBrush(HatchStyle.BackwardDiagonal, Color.HotPink)) + using (var brush = new HatchBrush(HatchStyle.BackwardDiagonal, System.Drawing.Color.HotPink)) { graphics.FillRectangle(brush, new Rectangle(0, 0, 800, 800)); // can't find a way to flood fill with a brush } diff --git a/tests/ImageSharp.Benchmarks/Samplers/Glow.cs b/tests/ImageSharp.Benchmarks/Samplers/Glow.cs index 15b82e022d..29f69cdd55 100644 --- a/tests/ImageSharp.Benchmarks/Samplers/Glow.cs +++ b/tests/ImageSharp.Benchmarks/Samplers/Glow.cs @@ -20,14 +20,14 @@ namespace SixLabors.ImageSharp.Benchmarks public class Glow : BenchmarkBase { - private GlowProcessor bulk; + private GlowProcessor bulk; private GlowProcessorParallel parallel; [GlobalSetup] public void Setup() { - this.bulk = new GlowProcessor(NamedColors.Beige, 800 * .5f, GraphicsOptions.Default); + this.bulk = new GlowProcessor(Color.Beige, 800 * .5f, GraphicsOptions.Default); this.parallel = new GlowProcessorParallel(NamedColors.Beige) { Radius = 800 * .5f, }; } diff --git a/tests/ImageSharp.Tests/Color/ColorTests.CastFrom.cs b/tests/ImageSharp.Tests/Color/ColorTests.CastFrom.cs new file mode 100644 index 0000000000..22c6d55ad8 --- /dev/null +++ b/tests/ImageSharp.Tests/Color/ColorTests.CastFrom.cs @@ -0,0 +1,93 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using SixLabors.ImageSharp.PixelFormats; + +using Xunit; + +namespace SixLabors.ImageSharp.Tests +{ + public partial class ColorTests + { + public class CastFrom + { + [Fact] + public void Rgba64() + { + Rgba64 source = new Rgba64(100, 2222, 3333, 4444); + + // Act: + Color color = source; + + // Assert: + Rgba64 data = color.ToPixel(); + Assert.Equal(source, data); + } + + [Fact] + public void Rgba32() + { + Rgba32 source = new Rgba32(1, 22, 33, 231); + + // Act: + Color color = source; + + // Assert: + Rgba32 data = color.ToPixel(); + Assert.Equal(source, data); + } + + [Fact] + public void Argb32() + { + Argb32 source = new Argb32(1, 22, 33, 231); + + // Act: + Color color = source; + + // Assert: + Argb32 data = color.ToPixel(); + Assert.Equal(source, data); + } + + [Fact] + public void Bgra32() + { + Bgra32 source = new Bgra32(1, 22, 33, 231); + + // Act: + Color color = source; + + // Assert: + Bgra32 data = color.ToPixel(); + Assert.Equal(source, data); + } + + [Fact] + public void Rgb24() + { + Rgb24 source = new Rgb24(1, 22, 231); + + // Act: + Color color = source; + + // Assert: + Rgb24 data = color.ToPixel(); + Assert.Equal(source, data); + } + + [Fact] + public void Bgr24() + { + Bgr24 source = new Bgr24(1, 22, 231); + + // Act: + Color color = source; + + // Assert: + Bgr24 data = color.ToPixel(); + Assert.Equal(source, data); + } + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Color/ColorTests.CastTo.cs b/tests/ImageSharp.Tests/Color/ColorTests.CastTo.cs new file mode 100644 index 0000000000..d44472b28a --- /dev/null +++ b/tests/ImageSharp.Tests/Color/ColorTests.CastTo.cs @@ -0,0 +1,93 @@ +// // Copyright (c) Six Labors and contributors. +// // Licensed under the Apache License, Version 2.0. + +using SixLabors.ImageSharp.PixelFormats; + +using Xunit; + +namespace SixLabors.ImageSharp.Tests +{ + public partial class ColorTests + { + public class CastTo + { + [Fact] + public void Rgba64() + { + Rgba64 source = new Rgba64(100, 2222, 3333, 4444); + + // Act: + Color color = new Color(source); + + // Assert: + Rgba64 data = color; + Assert.Equal(source, data); + } + + [Fact] + public void Rgba32() + { + Rgba32 source = new Rgba32(1, 22, 33, 231); + + // Act: + Color color = new Color(source); + + // Assert: + Rgba32 data = color; + Assert.Equal(source, data); + } + + [Fact] + public void Argb32() + { + Argb32 source = new Argb32(1, 22, 33, 231); + + // Act: + Color color = new Color(source); + + // Assert: + Argb32 data = color; + Assert.Equal(source, data); + } + + [Fact] + public void Bgra32() + { + Bgra32 source = new Bgra32(1, 22, 33, 231); + + // Act: + Color color = new Color(source); + + // Assert: + Bgra32 data = color; + Assert.Equal(source, data); + } + + [Fact] + public void Rgb24() + { + Rgb24 source = new Rgb24(1, 22, 231); + + // Act: + Color color = new Color(source); + + // Assert: + Rgb24 data = color; + Assert.Equal(source, data); + } + + [Fact] + public void Bgr24() + { + Bgr24 source = new Bgr24(1, 22, 231); + + // Act: + Color color = new Color(source); + + // Assert: + Bgr24 data = color; + Assert.Equal(source, data); + } + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Color/ColorTests.ConstructFrom.cs b/tests/ImageSharp.Tests/Color/ColorTests.ConstructFrom.cs new file mode 100644 index 0000000000..9d21cd80c5 --- /dev/null +++ b/tests/ImageSharp.Tests/Color/ColorTests.ConstructFrom.cs @@ -0,0 +1,93 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using SixLabors.ImageSharp.PixelFormats; + +using Xunit; + +namespace SixLabors.ImageSharp.Tests +{ + public partial class ColorTests + { + public class ConstructFrom + { + [Fact] + public void Rgba64() + { + Rgba64 source = new Rgba64(100, 2222, 3333, 4444); + + // Act: + Color color = new Color(source); + + // Assert: + Rgba64 data = color.ToPixel(); + Assert.Equal(source, data); + } + + [Fact] + public void Rgba32() + { + Rgba32 source = new Rgba32(1, 22, 33, 231); + + // Act: + Color color = new Color(source); + + // Assert: + Rgba32 data = color.ToPixel(); + Assert.Equal(source, data); + } + + [Fact] + public void Argb32() + { + Argb32 source = new Argb32(1, 22, 33, 231); + + // Act: + Color color = new Color(source); + + // Assert: + Argb32 data = color.ToPixel(); + Assert.Equal(source, data); + } + + [Fact] + public void Bgra32() + { + Bgra32 source = new Bgra32(1, 22, 33, 231); + + // Act: + Color color = new Color(source); + + // Assert: + Bgra32 data = color.ToPixel(); + Assert.Equal(source, data); + } + + [Fact] + public void Rgb24() + { + Rgb24 source = new Rgb24(1, 22, 231); + + // Act: + Color color = new Color(source); + + // Assert: + Rgb24 data = color.ToPixel(); + Assert.Equal(source, data); + } + + [Fact] + public void Bgr24() + { + Bgr24 source = new Bgr24(1, 22, 231); + + // Act: + Color color = new Color(source); + + // Assert: + Bgr24 data = color.ToPixel(); + Assert.Equal(source, data); + } + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Color/ColorTests.cs b/tests/ImageSharp.Tests/Color/ColorTests.cs new file mode 100644 index 0000000000..b2559d1d16 --- /dev/null +++ b/tests/ImageSharp.Tests/Color/ColorTests.cs @@ -0,0 +1,99 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Linq; +using System.Reflection; + +using SixLabors.ImageSharp.PixelFormats; + +using Xunit; + +namespace SixLabors.ImageSharp.Tests +{ + public partial class ColorTests + { + [Fact] + public void Equality_WhenTrue() + { + Color c1 = new Rgba64(100, 2000, 3000, 40000); + Color c2 = new Rgba64(100, 2000, 3000, 40000); + + Assert.True(c1.Equals(c2)); + Assert.True(c1 == c2); + Assert.False(c1 != c2); + Assert.True(c1.GetHashCode() == c2.GetHashCode()); + } + + [Fact] + public void Equality_WhenFalse() + { + Color c1 = new Rgba64(100, 2000, 3000, 40000); + Color c2 = new Rgba64(101, 2000, 3000, 40000); + Color c3 = new Rgba64(100, 2000, 3000, 40001); + + Assert.False(c1.Equals(c2)); + Assert.False(c2.Equals(c3)); + Assert.False(c3.Equals(c1)); + + Assert.False(c1 == c2); + Assert.True(c1 != c2); + + Assert.False(c1.Equals(null)); + } + + [Fact] + public void ToHex() + { + string expected = "ABCD1234"; + Color color = Color.FromHex(expected); + string actual = color.ToHex(); + + Assert.Equal(expected, actual); + } + + [Fact] + public void WebSafePalette_IsCorrect() + { + Rgba32[] actualPalette = Color.WebSafePalette.ToArray().Select(c => (Rgba32)c).ToArray(); + Assert.Equal(ReferencePalette.WebSafeColors, actualPalette); + } + + [Fact] + public void WernerPalette_IsCorrect() + { + Rgba32[] actualPalette = Color.WernerPalette.ToArray().Select(c => (Rgba32)c).ToArray(); + Assert.Equal(ReferencePalette.WernerColors, actualPalette); + } + + public class FromHex + { + [Fact] + public void ShortHex() + { + Assert.Equal(new Rgb24(255, 255, 255), (Rgb24) Color.FromHex("#fff")); + Assert.Equal(new Rgb24(255, 255, 255), (Rgb24) Color.FromHex("fff")); + Assert.Equal(new Rgba32(0, 0, 0, 255), (Rgba32) Color.FromHex("000f")); + } + + [Fact] + public void LeadingPoundIsOptional() + { + Assert.Equal(new Rgb24(0, 128, 128), (Rgb24) Color.FromHex("#008080")); + Assert.Equal(new Rgb24(0, 128, 128), (Rgb24) Color.FromHex("008080")); + } + + [Fact] + public void ThrowsOnEmpty() + { + Assert.Throws(() => Color.FromHex("")); + } + + [Fact] + public void ThrowsOnNull() + { + Assert.Throws(() => Color.FromHex(null)); + } + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Color/ReferencePalette.cs b/tests/ImageSharp.Tests/Color/ReferencePalette.cs new file mode 100644 index 0000000000..3c6e382c58 --- /dev/null +++ b/tests/ImageSharp.Tests/Color/ReferencePalette.cs @@ -0,0 +1,277 @@ +// // Copyright (c) Six Labors and contributors. +// // Licensed under the Apache License, Version 2.0. + +using SixLabors.ImageSharp.PixelFormats; + +namespace SixLabors.ImageSharp.Tests +{ + internal static class ReferencePalette + { + /// + /// Gets a collection of named, web safe, colors as defined in the CSS Color Module Level 4. + /// + public static readonly Rgba32[] WebSafeColors = + { + Rgba32.AliceBlue, + Rgba32.AntiqueWhite, + Rgba32.Aqua, + Rgba32.Aquamarine, + Rgba32.Azure, + Rgba32.Beige, + Rgba32.Bisque, + Rgba32.Black, + Rgba32.BlanchedAlmond, + Rgba32.Blue, + Rgba32.BlueViolet, + Rgba32.Brown, + Rgba32.BurlyWood, + Rgba32.CadetBlue, + Rgba32.Chartreuse, + Rgba32.Chocolate, + Rgba32.Coral, + Rgba32.CornflowerBlue, + Rgba32.Cornsilk, + Rgba32.Crimson, + Rgba32.Cyan, + Rgba32.DarkBlue, + Rgba32.DarkCyan, + Rgba32.DarkGoldenrod, + Rgba32.DarkGray, + Rgba32.DarkGreen, + Rgba32.DarkKhaki, + Rgba32.DarkMagenta, + Rgba32.DarkOliveGreen, + Rgba32.DarkOrange, + Rgba32.DarkOrchid, + Rgba32.DarkRed, + Rgba32.DarkSalmon, + Rgba32.DarkSeaGreen, + Rgba32.DarkSlateBlue, + Rgba32.DarkSlateGray, + Rgba32.DarkTurquoise, + Rgba32.DarkViolet, + Rgba32.DeepPink, + Rgba32.DeepSkyBlue, + Rgba32.DimGray, + Rgba32.DodgerBlue, + Rgba32.Firebrick, + Rgba32.FloralWhite, + Rgba32.ForestGreen, + Rgba32.Fuchsia, + Rgba32.Gainsboro, + Rgba32.GhostWhite, + Rgba32.Gold, + Rgba32.Goldenrod, + Rgba32.Gray, + Rgba32.Green, + Rgba32.GreenYellow, + Rgba32.Honeydew, + Rgba32.HotPink, + Rgba32.IndianRed, + Rgba32.Indigo, + Rgba32.Ivory, + Rgba32.Khaki, + Rgba32.Lavender, + Rgba32.LavenderBlush, + Rgba32.LawnGreen, + Rgba32.LemonChiffon, + Rgba32.LightBlue, + Rgba32.LightCoral, + Rgba32.LightCyan, + Rgba32.LightGoldenrodYellow, + Rgba32.LightGray, + Rgba32.LightGreen, + Rgba32.LightPink, + Rgba32.LightSalmon, + Rgba32.LightSeaGreen, + Rgba32.LightSkyBlue, + Rgba32.LightSlateGray, + Rgba32.LightSteelBlue, + Rgba32.LightYellow, + Rgba32.Lime, + Rgba32.LimeGreen, + Rgba32.Linen, + Rgba32.Magenta, + Rgba32.Maroon, + Rgba32.MediumAquamarine, + Rgba32.MediumBlue, + Rgba32.MediumOrchid, + Rgba32.MediumPurple, + Rgba32.MediumSeaGreen, + Rgba32.MediumSlateBlue, + Rgba32.MediumSpringGreen, + Rgba32.MediumTurquoise, + Rgba32.MediumVioletRed, + Rgba32.MidnightBlue, + Rgba32.MintCream, + Rgba32.MistyRose, + Rgba32.Moccasin, + Rgba32.NavajoWhite, + Rgba32.Navy, + Rgba32.OldLace, + Rgba32.Olive, + Rgba32.OliveDrab, + Rgba32.Orange, + Rgba32.OrangeRed, + Rgba32.Orchid, + Rgba32.PaleGoldenrod, + Rgba32.PaleGreen, + Rgba32.PaleTurquoise, + Rgba32.PaleVioletRed, + Rgba32.PapayaWhip, + Rgba32.PeachPuff, + Rgba32.Peru, + Rgba32.Pink, + Rgba32.Plum, + Rgba32.PowderBlue, + Rgba32.Purple, + Rgba32.RebeccaPurple, + Rgba32.Red, + Rgba32.RosyBrown, + Rgba32.RoyalBlue, + Rgba32.SaddleBrown, + Rgba32.Salmon, + Rgba32.SandyBrown, + Rgba32.SeaGreen, + Rgba32.SeaShell, + Rgba32.Sienna, + Rgba32.Silver, + Rgba32.SkyBlue, + Rgba32.SlateBlue, + Rgba32.SlateGray, + Rgba32.Snow, + Rgba32.SpringGreen, + Rgba32.SteelBlue, + Rgba32.Tan, + Rgba32.Teal, + Rgba32.Thistle, + Rgba32.Tomato, + Rgba32.Transparent, + Rgba32.Turquoise, + Rgba32.Violet, + Rgba32.Wheat, + Rgba32.White, + Rgba32.WhiteSmoke, + Rgba32.Yellow, + Rgba32.YellowGreen + }; + + /// + /// Gets a collection of colors as defined in the original second edition of Werner’s Nomenclature of Colours 1821. + /// The hex codes were collected and defined by Nicholas Rougeux + /// + public static readonly Rgba32[] WernerColors = + { + Rgba32.FromHex("#f1e9cd"), + Rgba32.FromHex("#f2e7cf"), + Rgba32.FromHex("#ece6d0"), + Rgba32.FromHex("#f2eacc"), + Rgba32.FromHex("#f3e9ca"), + Rgba32.FromHex("#f2ebcd"), + Rgba32.FromHex("#e6e1c9"), + Rgba32.FromHex("#e2ddc6"), + Rgba32.FromHex("#cbc8b7"), + Rgba32.FromHex("#bfbbb0"), + Rgba32.FromHex("#bebeb3"), + Rgba32.FromHex("#b7b5ac"), + Rgba32.FromHex("#bab191"), + Rgba32.FromHex("#9c9d9a"), + Rgba32.FromHex("#8a8d84"), + Rgba32.FromHex("#5b5c61"), + Rgba32.FromHex("#555152"), + Rgba32.FromHex("#413f44"), + Rgba32.FromHex("#454445"), + Rgba32.FromHex("#423937"), + Rgba32.FromHex("#433635"), + Rgba32.FromHex("#252024"), + Rgba32.FromHex("#241f20"), + Rgba32.FromHex("#281f3f"), + Rgba32.FromHex("#1c1949"), + Rgba32.FromHex("#4f638d"), + Rgba32.FromHex("#383867"), + Rgba32.FromHex("#5c6b8f"), + Rgba32.FromHex("#657abb"), + Rgba32.FromHex("#6f88af"), + Rgba32.FromHex("#7994b5"), + Rgba32.FromHex("#6fb5a8"), + Rgba32.FromHex("#719ba2"), + Rgba32.FromHex("#8aa1a6"), + Rgba32.FromHex("#d0d5d3"), + Rgba32.FromHex("#8590ae"), + Rgba32.FromHex("#3a2f52"), + Rgba32.FromHex("#39334a"), + Rgba32.FromHex("#6c6d94"), + Rgba32.FromHex("#584c77"), + Rgba32.FromHex("#533552"), + Rgba32.FromHex("#463759"), + Rgba32.FromHex("#bfbac0"), + Rgba32.FromHex("#77747f"), + Rgba32.FromHex("#4a475c"), + Rgba32.FromHex("#b8bfaf"), + Rgba32.FromHex("#b2b599"), + Rgba32.FromHex("#979c84"), + Rgba32.FromHex("#5d6161"), + Rgba32.FromHex("#61ac86"), + Rgba32.FromHex("#a4b6a7"), + Rgba32.FromHex("#adba98"), + Rgba32.FromHex("#93b778"), + Rgba32.FromHex("#7d8c55"), + Rgba32.FromHex("#33431e"), + Rgba32.FromHex("#7c8635"), + Rgba32.FromHex("#8e9849"), + Rgba32.FromHex("#c2c190"), + Rgba32.FromHex("#67765b"), + Rgba32.FromHex("#ab924b"), + Rgba32.FromHex("#c8c76f"), + Rgba32.FromHex("#ccc050"), + Rgba32.FromHex("#ebdd99"), + Rgba32.FromHex("#ab9649"), + Rgba32.FromHex("#dbc364"), + Rgba32.FromHex("#e6d058"), + Rgba32.FromHex("#ead665"), + Rgba32.FromHex("#d09b2c"), + Rgba32.FromHex("#a36629"), + Rgba32.FromHex("#a77d35"), + Rgba32.FromHex("#f0d696"), + Rgba32.FromHex("#d7c485"), + Rgba32.FromHex("#f1d28c"), + Rgba32.FromHex("#efcc83"), + Rgba32.FromHex("#f3daa7"), + Rgba32.FromHex("#dfa837"), + Rgba32.FromHex("#ebbc71"), + Rgba32.FromHex("#d17c3f"), + Rgba32.FromHex("#92462f"), + Rgba32.FromHex("#be7249"), + Rgba32.FromHex("#bb603c"), + Rgba32.FromHex("#c76b4a"), + Rgba32.FromHex("#a75536"), + Rgba32.FromHex("#b63e36"), + Rgba32.FromHex("#b5493a"), + Rgba32.FromHex("#cd6d57"), + Rgba32.FromHex("#711518"), + Rgba32.FromHex("#e9c49d"), + Rgba32.FromHex("#eedac3"), + Rgba32.FromHex("#eecfbf"), + Rgba32.FromHex("#ce536b"), + Rgba32.FromHex("#b74a70"), + Rgba32.FromHex("#b7757c"), + Rgba32.FromHex("#612741"), + Rgba32.FromHex("#7a4848"), + Rgba32.FromHex("#3f3033"), + Rgba32.FromHex("#8d746f"), + Rgba32.FromHex("#4d3635"), + Rgba32.FromHex("#6e3b31"), + Rgba32.FromHex("#864735"), + Rgba32.FromHex("#553d3a"), + Rgba32.FromHex("#613936"), + Rgba32.FromHex("#7a4b3a"), + Rgba32.FromHex("#946943"), + Rgba32.FromHex("#c39e6d"), + Rgba32.FromHex("#513e32"), + Rgba32.FromHex("#8b7859"), + Rgba32.FromHex("#9b856b"), + Rgba32.FromHex("#766051"), + Rgba32.FromHex("#453b32") + }; + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Drawing/BeziersTests.cs b/tests/ImageSharp.Tests/Drawing/BeziersTests.cs index 69b2098dc9..cc8f27f3a2 100644 --- a/tests/ImageSharp.Tests/Drawing/BeziersTests.cs +++ b/tests/ImageSharp.Tests/Drawing/BeziersTests.cs @@ -19,8 +19,9 @@ public void ImageShouldBeOverlayedByBezierLine() string path = TestEnvironment.CreateOutputDirectory("Drawing", "BezierLine"); using (var image = new Image(500, 500)) { + image.Mutate(x => x.BackgroundColor(Color.Blue)); image.Mutate( - x => x.BackgroundColor(Rgba32.Blue).DrawBeziers( + x => x.DrawBeziers( Rgba32.HotPink, 5, new SixLabors.Primitives.PointF[] @@ -56,8 +57,9 @@ public void ImageShouldBeOverlayedBezierLineWithOpacity() using (var image = new Image(500, 500)) { + image.Mutate(x => x.BackgroundColor(Color.Blue)); image.Mutate( - x => x.BackgroundColor(Rgba32.Blue).DrawBeziers( + x => x.DrawBeziers( color, 10, new SixLabors.Primitives.PointF[] diff --git a/tests/ImageSharp.Tests/Drawing/DrawImageTest.cs b/tests/ImageSharp.Tests/Drawing/DrawImageTest.cs index ee04d43888..54b04390ec 100644 --- a/tests/ImageSharp.Tests/Drawing/DrawImageTest.cs +++ b/tests/ImageSharp.Tests/Drawing/DrawImageTest.cs @@ -80,7 +80,7 @@ public void ImageShouldDrawTransformedImage(TestImageProvider pr // Apply a background color so we can see the translation. blend.Mutate(x => x.Transform(builder)); - blend.Mutate(x => x.BackgroundColor(NamedColors.HotPink)); + blend.Mutate(x => x.BackgroundColor(Color.HotPink)); // Lets center the matrix so we can tell whether any cut-off issues we may have belong to the drawing processor var position = new Point((image.Width - blend.Width) / 2, (image.Height - blend.Height) / 2); diff --git a/tests/ImageSharp.Tests/Drawing/DrawPathTests.cs b/tests/ImageSharp.Tests/Drawing/DrawPathTests.cs index 0d791fbd23..d2485f334a 100644 --- a/tests/ImageSharp.Tests/Drawing/DrawPathTests.cs +++ b/tests/ImageSharp.Tests/Drawing/DrawPathTests.cs @@ -30,8 +30,9 @@ public void ImageShouldBeOverlayedByPath() new Vector2(10, 400)); var p = new Path(linerSegemnt, bazierSegment); - - image.Mutate(x => x.BackgroundColor(Rgba32.Blue).Draw(Rgba32.HotPink, 5, p)); + + image.Mutate(x => x.BackgroundColor(Rgba32.Blue)); + image.Mutate(x => x.Draw(Rgba32.HotPink, 5, p)); image.Save($"{path}/Simple.png"); Buffer2D sourcePixels = image.GetRootFramePixelBuffer(); @@ -67,7 +68,8 @@ public void ImageShouldBeOverlayedPathWithOpacity() using (var image = new Image(500, 500)) { - image.Mutate(x => x.BackgroundColor(Rgba32.Blue).Draw(color, 10, p)); + image.Mutate(x => x.BackgroundColor(Rgba32.Blue)); + image.Mutate(x => x.Draw(color, 10, p)); image.Save($"{path}/Opacity.png"); //shift background color towards forground color by the opacity amount diff --git a/tests/ImageSharp.Tests/Drawing/LineComplexPolygonTests.cs b/tests/ImageSharp.Tests/Drawing/LineComplexPolygonTests.cs index d827975c72..06961bec4b 100644 --- a/tests/ImageSharp.Tests/Drawing/LineComplexPolygonTests.cs +++ b/tests/ImageSharp.Tests/Drawing/LineComplexPolygonTests.cs @@ -31,7 +31,8 @@ public void ImageShouldBeOverlayedByPolygonOutline() using (var image = new Image(500, 500)) { - image.Mutate(x => x.BackgroundColor(Rgba32.Blue).Draw(Rgba32.HotPink, 5, simplePath.Clip(hole1))); + image.Mutate(x => x.BackgroundColor(Rgba32.Blue)); + image.Mutate(x => x.Draw(Rgba32.HotPink, 5, simplePath.Clip(hole1))); image.Save($"{path}/Simple.png"); Buffer2D sourcePixels = image.GetRootFramePixelBuffer(); @@ -73,7 +74,8 @@ public void ImageShouldBeOverlayedByPolygonOutlineNoOverlapping() using (var image = new Image(500, 500)) { - image.Mutate(x => x.BackgroundColor(Rgba32.Blue).Draw(Rgba32.HotPink, 5, simplePath.Clip(hole1))); + image.Mutate(x => x.BackgroundColor(Rgba32.Blue)); + image.Mutate(x => x.Draw(Rgba32.HotPink, 5, simplePath.Clip(hole1))); image.Save($"{path}/SimpleVanishHole.png"); Buffer2D sourcePixels = image.GetRootFramePixelBuffer(); @@ -113,7 +115,8 @@ public void ImageShouldBeOverlayedByPolygonOutlineOverlapping() using (var image = new Image(500, 500)) { - image.Mutate(x => x.BackgroundColor(Rgba32.Blue).Draw(Rgba32.HotPink, 5, simplePath.Clip(hole1))); + image.Mutate(x => x.BackgroundColor(Rgba32.Blue)); + image.Mutate(x => x.Draw(Rgba32.HotPink, 5, simplePath.Clip(hole1))); image.Save($"{path}/SimpleOverlapping.png"); Buffer2D sourcePixels = image.GetRootFramePixelBuffer(); @@ -147,9 +150,8 @@ public void ImageShouldBeOverlayedByPolygonOutlineDashed() using (var image = new Image(500, 500)) { - image.Mutate(x => x - .BackgroundColor(Rgba32.Blue) - .Draw(Pens.Dash(Rgba32.HotPink, 5), simplePath.Clip(hole1))); + image.Mutate(x => x.BackgroundColor(Rgba32.Blue)); + image.Mutate(x => x.Draw(Pens.Dash(Rgba32.HotPink, 5), simplePath.Clip(hole1))); image.Save($"{path}/Dashed.png"); } } @@ -171,7 +173,8 @@ public void ImageShouldBeOverlayedPolygonOutlineWithOpacity() using (var image = new Image(500, 500)) { - image.Mutate(x => x.BackgroundColor(Rgba32.Blue).Draw(color, 5, simplePath.Clip(hole1))); + image.Mutate(x => x.BackgroundColor(Rgba32.Blue)); + image.Mutate(x => x.Draw(color, 5, simplePath.Clip(hole1))); image.Save($"{path}/Opacity.png"); //shift background color towards forground color by the opacity amount diff --git a/tests/ImageSharp.Tests/Drawing/LineTests.cs b/tests/ImageSharp.Tests/Drawing/LineTests.cs index 43dec547eb..1cc0fd1a40 100644 --- a/tests/ImageSharp.Tests/Drawing/LineTests.cs +++ b/tests/ImageSharp.Tests/Drawing/LineTests.cs @@ -19,8 +19,9 @@ public void ImageShouldBeOverlayedByPath() string path = TestEnvironment.CreateOutputDirectory("Drawing", "Lines"); using (var image = new Image(500, 500)) { + image.Mutate(x => x.BackgroundColor(Rgba32.Blue)); image.Mutate( - x => x.BackgroundColor(Rgba32.Blue).DrawLines( + x => x.DrawLines( Rgba32.HotPink, 5, new Vector2(10, 10), @@ -43,8 +44,9 @@ public void ImageShouldBeOverlayedByPath_NoAntialias() string path = TestEnvironment.CreateOutputDirectory("Drawing", "Lines"); using (var image = new Image(500, 500)) { + image.Mutate(x => x.BackgroundColor(Rgba32.Blue)); image.Mutate( - x => x.BackgroundColor(Rgba32.Blue).DrawLines( + x => x.DrawLines( new GraphicsOptions(false), Rgba32.HotPink, 5, @@ -68,9 +70,8 @@ public void ImageShouldBeOverlayedByPathDashed() string path = TestEnvironment.CreateOutputDirectory("Drawing", "Lines"); using (var image = new Image(500, 500)) { - image.Mutate(x => x - .BackgroundColor(Rgba32.Blue) - .DrawLines(Pens.Dash(Rgba32.HotPink, 5), + image.Mutate(x => x.BackgroundColor(Rgba32.Blue)); + image.Mutate(x => x.DrawLines(Pens.Dash(Rgba32.HotPink, 5), new SixLabors.Primitives.PointF[] { new Vector2(10, 10), new Vector2(200, 150), @@ -86,9 +87,8 @@ public void ImageShouldBeOverlayedByPathDotted() string path = TestEnvironment.CreateOutputDirectory("Drawing", "Lines"); using (var image = new Image(500, 500)) { - image.Mutate(x => x - .BackgroundColor(Rgba32.Blue) - .DrawLines(Pens.Dot(Rgba32.HotPink, 5), + image.Mutate(x => x.BackgroundColor(Rgba32.Blue)); + image.Mutate(x => x.DrawLines(Pens.Dot(Rgba32.HotPink, 5), new SixLabors.Primitives.PointF[] { new Vector2(10, 10), new Vector2(200, 150), @@ -104,9 +104,8 @@ public void ImageShouldBeOverlayedByPathDashDot() string path = TestEnvironment.CreateOutputDirectory("Drawing", "Lines"); using (var image = new Image(500, 500)) { - image.Mutate(x => x - .BackgroundColor(Rgba32.Blue) - .DrawLines(Pens.DashDot(Rgba32.HotPink, 5), + image.Mutate(x => x.BackgroundColor(Rgba32.Blue)); + image.Mutate(x => x.DrawLines(Pens.DashDot(Rgba32.HotPink, 5), new SixLabors.Primitives.PointF[] { new Vector2(10, 10), new Vector2(200, 150), @@ -122,9 +121,9 @@ public void ImageShouldBeOverlayedByPathDashDotDot() string path = TestEnvironment.CreateOutputDirectory("Drawing", "Lines"); var image = new Image(500, 500); - image.Mutate(x => x - .BackgroundColor(Rgba32.Blue) - .DrawLines(Pens.DashDotDot(Rgba32.HotPink, 5), new SixLabors.Primitives.PointF[] { + image.Mutate(x => x.BackgroundColor(Rgba32.Blue)); + image.Mutate(x => x.DrawLines(Pens.DashDotDot(Rgba32.HotPink, 5), + new SixLabors.Primitives.PointF[] { new Vector2(10, 10), new Vector2(200, 150), new Vector2(50, 300) @@ -141,8 +140,9 @@ public void ImageShouldBeOverlayedPathWithOpacity() var image = new Image(500, 500); + image.Mutate(x => x.BackgroundColor(Rgba32.Blue)); image.Mutate( - x => x.BackgroundColor(Rgba32.Blue).DrawLines( + x => x.DrawLines( color, 10, new Vector2(10, 10), @@ -169,8 +169,9 @@ public void ImageShouldBeOverlayedByPathOutline() var image = new Image(500, 500); + image.Mutate(x => x.BackgroundColor(Rgba32.Blue)); image.Mutate( - x => x.BackgroundColor(Rgba32.Blue).DrawLines( + x => x.DrawLines( Rgba32.HotPink, 10, new Vector2(10, 10), diff --git a/tests/ImageSharp.Tests/Drawing/PolygonTests.cs b/tests/ImageSharp.Tests/Drawing/PolygonTests.cs index 6ea9c647f2..febb39c20d 100644 --- a/tests/ImageSharp.Tests/Drawing/PolygonTests.cs +++ b/tests/ImageSharp.Tests/Drawing/PolygonTests.cs @@ -20,8 +20,9 @@ public void ImageShouldBeOverlayedByPolygonOutline() using (Image image = new Image(500, 500)) { + image.Mutate(x => x.BackgroundColor(Rgba32.Blue)); image.Mutate( - x => x.BackgroundColor(Rgba32.Blue).DrawPolygon( + x => x.DrawPolygon( Rgba32.HotPink, 5, new Vector2(10, 10), @@ -54,7 +55,8 @@ public void ImageShouldBeOverlayedPolygonOutlineWithOpacity() using (Image image = new Image(500, 500)) { - image.Mutate(x => x.BackgroundColor(Rgba32.Blue).DrawPolygon(color, 10, simplePath)); + image.Mutate(x => x.BackgroundColor(Rgba32.Blue)); + image.Mutate(x => x.DrawPolygon(color, 10, simplePath)); image.Save($"{path}/Opacity.png"); //shift background color towards forground color by the opacity amount @@ -79,8 +81,9 @@ public void ImageShouldBeOverlayedByRectangleOutline() using (Image image = new Image(500, 500)) { + image.Mutate(x => x.BackgroundColor(Rgba32.Blue)); image.Mutate( - x => x.BackgroundColor(Rgba32.Blue).Draw(Rgba32.HotPink, 10, new Rectangle(10, 10, 190, 140))); + x => x.Draw(Rgba32.HotPink, 10, new Rectangle(10, 10, 190, 140))); image.Save($"{path}/Rectangle.png"); Buffer2D sourcePixels = image.GetRootFramePixelBuffer(); diff --git a/tests/ImageSharp.Tests/Drawing/SolidBezierTests.cs b/tests/ImageSharp.Tests/Drawing/SolidBezierTests.cs index 23acc1a44f..e8f53de010 100644 --- a/tests/ImageSharp.Tests/Drawing/SolidBezierTests.cs +++ b/tests/ImageSharp.Tests/Drawing/SolidBezierTests.cs @@ -24,15 +24,13 @@ public void FilledBezier(TestImageProvider provider) new Vector2(300, 400) }; - TPixel blue = NamedColors.Blue; - TPixel hotPink = NamedColors.HotPink; + Color blue = Color.Blue; + Color hotPink = Color.HotPink; using (Image image = provider.GetImage()) { - - image.Mutate(x => x - .BackgroundColor(blue) - .Fill(hotPink, new Polygon(new CubicBezierLineSegment(simplePath)))); + image.Mutate(x => x.BackgroundColor(blue)); + image.Mutate(x => x.Fill(hotPink.ToPixel(), new Polygon(new CubicBezierLineSegment(simplePath)))); image.DebugSave(provider); image.CompareToReferenceOutput(provider); } @@ -55,9 +53,9 @@ public void OverlayByFilledPolygonOpacity(TestImageProvider prov using (var image = provider.GetImage() as Image) { - image.Mutate(x => x - .BackgroundColor(Rgba32.Blue) - .Fill(color, new Polygon(new CubicBezierLineSegment(simplePath)))); + image.Mutate(x => x.BackgroundColor(Rgba32.Blue)); + + image.Mutate(x => x.Fill(color, new Polygon(new CubicBezierLineSegment(simplePath)))); image.DebugSave(provider); image.CompareToReferenceOutput(provider); } diff --git a/tests/ImageSharp.Tests/Drawing/SolidComplexPolygonTests.cs b/tests/ImageSharp.Tests/Drawing/SolidComplexPolygonTests.cs index 2c9628e842..0e997ad7eb 100644 --- a/tests/ImageSharp.Tests/Drawing/SolidComplexPolygonTests.cs +++ b/tests/ImageSharp.Tests/Drawing/SolidComplexPolygonTests.cs @@ -31,7 +31,8 @@ public void ImageShouldBeOverlayedByPolygonOutline() // var clipped = new Rectangle(10, 10, 100, 100).Clip(new Rectangle(20, 0, 20, 20)); using (var image = new Image(500, 500)) { - image.Mutate(x => x.BackgroundColor(Rgba32.Blue).Fill(Rgba32.HotPink, clipped)); + image.Mutate(x => x.BackgroundColor(Rgba32.Blue)); + image.Mutate(x => x.Fill(Rgba32.HotPink, clipped)); image.Save($"{path}/Simple.png"); Buffer2D sourcePixels = image.GetRootFramePixelBuffer(); @@ -59,7 +60,8 @@ public void ImageShouldBeOverlayedPolygonOutlineWithOverlap() using (var image = new Image(500, 500)) { - image.Mutate(x => x.BackgroundColor(Rgba32.Blue).Fill(Rgba32.HotPink, simplePath.Clip(hole1))); + image.Mutate(x => x.BackgroundColor(Rgba32.Blue)); + image.Mutate(x => x.Fill(Rgba32.HotPink, simplePath.Clip(hole1))); image.Save($"{path}/SimpleOverlapping.png"); Buffer2D sourcePixels = image.GetRootFramePixelBuffer(); @@ -88,7 +90,8 @@ public void ImageShouldBeOverlayedPolygonOutlineWithOpacity() using (var image = new Image(500, 500)) { - image.Mutate(x => x.BackgroundColor(Rgba32.Blue).Fill(color, simplePath.Clip(hole1))); + image.Mutate(x => x.BackgroundColor(Rgba32.Blue)); + image.Mutate(x => x.Fill(color, simplePath.Clip(hole1))); image.Save($"{path}/Opacity.png"); //shift background color towards forground color by the opacity amount diff --git a/tests/ImageSharp.Tests/Drawing/SolidPolygonTests.cs b/tests/ImageSharp.Tests/Drawing/SolidPolygonTests.cs index 5660518eb4..6a299aad7b 100644 --- a/tests/ImageSharp.Tests/Drawing/SolidPolygonTests.cs +++ b/tests/ImageSharp.Tests/Drawing/SolidPolygonTests.cs @@ -68,8 +68,9 @@ public void ImageShouldBeOverlayedByFilledPolygonNoAntialias() using (var image = new Image(500, 500)) { + image.Mutate(x => x.BackgroundColor(Rgba32.Blue)); image.Mutate( - x => x.BackgroundColor(Rgba32.Blue).FillPolygon( + x => x.FillPolygon( new GraphicsOptions(false), Rgba32.HotPink, simplePath)); @@ -101,9 +102,8 @@ public void ImageShouldBeOverlayedByFilledPolygonImage() { var brush = new ImageBrush(brushImage); - image.Mutate(x => x - .BackgroundColor(Rgba32.Blue) - .FillPolygon(brush, simplePath)); + image.Mutate(x => x.BackgroundColor(Rgba32.Blue)); + image.Mutate(x => x.FillPolygon(brush, simplePath)); image.Save($"{path}/Image.png"); } } @@ -121,7 +121,8 @@ public void ImageShouldBeOverlayedByFilledPolygonOpacity() using (var image = new Image(500, 500)) { - image.Mutate(x => x.BackgroundColor(Rgba32.Blue).FillPolygon(color, simplePath)); + image.Mutate(x => x.BackgroundColor(Rgba32.Blue)); + image.Mutate(x => x.FillPolygon(color, simplePath)); image.Save($"{path}/Opacity.png"); //shift background color towards forground color by the opacity amount @@ -140,8 +141,9 @@ public void ImageShouldBeOverlayedByFilledRectangle() using (var image = new Image(500, 500)) { + image.Mutate(x => x.BackgroundColor(Rgba32.Blue)); image.Mutate( - x => x.BackgroundColor(Rgba32.Blue).Fill( + x => x.Fill( Rgba32.HotPink, new SixLabors.Shapes.RectangularPolygon(10, 10, 190, 140))); image.Save($"{path}/Rectangle.png"); @@ -166,8 +168,9 @@ public void ImageShouldBeOverlayedByFilledTriangle() using (var image = new Image(100, 100)) { + image.Mutate(x => x.BackgroundColor(Rgba32.Blue)); image.Mutate( - x => x.BackgroundColor(Rgba32.Blue).Fill(Rgba32.HotPink, new RegularPolygon(50, 50, 3, 30))); + x => x.Fill(Rgba32.HotPink, new RegularPolygon(50, 50, 3, 30))); image.Save($"{path}/Triangle.png"); Buffer2D sourcePixels = image.GetRootFramePixelBuffer(); @@ -186,9 +189,9 @@ public void ImageShouldBeOverlayedByFilledSeptagon() config.MaxDegreeOfParallelism = 1; using (var image = new Image(config, 100, 100)) { - image.Mutate(x => x - .BackgroundColor(Rgba32.Blue) - .Fill(Rgba32.HotPink, new RegularPolygon(50, 50, 7, 30, -(float)Math.PI))); + image.Mutate(x => x.BackgroundColor(Rgba32.Blue)); + image.Mutate(x => x.Fill(Rgba32.HotPink, + new RegularPolygon(50, 50, 7, 30, -(float)Math.PI))); image.Save($"{path}/Septagon.png"); } } @@ -202,8 +205,8 @@ public void ImageShouldBeOverlayedByFilledEllipse() config.MaxDegreeOfParallelism = 1; using (var image = new Image(config, 100, 100)) { + image.Mutate(x => x.BackgroundColor(Rgba32.Blue)); image.Mutate(x => x - .BackgroundColor(Rgba32.Blue) .Fill(Rgba32.HotPink, new EllipsePolygon(50, 50, 30, 50) .Rotate((float)(Math.PI / 3)))); image.Save($"{path}/ellipse.png"); diff --git a/tests/ImageSharp.Tests/Formats/Bmp/BmpEncoderTests.cs b/tests/ImageSharp.Tests/Formats/Bmp/BmpEncoderTests.cs index abf57ed01a..dd76e9443c 100644 --- a/tests/ImageSharp.Tests/Formats/Bmp/BmpEncoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Bmp/BmpEncoderTests.cs @@ -16,7 +16,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Bmp { using static TestImages.Bmp; - public class BmpEncoderTests : FileTestBase + public class BmpEncoderTests { public static readonly TheoryData BitsPerPixel = new TheoryData diff --git a/tests/ImageSharp.Tests/PixelFormats/Rgba64Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Rgba64Tests.cs index 51f80e0e18..55a2dda7a9 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Rgba64Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Rgba64Tests.cs @@ -33,37 +33,50 @@ public void Rgba64_ToVector4() Assert.Equal(Vector4.One, new Rgba64(ushort.MaxValue, ushort.MaxValue, ushort.MaxValue, ushort.MaxValue).ToVector4()); } - [Fact] - public void Rgba64_ToScaledVector4() + [Theory] + [InlineData(ushort.MaxValue, ushort.MaxValue, ushort.MaxValue, ushort.MaxValue)] + [InlineData(0, 0, 0, 0)] + [InlineData(ushort.MaxValue/2, 100, 2222, 33333)] + public void Rgba64_ToScaledVector4(ushort r, ushort g, ushort b, ushort a) { // arrange - var short2 = new Rgba64(ushort.MaxValue, ushort.MaxValue, ushort.MaxValue, ushort.MaxValue); + var short2 = new Rgba64(r, g, b, a); + + float max = ushort.MaxValue; + float rr = r / max; + float gg = g / max; + float bb = b / max; + float aa = a / max; // act Vector4 actual = short2.ToScaledVector4(); // assert - Assert.Equal(1, actual.X); - Assert.Equal(1, actual.Y); - Assert.Equal(1, actual.Z); - Assert.Equal(1, actual.W); + Assert.Equal(rr, actual.X); + Assert.Equal(gg, actual.Y); + Assert.Equal(bb, actual.Z); + Assert.Equal(aa, actual.W); } - [Fact] - public void Rgba64_FromScaledVector4() + [Theory] + [InlineData(ushort.MaxValue, ushort.MaxValue, ushort.MaxValue, ushort.MaxValue)] + [InlineData(0, 0, 0, 0)] + [InlineData(ushort.MaxValue/2, 100, 2222, 33333)] + public void Rgba64_FromScaledVector4(ushort r, ushort g, ushort b, ushort a) { // arrange - var pixel = default(Rgba64); - var short4 = new Rgba64(ushort.MaxValue, ushort.MaxValue, ushort.MaxValue, ushort.MaxValue); - const ulong expected = 0xFFFFFFFFFFFFFFFF; - + + var source = new Rgba64(r, g, b, a); + // act - Vector4 scaled = short4.ToScaledVector4(); - pixel.FromScaledVector4(scaled); - ulong actual = pixel.PackedValue; + Vector4 scaled = source.ToScaledVector4(); + + Rgba64 actual = default; + actual.FromScaledVector4(scaled); + // assert - Assert.Equal(expected, actual); + Assert.Equal(source, actual); } [Fact] @@ -91,6 +104,7 @@ public void Rgba64_ToRgba32() // assert Assert.Equal(expected, actual); } + [Fact] public void Rgba64_FromBgra5551() @@ -108,5 +122,172 @@ public void Rgba64_FromBgra5551() Assert.Equal(expected, rgba.B); Assert.Equal(expected, rgba.A); } + + [Fact] + public void Equality_WhenTrue() + { + Rgba64 c1 = new Rgba64(100, 2000, 3000, 40000); + Rgba64 c2 = new Rgba64(100, 2000, 3000, 40000); + + Assert.True(c1.Equals(c2)); + Assert.True(c1.GetHashCode() == c2.GetHashCode()); + } + + [Fact] + public void Equality_WhenFalse() + { + Rgba64 c1 = new Rgba64(100, 2000, 3000, 40000); + Rgba64 c2 = new Rgba64(101, 2000, 3000, 40000); + Rgba64 c3 = new Rgba64(100, 2000, 3000, 40001); + + Assert.False(c1.Equals(c2)); + Assert.False(c2.Equals(c3)); + Assert.False(c3.Equals(c1)); + } + + [Fact] + public void Rgba64_FromRgba32() + { + var source = new Rgba32(20, 38, 76, 115); + var expected = new Rgba64(5140, 9766, 19532, 29555); + + Rgba64 actual = default; + actual.FromRgba32(source); + + Assert.Equal(expected, actual); + } + + [Fact] + public void ConstructFrom_Rgba32() + { + var expected = new Rgba64(5140, 9766, 19532, 29555); + var source = new Rgba32(20, 38, 76, 115); + Rgba64 actual = new Rgba64(source); + + Assert.Equal(expected, actual); + } + + [Fact] + public void ConstructFrom_Bgra32() + { + var expected = new Rgba64(5140, 9766, 19532, 29555); + var source = new Bgra32(20, 38, 76, 115); + Rgba64 actual = new Rgba64(source); + + Assert.Equal(expected, actual); + } + + [Fact] + public void ConstructFrom_Argb32() + { + var expected = new Rgba64(5140, 9766, 19532, 29555); + var source = new Argb32(20, 38, 76, 115); + Rgba64 actual = new Rgba64(source); + + Assert.Equal(expected, actual); + } + + [Fact] + public void ConstructFrom_Rgb24() + { + var expected = new Rgba64(5140, 9766, 19532, ushort.MaxValue); + var source = new Rgb24(20, 38, 76); + Rgba64 actual = new Rgba64(source); + + Assert.Equal(expected, actual); + } + + [Fact] + public void ConstructFrom_Bgr24() + { + var expected = new Rgba64(5140, 9766, 19532, ushort.MaxValue); + var source = new Bgr24(20, 38, 76); + Rgba64 actual = new Rgba64(source); + + Assert.Equal(expected, actual); + } + + [Fact] + public void ConstructFrom_Vector4() + { + Vector4 source = new Vector4(0f, 0.2f, 0.5f, 1f); + Rgba64 expected = default; + expected.FromScaledVector4(source); + + Rgba64 actual = new Rgba64(source); + + Assert.Equal(expected, actual); + } + + + [Fact] + public void ToRgba32_Retval() + { + // arrange + var source = new Rgba64(5140, 9766, 19532, 29555); + var expected = new Rgba32(20, 38, 76, 115); + + // act + var actual = source.ToRgba32(); + + // assert + Assert.Equal(expected, actual); + } + + [Fact] + public void ToBgra32_Retval() + { + // arrange + var source = new Rgba64(5140, 9766, 19532, 29555); + var expected = new Bgra32(20, 38, 76, 115); + + // act + var actual = source.ToBgra32(); + + // assert + Assert.Equal(expected, actual); + } + + [Fact] + public void ToArgb32_Retval() + { + // arrange + var source = new Rgba64(5140, 9766, 19532, 29555); + var expected = new Argb32(20, 38, 76, 115); + + // act + var actual = source.ToArgb32(); + + // assert + Assert.Equal(expected, actual); + } + + [Fact] + public void ToRgb24_Retval() + { + // arrange + var source = new Rgba64(5140, 9766, 19532, 29555); + var expected = new Rgb24(20, 38, 76); + + // act + var actual = source.ToRgb24(); + + // assert + Assert.Equal(expected, actual); + } + + [Fact] + public void ToBgr24_Retval() + { + // arrange + var source = new Rgba64(5140, 9766, 19532, 29555); + var expected = new Bgr24(20, 38, 76); + + // act + var actual = source.ToBgr24(); + + // assert + Assert.Equal(expected, actual); + } } } diff --git a/tests/ImageSharp.Tests/Processing/Binarization/BinaryDitherTest.cs b/tests/ImageSharp.Tests/Processing/Binarization/BinaryDitherTest.cs index 5f6e825f63..dcbf0ca038 100644 --- a/tests/ImageSharp.Tests/Processing/Binarization/BinaryDitherTest.cs +++ b/tests/ImageSharp.Tests/Processing/Binarization/BinaryDitherTest.cs @@ -25,38 +25,38 @@ public BinaryDitherTest() public void BinaryDither_CorrectProcessor() { this.operations.BinaryDither(this.orderedDither); - BinaryOrderedDitherProcessor p = this.Verify>(); + BinaryOrderedDitherProcessor p = this.Verify(); Assert.Equal(this.orderedDither, p.Dither); - Assert.Equal(NamedColors.White, p.UpperColor); - Assert.Equal(NamedColors.Black, p.LowerColor); + Assert.Equal(Color.White, p.UpperColor); + Assert.Equal(Color.Black, p.LowerColor); } [Fact] public void BinaryDither_rect_CorrectProcessor() { this.operations.BinaryDither(this.orderedDither, this.rect); - BinaryOrderedDitherProcessor p = this.Verify>(this.rect); + BinaryOrderedDitherProcessor p = this.Verify(this.rect); Assert.Equal(this.orderedDither, p.Dither); - Assert.Equal(NamedColors.White, p.UpperColor); - Assert.Equal(NamedColors.Black, p.LowerColor); + Assert.Equal(Color.White, p.UpperColor); + Assert.Equal(Color.Black, p.LowerColor); } [Fact] public void BinaryDither_index_CorrectProcessor() { - this.operations.BinaryDither(this.orderedDither, NamedColors.Yellow, NamedColors.HotPink); - BinaryOrderedDitherProcessor p = this.Verify>(); + this.operations.BinaryDither(this.orderedDither, Color.Yellow, Color.HotPink); + BinaryOrderedDitherProcessor p = this.Verify(); Assert.Equal(this.orderedDither, p.Dither); - Assert.Equal(NamedColors.Yellow, p.UpperColor); - Assert.Equal(NamedColors.HotPink, p.LowerColor); + Assert.Equal(Color.Yellow, p.UpperColor); + Assert.Equal(Color.HotPink, p.LowerColor); } [Fact] public void BinaryDither_index_rect_CorrectProcessor() { - this.operations.BinaryDither(this.orderedDither, NamedColors.Yellow, NamedColors.HotPink, this.rect); - BinaryOrderedDitherProcessor p = this.Verify>(this.rect); + this.operations.BinaryDither(this.orderedDither, Color.Yellow, Color.HotPink, this.rect); + BinaryOrderedDitherProcessor p = this.Verify(this.rect); Assert.Equal(this.orderedDither, p.Dither); - Assert.Equal(NamedColors.HotPink, p.LowerColor); + Assert.Equal(Color.HotPink, p.LowerColor); } @@ -64,44 +64,44 @@ public void BinaryDither_index_rect_CorrectProcessor() public void BinaryDither_ErrorDiffuser_CorrectProcessor() { this.operations.BinaryDiffuse(this.errorDiffuser, .4F); - BinaryErrorDiffusionProcessor p = this.Verify>(); + BinaryErrorDiffusionProcessor p = this.Verify(); Assert.Equal(this.errorDiffuser, p.Diffuser); Assert.Equal(.4F, p.Threshold); - Assert.Equal(NamedColors.White, p.UpperColor); - Assert.Equal(NamedColors.Black, p.LowerColor); + Assert.Equal(Color.White, p.UpperColor); + Assert.Equal(Color.Black, p.LowerColor); } [Fact] public void BinaryDither_ErrorDiffuser_rect_CorrectProcessor() { this.operations.BinaryDiffuse(this.errorDiffuser, .3F, this.rect); - BinaryErrorDiffusionProcessor p = this.Verify>(this.rect); + BinaryErrorDiffusionProcessor p = this.Verify(this.rect); Assert.Equal(this.errorDiffuser, p.Diffuser); Assert.Equal(.3F, p.Threshold); - Assert.Equal(NamedColors.White, p.UpperColor); - Assert.Equal(NamedColors.Black, p.LowerColor); + Assert.Equal(Color.White, p.UpperColor); + Assert.Equal(Color.Black, p.LowerColor); } [Fact] public void BinaryDither_ErrorDiffuser_CorrectProcessorWithColors() { - this.operations.BinaryDiffuse(this.errorDiffuser, .5F, NamedColors.HotPink, NamedColors.Yellow); - BinaryErrorDiffusionProcessor p = this.Verify>(); + this.operations.BinaryDiffuse(this.errorDiffuser, .5F, Color.HotPink, Color.Yellow); + BinaryErrorDiffusionProcessor p = this.Verify(); Assert.Equal(this.errorDiffuser, p.Diffuser); Assert.Equal(.5F, p.Threshold); - Assert.Equal(NamedColors.HotPink, p.UpperColor); - Assert.Equal(NamedColors.Yellow, p.LowerColor); + Assert.Equal(Color.HotPink, p.UpperColor); + Assert.Equal(Color.Yellow, p.LowerColor); } [Fact] public void BinaryDither_ErrorDiffuser_rect_CorrectProcessorWithColors() { - this.operations.BinaryDiffuse(this.errorDiffuser, .5F, NamedColors.HotPink, NamedColors.Yellow, this.rect); - BinaryErrorDiffusionProcessor p = this.Verify>(this.rect); + this.operations.BinaryDiffuse(this.errorDiffuser, .5F, Color.HotPink, Color.Yellow, this.rect); + BinaryErrorDiffusionProcessor p = this.Verify(this.rect); Assert.Equal(this.errorDiffuser, p.Diffuser); Assert.Equal(.5F, p.Threshold); - Assert.Equal(NamedColors.HotPink, p.UpperColor); - Assert.Equal(NamedColors.Yellow, p.LowerColor); + Assert.Equal(Color.HotPink, p.UpperColor); + Assert.Equal(Color.Yellow, p.LowerColor); } } } \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Processing/Binarization/BinaryThresholdTest.cs b/tests/ImageSharp.Tests/Processing/Binarization/BinaryThresholdTest.cs index 569c4ba217..f0fcba1815 100644 --- a/tests/ImageSharp.Tests/Processing/Binarization/BinaryThresholdTest.cs +++ b/tests/ImageSharp.Tests/Processing/Binarization/BinaryThresholdTest.cs @@ -15,40 +15,40 @@ public class BinaryThresholdTest : BaseImageOperationsExtensionTest public void BinaryThreshold_CorrectProcessor() { this.operations.BinaryThreshold(.23f); - BinaryThresholdProcessor p = this.Verify>(); + BinaryThresholdProcessor p = this.Verify(); Assert.Equal(.23f, p.Threshold); - Assert.Equal(NamedColors.White, p.UpperColor); - Assert.Equal(NamedColors.Black, p.LowerColor); + Assert.Equal(Color.White, p.UpperColor); + Assert.Equal(Color.Black, p.LowerColor); } [Fact] public void BinaryThreshold_rect_CorrectProcessor() { this.operations.BinaryThreshold(.93f, this.rect); - BinaryThresholdProcessor p = this.Verify>(this.rect); + BinaryThresholdProcessor p = this.Verify(this.rect); Assert.Equal(.93f, p.Threshold); - Assert.Equal(NamedColors.White, p.UpperColor); - Assert.Equal(NamedColors.Black, p.LowerColor); + Assert.Equal(Color.White, p.UpperColor); + Assert.Equal(Color.Black, p.LowerColor); } [Fact] public void BinaryThreshold_CorrectProcessorWithUpperLower() { - this.operations.BinaryThreshold(.23f, NamedColors.HotPink, NamedColors.Yellow); - BinaryThresholdProcessor p = this.Verify>(); + this.operations.BinaryThreshold(.23f, Color.HotPink, Color.Yellow); + BinaryThresholdProcessor p = this.Verify(); Assert.Equal(.23f, p.Threshold); - Assert.Equal(NamedColors.HotPink, p.UpperColor); - Assert.Equal(NamedColors.Yellow, p.LowerColor); + Assert.Equal(Color.HotPink, p.UpperColor); + Assert.Equal(Color.Yellow, p.LowerColor); } [Fact] public void BinaryThreshold_rect_CorrectProcessorWithUpperLower() { - this.operations.BinaryThreshold(.93f, NamedColors.HotPink, NamedColors.Yellow, this.rect); - BinaryThresholdProcessor p = this.Verify>(this.rect); + this.operations.BinaryThreshold(.93f, Color.HotPink, Color.Yellow, this.rect); + BinaryThresholdProcessor p = this.Verify(this.rect); Assert.Equal(.93f, p.Threshold); - Assert.Equal(NamedColors.HotPink, p.UpperColor); - Assert.Equal(NamedColors.Yellow, p.LowerColor); + Assert.Equal(Color.HotPink, p.UpperColor); + Assert.Equal(Color.Yellow, p.LowerColor); } } } \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Processing/Dithering/DitherTest.cs b/tests/ImageSharp.Tests/Processing/Dithering/DitherTest.cs index f393d5923d..d91688cd2c 100644 --- a/tests/ImageSharp.Tests/Processing/Dithering/DitherTest.cs +++ b/tests/ImageSharp.Tests/Processing/Dithering/DitherTest.cs @@ -1,6 +1,8 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. +using System; + using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Processing; using SixLabors.ImageSharp.Processing.Dithering; @@ -12,13 +14,21 @@ namespace SixLabors.ImageSharp.Tests.Processing.Binarization { public class DitherTest : BaseImageOperationsExtensionTest { + private class Assert : Xunit.Assert + { + public static void Equal(ReadOnlySpan a, ReadOnlySpan b) + { + Xunit.Assert.True(a.SequenceEqual(b)); + } + } + private readonly IOrderedDither orderedDither; private readonly IErrorDiffuser errorDiffuser; - private readonly Rgba32[] TestPalette = + private readonly Color[] TestPalette = { - Rgba32.Red, - Rgba32.Green, - Rgba32.Blue + Color.Red, + Color.Green, + Color.Blue }; public DitherTest() @@ -31,24 +41,24 @@ public DitherTest() public void Dither_CorrectProcessor() { this.operations.Dither(this.orderedDither); - OrderedDitherPaletteProcessor p = this.Verify>(); + OrderedDitherPaletteProcessor p = this.Verify(); Assert.Equal(this.orderedDither, p.Dither); - Assert.Equal(NamedColors.WebSafePalette, p.Palette); + Assert.Equal(Color.WebSafePalette, p.Palette); } [Fact] public void Dither_rect_CorrectProcessor() { this.operations.Dither(this.orderedDither, this.rect); - OrderedDitherPaletteProcessor p = this.Verify>(this.rect); + OrderedDitherPaletteProcessor p = this.Verify(this.rect); Assert.Equal(this.orderedDither, p.Dither); - Assert.Equal(NamedColors.WebSafePalette, p.Palette); + Assert.Equal(Color.WebSafePalette, p.Palette); } [Fact] public void Dither_index_CorrectProcessor() { this.operations.Dither(this.orderedDither, this.TestPalette); - OrderedDitherPaletteProcessor p = this.Verify>(); + OrderedDitherPaletteProcessor p = this.Verify(); Assert.Equal(this.orderedDither, p.Dither); Assert.Equal(this.TestPalette, p.Palette); } @@ -57,7 +67,7 @@ public void Dither_index_CorrectProcessor() public void Dither_index_rect_CorrectProcessor() { this.operations.Dither(this.orderedDither, this.TestPalette, this.rect); - OrderedDitherPaletteProcessor p = this.Verify>(this.rect); + OrderedDitherPaletteProcessor p = this.Verify(this.rect); Assert.Equal(this.orderedDither, p.Dither); Assert.Equal(this.TestPalette, p.Palette); } @@ -67,27 +77,27 @@ public void Dither_index_rect_CorrectProcessor() public void Dither_ErrorDiffuser_CorrectProcessor() { this.operations.Diffuse(this.errorDiffuser, .4F); - ErrorDiffusionPaletteProcessor p = this.Verify>(); + ErrorDiffusionPaletteProcessor p = this.Verify(); Assert.Equal(this.errorDiffuser, p.Diffuser); Assert.Equal(.4F, p.Threshold); - Assert.Equal(NamedColors.WebSafePalette, p.Palette); + Assert.Equal(Color.WebSafePalette, p.Palette); } [Fact] public void Dither_ErrorDiffuser_rect_CorrectProcessor() { this.operations.Diffuse(this.errorDiffuser, .3F, this.rect); - ErrorDiffusionPaletteProcessor p = this.Verify>(this.rect); + ErrorDiffusionPaletteProcessor p = this.Verify(this.rect); Assert.Equal(this.errorDiffuser, p.Diffuser); Assert.Equal(.3F, p.Threshold); - Assert.Equal(NamedColors.WebSafePalette, p.Palette); + Assert.Equal(Color.WebSafePalette, p.Palette); } [Fact] public void Dither_ErrorDiffuser_CorrectProcessorWithColors() { this.operations.Diffuse(this.errorDiffuser, .5F, this.TestPalette); - ErrorDiffusionPaletteProcessor p = this.Verify>(); + ErrorDiffusionPaletteProcessor p = this.Verify(); Assert.Equal(this.errorDiffuser, p.Diffuser); Assert.Equal(.5F, p.Threshold); Assert.Equal(this.TestPalette, p.Palette); @@ -97,7 +107,7 @@ public void Dither_ErrorDiffuser_CorrectProcessorWithColors() public void Dither_ErrorDiffuser_rect_CorrectProcessorWithColors() { this.operations.Diffuse(this.errorDiffuser, .5F, this.TestPalette, this.rect); - ErrorDiffusionPaletteProcessor p = this.Verify>(this.rect); + ErrorDiffusionPaletteProcessor p = this.Verify(this.rect); Assert.Equal(this.errorDiffuser, p.Diffuser); Assert.Equal(.5F, p.Threshold); Assert.Equal(this.TestPalette, p.Palette); diff --git a/tests/ImageSharp.Tests/Processing/Effects/BackgroundColorTest.cs b/tests/ImageSharp.Tests/Processing/Effects/BackgroundColorTest.cs index 7775de2d24..14758958f0 100644 --- a/tests/ImageSharp.Tests/Processing/Effects/BackgroundColorTest.cs +++ b/tests/ImageSharp.Tests/Processing/Effects/BackgroundColorTest.cs @@ -14,41 +14,41 @@ public class BackgroundColorTest : BaseImageOperationsExtensionTest [Fact] public void BackgroundColor_amount_BackgroundColorProcessorDefaultsSet() { - this.operations.BackgroundColor(Rgba32.BlanchedAlmond); - var processor = this.Verify>(); + this.operations.BackgroundColor(Color.BlanchedAlmond); + var processor = this.Verify(); Assert.Equal(GraphicsOptions.Default, processor.GraphicsOptions); - Assert.Equal(Rgba32.BlanchedAlmond, processor.Color); + Assert.Equal(Color.BlanchedAlmond, processor.Color); } [Fact] public void BackgroundColor_amount_rect_BackgroundColorProcessorDefaultsSet() { - this.operations.BackgroundColor(Rgba32.BlanchedAlmond, this.rect); - var processor = this.Verify>(this.rect); + this.operations.BackgroundColor(Color.BlanchedAlmond, this.rect); + var processor = this.Verify(this.rect); Assert.Equal(GraphicsOptions.Default, processor.GraphicsOptions); - Assert.Equal(Rgba32.BlanchedAlmond, processor.Color); + Assert.Equal(Color.BlanchedAlmond, processor.Color); } [Fact] public void BackgroundColor_amount_options_BackgroundColorProcessorDefaultsSet() { - this.operations.BackgroundColor(this.options, Rgba32.BlanchedAlmond); - var processor = this.Verify>(); + this.operations.BackgroundColor(this.options, Color.BlanchedAlmond); + var processor = this.Verify(); Assert.Equal(this.options, processor.GraphicsOptions); - Assert.Equal(Rgba32.BlanchedAlmond, processor.Color); + Assert.Equal(Color.BlanchedAlmond, processor.Color); } [Fact] public void BackgroundColor_amount_rect_options_BackgroundColorProcessorDefaultsSet() { - this.operations.BackgroundColor(this.options, Rgba32.BlanchedAlmond, this.rect); - var processor = this.Verify>(this.rect); + this.operations.BackgroundColor(this.options, Color.BlanchedAlmond, this.rect); + var processor = this.Verify(this.rect); Assert.Equal(this.options, processor.GraphicsOptions); - Assert.Equal(Rgba32.BlanchedAlmond, processor.Color); + Assert.Equal(Color.BlanchedAlmond, processor.Color); } } } \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Processing/Overlays/GlowTest.cs b/tests/ImageSharp.Tests/Processing/Overlays/GlowTest.cs index 899082e361..0301f5c039 100644 --- a/tests/ImageSharp.Tests/Processing/Overlays/GlowTest.cs +++ b/tests/ImageSharp.Tests/Processing/Overlays/GlowTest.cs @@ -18,10 +18,10 @@ public class GlowTest : BaseImageOperationsExtensionTest public void Glow_GlowProcessorWithDefaultValues() { this.operations.Glow(); - var p = this.Verify>(); + var p = this.Verify(); Assert.Equal(GraphicsOptions.Default, p.GraphicsOptions); - Assert.Equal(Rgba32.Black, p.GlowColor); + Assert.Equal(Color.Black, p.GlowColor); Assert.Equal(ValueSize.PercentageOfWidth(.5f), p.Radius); } @@ -29,10 +29,10 @@ public void Glow_GlowProcessorWithDefaultValues() public void Glow_Color_GlowProcessorWithDefaultValues() { this.operations.Glow(Rgba32.Aquamarine); - var p = this.Verify>(); + var p = this.Verify(); Assert.Equal(GraphicsOptions.Default, p.GraphicsOptions); - Assert.Equal(Rgba32.Aquamarine, p.GlowColor); + Assert.Equal(Color.Aquamarine, p.GlowColor); Assert.Equal(ValueSize.PercentageOfWidth(.5f), p.Radius); } @@ -40,10 +40,10 @@ public void Glow_Color_GlowProcessorWithDefaultValues() public void Glow_Radux_GlowProcessorWithDefaultValues() { this.operations.Glow(3.5f); - var p = this.Verify>(); + var p = this.Verify(); Assert.Equal(GraphicsOptions.Default, p.GraphicsOptions); - Assert.Equal(Rgba32.Black, p.GlowColor); + Assert.Equal(Color.Black, p.GlowColor); Assert.Equal(ValueSize.Absolute(3.5f), p.Radius); } @@ -52,10 +52,10 @@ public void Glow_Rect_GlowProcessorWithDefaultValues() { var rect = new Rectangle(12, 123, 43, 65); this.operations.Glow(rect); - var p = this.Verify>(rect); + var p = this.Verify(rect); Assert.Equal(GraphicsOptions.Default, p.GraphicsOptions); - Assert.Equal(Rgba32.Black, p.GlowColor); + Assert.Equal(Color.Black, p.GlowColor); Assert.Equal(ValueSize.PercentageOfWidth(.5f), p.Radius); } } diff --git a/tests/ImageSharp.Tests/Processing/Overlays/VignetteTest.cs b/tests/ImageSharp.Tests/Processing/Overlays/VignetteTest.cs index f47bffe26f..2538aa137c 100644 --- a/tests/ImageSharp.Tests/Processing/Overlays/VignetteTest.cs +++ b/tests/ImageSharp.Tests/Processing/Overlays/VignetteTest.cs @@ -16,10 +16,10 @@ public class VignetteTest : BaseImageOperationsExtensionTest public void Vignette_VignetteProcessorWithDefaultValues() { this.operations.Vignette(); - var p = this.Verify>(); + var p = this.Verify(); Assert.Equal(GraphicsOptions.Default, p.GraphicsOptions); - Assert.Equal(Rgba32.Black, p.VignetteColor); + Assert.Equal(Color.Black, p.VignetteColor); Assert.Equal(ValueSize.PercentageOfWidth(.5f), p.RadiusX); Assert.Equal(ValueSize.PercentageOfHeight(.5f), p.RadiusY); } @@ -27,11 +27,11 @@ public void Vignette_VignetteProcessorWithDefaultValues() [Fact] public void Vignette_Color_VignetteProcessorWithDefaultValues() { - this.operations.Vignette(Rgba32.Aquamarine); - var p = this.Verify>(); + this.operations.Vignette(Color.Aquamarine); + var p = this.Verify(); Assert.Equal(GraphicsOptions.Default, p.GraphicsOptions); - Assert.Equal(Rgba32.Aquamarine, p.VignetteColor); + Assert.Equal(Color.Aquamarine, p.VignetteColor); Assert.Equal(ValueSize.PercentageOfWidth(.5f), p.RadiusX); Assert.Equal(ValueSize.PercentageOfHeight(.5f), p.RadiusY); } @@ -40,10 +40,10 @@ public void Vignette_Color_VignetteProcessorWithDefaultValues() public void Vignette_Radux_VignetteProcessorWithDefaultValues() { this.operations.Vignette(3.5f, 12123f); - var p = this.Verify>(); + var p = this.Verify(); Assert.Equal(GraphicsOptions.Default, p.GraphicsOptions); - Assert.Equal(Rgba32.Black, p.VignetteColor); + Assert.Equal(Color.Black, p.VignetteColor); Assert.Equal(ValueSize.Absolute(3.5f), p.RadiusX); Assert.Equal(ValueSize.Absolute(12123f), p.RadiusY); } @@ -53,10 +53,10 @@ public void Vignette_Rect_VignetteProcessorWithDefaultValues() { var rect = new Rectangle(12, 123, 43, 65); this.operations.Vignette(rect); - var p = this.Verify>(rect); + var p = this.Verify(rect); Assert.Equal(GraphicsOptions.Default, p.GraphicsOptions); - Assert.Equal(Rgba32.Black, p.VignetteColor); + Assert.Equal(Color.Black, p.VignetteColor); Assert.Equal(ValueSize.PercentageOfWidth(.5f), p.RadiusX); Assert.Equal(ValueSize.PercentageOfHeight(.5f), p.RadiusY); } diff --git a/tests/ImageSharp.Tests/Processing/Processors/Effects/BackgroundColorTest.cs b/tests/ImageSharp.Tests/Processing/Processors/Effects/BackgroundColorTest.cs index d7f77c9565..dc6ff6f3eb 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Effects/BackgroundColorTest.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Effects/BackgroundColorTest.cs @@ -24,7 +24,7 @@ public class BackgroundColorTest public void FullImage(TestImageProvider provider) where TPixel : struct, IPixel { - provider.RunValidatingProcessorTest(x => x.BackgroundColor(NamedColors.HotPink)); + provider.RunValidatingProcessorTest(x => x.BackgroundColor(Color.HotPink)); } [Theory] @@ -33,7 +33,7 @@ public void InBox(TestImageProvider provider) where TPixel : struct, IPixel { provider.RunRectangleConstrainedValidatingProcessorTest( - (x, rect) => x.BackgroundColor(NamedColors.HotPink, rect)); + (x, rect) => x.BackgroundColor(Color.HotPink, rect)); } } } \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Processing/Processors/Overlays/GlowTest.cs b/tests/ImageSharp.Tests/Processing/Processors/Overlays/GlowTest.cs index 113c13b8ae..27aeb4b053 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Overlays/GlowTest.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Overlays/GlowTest.cs @@ -13,11 +13,11 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Overlays [GroupOutput("Overlays")] public class GlowTest : OverlayTestBase { - protected override void Apply(IImageProcessingContext ctx, T color) => ctx.Glow(color); + protected override void Apply(IImageProcessingContext ctx, Color color) => ctx.Glow(color); - protected override void Apply(IImageProcessingContext ctx, float radiusX, float radiusY) => + protected override void Apply(IImageProcessingContext ctx, float radiusX, float radiusY) => ctx.Glow(radiusX); - protected override void Apply(IImageProcessingContext ctx, Rectangle rect) => ctx.Glow(rect); + protected override void Apply(IImageProcessingContext ctx, Rectangle rect) => ctx.Glow(rect); } } \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Processing/Processors/Overlays/OverlayTestBase.cs b/tests/ImageSharp.Tests/Processing/Processors/Overlays/OverlayTestBase.cs index d2abcd7312..788f7e1ade 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Overlays/OverlayTestBase.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Overlays/OverlayTestBase.cs @@ -27,8 +27,8 @@ public void FullImage_ApplyColor(TestImageProvider provider, str where TPixel : struct, IPixel { provider.Utility.TestGroupName = this.GetType().Name; - var f = (FieldInfo)typeof(NamedColors).GetMember(colorName)[0]; - TPixel color = (TPixel)f.GetValue(null); + var f = (FieldInfo)typeof(Color).GetMember(colorName)[0]; + Color color = (Color)f.GetValue(null); provider.RunValidatingProcessorTest(x => this.Apply(x, color), colorName, ValidatorComparer, appendPixelTypeToFileName: false); } @@ -58,13 +58,10 @@ public void InBox(TestImageProvider provider) provider.RunRectangleConstrainedValidatingProcessorTest((x, rect) => this.Apply(x, rect)); } - protected abstract void Apply(IImageProcessingContext ctx, T color) - where T : struct, IPixel; + protected abstract void Apply(IImageProcessingContext ctx, Color color); - protected abstract void Apply(IImageProcessingContext ctx, float radiusX, float radiusY) - where T : struct, IPixel; + protected abstract void Apply(IImageProcessingContext ctx, float radiusX, float radiusY); - protected abstract void Apply(IImageProcessingContext ctx, Rectangle rect) - where T : struct, IPixel; + protected abstract void Apply(IImageProcessingContext ctx, Rectangle rect); } } \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Processing/Processors/Overlays/VignetteTest.cs b/tests/ImageSharp.Tests/Processing/Processors/Overlays/VignetteTest.cs index ad04a827db..9448feefe2 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Overlays/VignetteTest.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Overlays/VignetteTest.cs @@ -9,11 +9,11 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Overlays [GroupOutput("Overlays")] public class VignetteTest : OverlayTestBase { - protected override void Apply(IImageProcessingContext ctx, T color) => ctx.Vignette(color); + protected override void Apply(IImageProcessingContext ctx, Color color) => ctx.Vignette(color); - protected override void Apply(IImageProcessingContext ctx, float radiusX, float radiusY) => + protected override void Apply(IImageProcessingContext ctx, float radiusX, float radiusY) => ctx.Vignette(radiusX, radiusY); - protected override void Apply(IImageProcessingContext ctx, Rectangle rect) => ctx.Vignette(rect); + protected override void Apply(IImageProcessingContext ctx, Rectangle rect) => ctx.Vignette(rect); } } \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Processing/Processors/Quantization/PaletteQuantizerTests.cs b/tests/ImageSharp.Tests/Processing/Processors/Quantization/PaletteQuantizerTests.cs index a4e6edd53e..05ce700476 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Quantization/PaletteQuantizerTests.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Quantization/PaletteQuantizerTests.cs @@ -11,21 +11,21 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Quantization { public class PaletteQuantizerTests { - private static readonly Rgba32[] Rgb = new Rgba32[] { Rgba32.Red, Rgba32.Green, Rgba32.Blue }; + private static readonly Color[] Rgb = new Color[] { Rgba32.Red, Rgba32.Green, Rgba32.Blue }; [Fact] public void PaletteQuantizerConstructor() { - var quantizer = new PaletteQuantizer(Rgb); + var quantizer = new PaletteQuantizer(Rgb); Assert.Equal(Rgb, quantizer.Palette); Assert.Equal(KnownDiffusers.FloydSteinberg, quantizer.Diffuser); - quantizer = new PaletteQuantizer(Rgb, false); + quantizer = new PaletteQuantizer(Rgb, false); Assert.Equal(Rgb, quantizer.Palette); Assert.Null(quantizer.Diffuser); - quantizer = new PaletteQuantizer(Rgb, KnownDiffusers.Atkinson); + quantizer = new PaletteQuantizer(Rgb, KnownDiffusers.Atkinson); Assert.Equal(Rgb, quantizer.Palette); Assert.Equal(KnownDiffusers.Atkinson, quantizer.Diffuser); } @@ -33,35 +33,27 @@ public void PaletteQuantizerConstructor() [Fact] public void PaletteQuantizerCanCreateFrameQuantizer() { - var quantizer = new PaletteQuantizer(Rgb); - IFrameQuantizer frameQuantizer = quantizer.CreateFrameQuantizer(Configuration.Default); + var quantizer = new PaletteQuantizer(Rgb); + IFrameQuantizer frameQuantizer = quantizer.CreateFrameQuantizer(Configuration.Default); Assert.NotNull(frameQuantizer); Assert.True(frameQuantizer.Dither); Assert.Equal(KnownDiffusers.FloydSteinberg, frameQuantizer.Diffuser); - quantizer = new PaletteQuantizer(Rgb, false); - frameQuantizer = quantizer.CreateFrameQuantizer(Configuration.Default); + quantizer = new PaletteQuantizer(Rgb, false); + frameQuantizer = quantizer.CreateFrameQuantizer(Configuration.Default); Assert.NotNull(frameQuantizer); Assert.False(frameQuantizer.Dither); Assert.Null(frameQuantizer.Diffuser); - quantizer = new PaletteQuantizer(Rgb, KnownDiffusers.Atkinson); - frameQuantizer = quantizer.CreateFrameQuantizer(Configuration.Default); + quantizer = new PaletteQuantizer(Rgb, KnownDiffusers.Atkinson); + frameQuantizer = quantizer.CreateFrameQuantizer(Configuration.Default); Assert.NotNull(frameQuantizer); Assert.True(frameQuantizer.Dither); Assert.Equal(KnownDiffusers.Atkinson, frameQuantizer.Diffuser); } - [Fact] - public void PaletteQuantizerThrowsOnInvalidGenericMethodCall() - { - var quantizer = new PaletteQuantizer(Rgb); - - Assert.Throws(() => ((IQuantizer)quantizer).CreateFrameQuantizer(Configuration.Default)); - } - [Fact] public void KnownQuantizersWebSafeTests() { diff --git a/tests/ImageSharp.Tests/Quantization/QuantizedImageTests.cs b/tests/ImageSharp.Tests/Quantization/QuantizedImageTests.cs index a0d7869e39..04e9803af4 100644 --- a/tests/ImageSharp.Tests/Quantization/QuantizedImageTests.cs +++ b/tests/ImageSharp.Tests/Quantization/QuantizedImageTests.cs @@ -1,6 +1,8 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. +using System; + using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Processing.Processors.Quantization; @@ -47,7 +49,7 @@ public void OctreeQuantizerYieldsCorrectTransparentPixel( foreach (ImageFrame frame in image.Frames) { - QuantizedFrame quantized = + IQuantizedFrame quantized = quantizer.CreateFrameQuantizer(this.Configuration).QuantizeFrame(frame); int index = this.GetTransparentIndex(quantized); @@ -70,7 +72,7 @@ public void WuQuantizerYieldsCorrectTransparentPixel(TestImageProvider frame in image.Frames) { - QuantizedFrame quantized = + IQuantizedFrame quantized = quantizer.CreateFrameQuantizer(this.Configuration).QuantizeFrame(frame); int index = this.GetTransparentIndex(quantized); @@ -79,15 +81,16 @@ public void WuQuantizerYieldsCorrectTransparentPixel(TestImageProvider(QuantizedFrame quantized) + private int GetTransparentIndex(IQuantizedFrame quantized) where TPixel : struct, IPixel { // Transparent pixels are much more likely to be found at the end of a palette int index = -1; Rgba32 trans = default; - for (int i = quantized.Palette.Length - 1; i >= 0; i--) + ReadOnlySpan paletteSpan = quantized.Palette.Span; + for (int i = paletteSpan.Length - 1; i >= 0; i--) { - quantized.Palette[i].ToRgba32(ref trans); + paletteSpan[i].ToRgba32(ref trans); if (trans.Equals(default)) { diff --git a/tests/ImageSharp.Tests/Quantization/WuQuantizerTests.cs b/tests/ImageSharp.Tests/Quantization/WuQuantizerTests.cs index 3eacd74ea1..a1de7fd4b9 100644 --- a/tests/ImageSharp.Tests/Quantization/WuQuantizerTests.cs +++ b/tests/ImageSharp.Tests/Quantization/WuQuantizerTests.cs @@ -15,12 +15,12 @@ public void SinglePixelOpaque() var quantizer = new WuQuantizer(false); using (var image = new Image(config, 1, 1, Rgba32.Black)) - using (QuantizedFrame result = quantizer.CreateFrameQuantizer(config).QuantizeFrame(image.Frames[0])) + using (IQuantizedFrame result = quantizer.CreateFrameQuantizer(config).QuantizeFrame(image.Frames[0])) { Assert.Equal(1, result.Palette.Length); Assert.Equal(1, result.GetPixelSpan().Length); - Assert.Equal(Rgba32.Black, result.Palette[0]); + Assert.Equal(Rgba32.Black, result.Palette.Span[0]); Assert.Equal(0, result.GetPixelSpan()[0]); } } @@ -32,12 +32,12 @@ public void SinglePixelTransparent() var quantizer = new WuQuantizer(false); using (var image = new Image(config, 1, 1, default(Rgba32))) - using (QuantizedFrame result = quantizer.CreateFrameQuantizer(config).QuantizeFrame(image.Frames[0])) + using (IQuantizedFrame result = quantizer.CreateFrameQuantizer(config).QuantizeFrame(image.Frames[0])) { Assert.Equal(1, result.Palette.Length); Assert.Equal(1, result.GetPixelSpan().Length); - Assert.Equal(default, result.Palette[0]); + Assert.Equal(default, result.Palette.Span[0]); Assert.Equal(0, result.GetPixelSpan()[0]); } } @@ -75,13 +75,14 @@ public void Palette256() Configuration config = Configuration.Default; var quantizer = new WuQuantizer(false); using (IFrameQuantizer frameQuantizer = quantizer.CreateFrameQuantizer(config)) - using (QuantizedFrame result = frameQuantizer.QuantizeFrame(image.Frames[0])) + using (IQuantizedFrame result = frameQuantizer.QuantizeFrame(image.Frames[0])) { Assert.Equal(256, result.Palette.Length); Assert.Equal(256, result.GetPixelSpan().Length); var actualImage = new Image(1, 256); + ReadOnlySpan paletteSpan = result.Palette.Span; int paletteCount = result.Palette.Length - 1; for (int y = 0; y < actualImage.Height; y++) { @@ -92,7 +93,7 @@ public void Palette256() for (int x = 0; x < actualImage.Width; x++) { int i = x + yy; - row[x] = result.Palette[Math.Min(paletteCount, quantizedPixelSpan[i])]; + row[x] = paletteSpan[Math.Min(paletteCount, quantizedPixelSpan[i])]; } } @@ -112,7 +113,7 @@ public void LowVariance(TestImageProvider provider) Configuration config = Configuration.Default; var quantizer = new WuQuantizer(false); using (IFrameQuantizer frameQuantizer = quantizer.CreateFrameQuantizer(config)) - using (QuantizedFrame result = frameQuantizer.QuantizeFrame(image.Frames[0])) + using (IQuantizedFrame result = frameQuantizer.QuantizeFrame(image.Frames[0])) { Assert.Equal(48, result.Palette.Length); } @@ -141,11 +142,12 @@ private static void TestScale(Func pixelBuilder) var quantizer = new WuQuantizer(false); using (IFrameQuantizer frameQuantizer = quantizer.CreateFrameQuantizer(config)) - using (QuantizedFrame result = frameQuantizer.QuantizeFrame(image.Frames[0])) + using (IQuantizedFrame result = frameQuantizer.QuantizeFrame(image.Frames[0])) { Assert.Equal(4 * 8, result.Palette.Length); Assert.Equal(256, result.GetPixelSpan().Length); + ReadOnlySpan paletteSpan = result.Palette.Span; int paletteCount = result.Palette.Length - 1; for (int y = 0; y < actualImage.Height; y++) { @@ -156,7 +158,7 @@ private static void TestScale(Func pixelBuilder) for (int x = 0; x < actualImage.Width; x++) { int i = x + yy; - row[x] = result.Palette[Math.Min(paletteCount, quantizedPixelSpan[i])]; + row[x] = paletteSpan[Math.Min(paletteCount, quantizedPixelSpan[i])]; } } }