From f3159e4429ee9302c0321459faa46f886b0fad46 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Fri, 21 Apr 2017 17:45:37 +1000 Subject: [PATCH] Add Hsl --- src/ImageSharp/Colors/Spaces/Cmyk.cs | 11 +- .../Conversion/ColorSpaceConverter.CieLab.cs | 13 ++ .../Conversion/ColorSpaceConverter.CieLch.cs | 13 ++ .../Conversion/ColorSpaceConverter.CieXyy.cs | 16 +- .../Conversion/ColorSpaceConverter.CieXyz.cs | 15 ++ .../Conversion/ColorSpaceConverter.Cmyk.cs | 14 ++ .../Conversion/ColorSpaceConverter.Hsl.cs | 142 ++++++++++++++++ .../ColorSpaceConverter.HunterLab.cs | 13 ++ .../ColorSpaceConverter.LinearRgb.cs | 13 ++ .../Conversion/ColorSpaceConverter.Lms.cs | 13 ++ .../Conversion/ColorSpaceConverter.Rgb.cs | 13 ++ .../Implementation/Hsl/HslAndRgbConverter.cs | 153 +++++++++++++++++ src/ImageSharp/Colors/Spaces/Hsl.cs | 157 ++++++++++++++++++ .../Colorspaces/ColorSpaceEqualityTests.cs | 7 + .../Colorspaces/RgbAndCmykConversionTest.cs | 2 +- .../Colorspaces/RgbAndHslConversionTest.cs | 72 ++++++++ 16 files changed, 664 insertions(+), 3 deletions(-) create mode 100644 src/ImageSharp/Colors/Spaces/Conversion/ColorSpaceConverter.Hsl.cs create mode 100644 src/ImageSharp/Colors/Spaces/Conversion/Implementation/Hsl/HslAndRgbConverter.cs create mode 100644 src/ImageSharp/Colors/Spaces/Hsl.cs create mode 100644 tests/ImageSharp.Tests/Colors/Colorspaces/RgbAndHslConversionTest.cs diff --git a/src/ImageSharp/Colors/Spaces/Cmyk.cs b/src/ImageSharp/Colors/Spaces/Cmyk.cs index 488c36e8ed..d21ab0fcd1 100644 --- a/src/ImageSharp/Colors/Spaces/Cmyk.cs +++ b/src/ImageSharp/Colors/Spaces/Cmyk.cs @@ -32,9 +32,18 @@ namespace ImageSharp.Colors.Spaces /// The yellow component. /// The keyline black component. public Cmyk(float c, float m, float y, float k) + : this(new Vector4(c, m, y, k)) + { + } + + /// + /// Initializes a new instance of the struct. + /// + /// The vector representing the c, m, y, k components. + public Cmyk(Vector4 vector) : this() { - this.backingVector = Vector4.Clamp(new Vector4(c, m, y, k), Vector4.Zero, Vector4.One); + this.backingVector = Vector4.Clamp(vector, Vector4.Zero, Vector4.One); } /// diff --git a/src/ImageSharp/Colors/Spaces/Conversion/ColorSpaceConverter.CieLab.cs b/src/ImageSharp/Colors/Spaces/Conversion/ColorSpaceConverter.CieLab.cs index 95582d2b36..87d48b2184 100644 --- a/src/ImageSharp/Colors/Spaces/Conversion/ColorSpaceConverter.CieLab.cs +++ b/src/ImageSharp/Colors/Spaces/Conversion/ColorSpaceConverter.CieLab.cs @@ -85,6 +85,19 @@ namespace ImageSharp.Colors.Spaces.Conversion return this.ToCieLab(xyzColor); } + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public CieLab ToCieLab(Hsl color) + { + Guard.NotNull(color, nameof(color)); + + CieXyz xyzColor = this.ToCieXyz(color); + return this.ToCieLab(xyzColor); + } + /// /// Converts a into a /// diff --git a/src/ImageSharp/Colors/Spaces/Conversion/ColorSpaceConverter.CieLch.cs b/src/ImageSharp/Colors/Spaces/Conversion/ColorSpaceConverter.CieLch.cs index 79fa53c82b..6224c91597 100644 --- a/src/ImageSharp/Colors/Spaces/Conversion/ColorSpaceConverter.CieLch.cs +++ b/src/ImageSharp/Colors/Spaces/Conversion/ColorSpaceConverter.CieLch.cs @@ -72,6 +72,19 @@ namespace ImageSharp.Colors.Spaces.Conversion return this.ToCieLch(xyzColor); } + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public CieLch ToCieLch(Hsl color) + { + Guard.NotNull(color, nameof(color)); + + CieXyz xyzColor = this.ToCieXyz(color); + return this.ToCieLch(xyzColor); + } + /// /// Converts a into a /// diff --git a/src/ImageSharp/Colors/Spaces/Conversion/ColorSpaceConverter.CieXyy.cs b/src/ImageSharp/Colors/Spaces/Conversion/ColorSpaceConverter.CieXyy.cs index 0b86109af8..8d27484056 100644 --- a/src/ImageSharp/Colors/Spaces/Conversion/ColorSpaceConverter.CieXyy.cs +++ b/src/ImageSharp/Colors/Spaces/Conversion/ColorSpaceConverter.CieXyy.cs @@ -58,7 +58,7 @@ namespace ImageSharp.Colors.Spaces.Conversion /// Converts a into a /// /// The color to convert. - /// The + /// The public CieXyy ToCieXyy(Cmyk color) { Guard.NotNull(color, nameof(color)); @@ -68,6 +68,20 @@ namespace ImageSharp.Colors.Spaces.Conversion return this.ToCieXyy(xyzColor); } + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public CieXyy ToCieXyy(Hsl color) + { + Guard.NotNull(color, nameof(color)); + + CieXyz xyzColor = this.ToCieXyz(color); + + return this.ToCieXyy(xyzColor); + } + /// /// Converts a into a /// diff --git a/src/ImageSharp/Colors/Spaces/Conversion/ColorSpaceConverter.CieXyz.cs b/src/ImageSharp/Colors/Spaces/Conversion/ColorSpaceConverter.CieXyz.cs index 7e171d42eb..f963c72f98 100644 --- a/src/ImageSharp/Colors/Spaces/Conversion/ColorSpaceConverter.CieXyz.cs +++ b/src/ImageSharp/Colors/Spaces/Conversion/ColorSpaceConverter.CieXyz.cs @@ -85,6 +85,21 @@ namespace ImageSharp.Colors.Spaces.Conversion return this.ToCieXyz(rgb); } + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public CieXyz ToCieXyz(Hsl color) + { + Guard.NotNull(color, nameof(color)); + + // Conversion + Rgb rgb = this.ToRgb(color); + + return this.ToCieXyz(rgb); + } + /// /// Converts a into a /// diff --git a/src/ImageSharp/Colors/Spaces/Conversion/ColorSpaceConverter.Cmyk.cs b/src/ImageSharp/Colors/Spaces/Conversion/ColorSpaceConverter.Cmyk.cs index dc7e109271..3934eaa50a 100644 --- a/src/ImageSharp/Colors/Spaces/Conversion/ColorSpaceConverter.Cmyk.cs +++ b/src/ImageSharp/Colors/Spaces/Conversion/ColorSpaceConverter.Cmyk.cs @@ -71,6 +71,20 @@ namespace ImageSharp.Colors.Spaces.Conversion return CmykAndRgbConverter.Convert(rgb); } + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public Cmyk ToCmyk(Hsl color) + { + Guard.NotNull(color, nameof(color)); + + Rgb rgb = this.ToRgb(color); + + return CmykAndRgbConverter.Convert(rgb); + } + /// /// Converts a into a /// diff --git a/src/ImageSharp/Colors/Spaces/Conversion/ColorSpaceConverter.Hsl.cs b/src/ImageSharp/Colors/Spaces/Conversion/ColorSpaceConverter.Hsl.cs new file mode 100644 index 0000000000..53ba332e30 --- /dev/null +++ b/src/ImageSharp/Colors/Spaces/Conversion/ColorSpaceConverter.Hsl.cs @@ -0,0 +1,142 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageSharp.Colors.Spaces.Conversion +{ + using ImageSharp.Colors.Spaces; + using ImageSharp.Colors.Spaces.Conversion.Implementation.Hsl; + + /// + /// Converts between color spaces ensuring that the color is adapted using chromatic adaptation. + /// + public partial class ColorSpaceConverter + { + private static readonly HslAndRgbConverter HslAndRgbConverter = new HslAndRgbConverter(); + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public Hsl ToHsl(CieLab color) + { + Guard.NotNull(color, nameof(color)); + + CieXyz xyzColor = this.ToCieXyz(color); + + return this.ToHsl(xyzColor); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public Hsl ToHsl(CieLch color) + { + Guard.NotNull(color, nameof(color)); + + CieXyz xyzColor = this.ToCieXyz(color); + + return this.ToHsl(xyzColor); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public Hsl ToHsl(CieXyy color) + { + Guard.NotNull(color, nameof(color)); + + CieXyz xyzColor = this.ToCieXyz(color); + + return this.ToHsl(xyzColor); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public Hsl ToHsl(CieXyz color) + { + Guard.NotNull(color, nameof(color)); + + Rgb rgb = this.ToRgb(color); + + return HslAndRgbConverter.Convert(rgb); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public Hsl ToHsl(Cmyk color) + { + Guard.NotNull(color, nameof(color)); + + Rgb rgb = this.ToRgb(color); + + return HslAndRgbConverter.Convert(rgb); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public Hsl ToHsl(HunterLab color) + { + Guard.NotNull(color, nameof(color)); + + CieXyz xyzColor = this.ToCieXyz(color); + + return this.ToHsl(xyzColor); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public Hsl ToHsl(LinearRgb color) + { + Guard.NotNull(color, nameof(color)); + + Rgb rgb = this.ToRgb(color); + + return HslAndRgbConverter.Convert(rgb); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public Hsl ToHsl(Lms color) + { + Guard.NotNull(color, nameof(color)); + + CieXyz xyzColor = this.ToCieXyz(color); + + return this.ToHsl(xyzColor); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public Hsl ToHsl(Rgb color) + { + Guard.NotNull(color, nameof(color)); + + return HslAndRgbConverter.Convert(color); + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/Colors/Spaces/Conversion/ColorSpaceConverter.HunterLab.cs b/src/ImageSharp/Colors/Spaces/Conversion/ColorSpaceConverter.HunterLab.cs index 6d84423875..a00c19b741 100644 --- a/src/ImageSharp/Colors/Spaces/Conversion/ColorSpaceConverter.HunterLab.cs +++ b/src/ImageSharp/Colors/Spaces/Conversion/ColorSpaceConverter.HunterLab.cs @@ -82,6 +82,19 @@ namespace ImageSharp.Colors.Spaces.Conversion return this.ToHunterLab(xyzColor); } + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public HunterLab ToHunterLab(Hsl color) + { + Guard.NotNull(color, nameof(color)); + + CieXyz xyzColor = this.ToCieXyz(color); + return this.ToHunterLab(xyzColor); + } + /// /// Converts a into a /// diff --git a/src/ImageSharp/Colors/Spaces/Conversion/ColorSpaceConverter.LinearRgb.cs b/src/ImageSharp/Colors/Spaces/Conversion/ColorSpaceConverter.LinearRgb.cs index d381634d2f..6ba6b6cd30 100644 --- a/src/ImageSharp/Colors/Spaces/Conversion/ColorSpaceConverter.LinearRgb.cs +++ b/src/ImageSharp/Colors/Spaces/Conversion/ColorSpaceConverter.LinearRgb.cs @@ -87,6 +87,19 @@ namespace ImageSharp.Colors.Spaces.Conversion return this.ToLinearRgb(rgb); } + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public LinearRgb ToLinearRgb(Hsl color) + { + Guard.NotNull(color, nameof(color)); + + Rgb rgb = this.ToRgb(color); + return this.ToLinearRgb(rgb); + } + /// /// Converts a into a /// diff --git a/src/ImageSharp/Colors/Spaces/Conversion/ColorSpaceConverter.Lms.cs b/src/ImageSharp/Colors/Spaces/Conversion/ColorSpaceConverter.Lms.cs index 202ecf4ddf..cdea60f870 100644 --- a/src/ImageSharp/Colors/Spaces/Conversion/ColorSpaceConverter.Lms.cs +++ b/src/ImageSharp/Colors/Spaces/Conversion/ColorSpaceConverter.Lms.cs @@ -77,6 +77,19 @@ namespace ImageSharp.Colors.Spaces.Conversion return this.ToLms(xyzColor); } + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public Lms ToLms(Hsl color) + { + Guard.NotNull(color, nameof(color)); + + CieXyz xyzColor = this.ToCieXyz(color); + return this.ToLms(xyzColor); + } + /// /// Converts a into a /// diff --git a/src/ImageSharp/Colors/Spaces/Conversion/ColorSpaceConverter.Rgb.cs b/src/ImageSharp/Colors/Spaces/Conversion/ColorSpaceConverter.Rgb.cs index 2682b05aae..547a04771e 100644 --- a/src/ImageSharp/Colors/Spaces/Conversion/ColorSpaceConverter.Rgb.cs +++ b/src/ImageSharp/Colors/Spaces/Conversion/ColorSpaceConverter.Rgb.cs @@ -82,6 +82,19 @@ namespace ImageSharp.Colors.Spaces.Conversion return CmykAndRgbConverter.Convert(color); } + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public Rgb ToRgb(Hsl color) + { + Guard.NotNull(color, nameof(color)); + + // Conversion + return HslAndRgbConverter.Convert(color); + } + /// /// Converts a into a /// diff --git a/src/ImageSharp/Colors/Spaces/Conversion/Implementation/Hsl/HslAndRgbConverter.cs b/src/ImageSharp/Colors/Spaces/Conversion/Implementation/Hsl/HslAndRgbConverter.cs new file mode 100644 index 0000000000..d5cc2f6316 --- /dev/null +++ b/src/ImageSharp/Colors/Spaces/Conversion/Implementation/Hsl/HslAndRgbConverter.cs @@ -0,0 +1,153 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageSharp.Colors.Spaces.Conversion.Implementation.Hsl +{ + using System.Runtime.CompilerServices; + + using ImageSharp.Colors.Spaces; + + /// + /// Color converter between HSL and Rgb + /// See for formulas. + /// + internal class HslAndRgbConverter : IColorConversion, IColorConversion + { + /// + public Rgb Convert(Hsl input) + { + float rangedH = input.H / 360F; + float r = 0; + float g = 0; + float b = 0; + float s = input.S; + float l = input.L; + + if (MathF.Abs(l) > Constants.Epsilon) + { + if (MathF.Abs(s) < Constants.Epsilon) + { + r = g = b = l; + } + else + { + float temp2 = (l < .5F) ? l * (1F + s) : l + s - (l * s); + float temp1 = (2F * l) - temp2; + + r = GetColorComponent(temp1, temp2, rangedH + 0.3333333F); + g = GetColorComponent(temp1, temp2, rangedH); + b = GetColorComponent(temp1, temp2, rangedH - 0.3333333F); + } + } + + return new Rgb(r, g, b); + } + + /// + public Hsl Convert(Rgb input) + { + float r = input.R; + float g = input.G; + float b = input.B; + + float max = MathF.Max(r, MathF.Max(g, b)); + float min = MathF.Min(r, MathF.Min(g, b)); + float chroma = max - min; + float h = 0F; + float s = 0F; + float l = (max + min) / 2F; + + if (MathF.Abs(chroma) < Constants.Epsilon) + { + return new Hsl(0F, s, l); + } + + if (MathF.Abs(r - max) < Constants.Epsilon) + { + h = (g - b) / chroma; + } + else if (MathF.Abs(g - max) < Constants.Epsilon) + { + h = 2F + ((b - r) / chroma); + } + else if (MathF.Abs(b - max) < Constants.Epsilon) + { + h = 4F + ((r - g) / chroma); + } + + h *= 60F; + if (h < 0F) + { + h += 360F; + } + + if (l <= .5F) + { + s = chroma / (max + min); + } + else + { + s = chroma / (2F - chroma); + } + + return new Hsl(h, s, l); + } + + /// + /// Gets the color component from the given values. + /// + /// The first value. + /// The second value. + /// The third value. + /// + /// The . + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static float GetColorComponent(float first, float second, float third) + { + third = MoveIntoRange(third); + if (third < 0.1666667F) + { + return first + ((second - first) * 6F * third); + } + + if (third < .5F) + { + return second; + } + + if (third < 0.6666667F) + { + return first + ((second - first) * (0.6666667F - third) * 6F); + } + + return first; + } + + /// + /// Moves the specific value within the acceptable range for + /// conversion. + /// Used for converting colors to this type. + /// + /// The value to shift. + /// + /// The . + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static float MoveIntoRange(float value) + { + if (value < 0F) + { + value += 1F; + } + else if (value > 1F) + { + value -= 1F; + } + + return value; + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/Colors/Spaces/Hsl.cs b/src/ImageSharp/Colors/Spaces/Hsl.cs new file mode 100644 index 0000000000..48948c7494 --- /dev/null +++ b/src/ImageSharp/Colors/Spaces/Hsl.cs @@ -0,0 +1,157 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageSharp.Colors.Spaces +{ + using System; + using System.ComponentModel; + using System.Numerics; + + /// + /// Represents a Hsl (hue, saturation, lightness) color. + /// + public struct Hsl : IColorVector, IEquatable, IAlmostEquatable + { + /// + /// Represents a that has H, S, and L values set to zero. + /// + public static readonly Hsl Empty = default(Hsl); + + /// + /// Max range used for clamping + /// + private static readonly Vector3 VectorMax = new Vector3(360, 1, 1); + + /// + /// The backing vector for SIMD support. + /// + private readonly Vector3 backingVector; + + /// + /// Initializes a new instance of the struct. + /// + /// The h hue component. + /// The s saturation component. + /// The l value (lightness) component. + public Hsl(float h, float s, float l) + : this(new Vector3(h, s, l)) + { + } + + /// + /// Initializes a new instance of the struct. + /// + /// The vector representing the h, s, l components. + public Hsl(Vector3 vector) + { + this.backingVector = Vector3.Clamp(vector, Vector3.Zero, VectorMax); + } + + /// + /// Gets the hue component. + /// A value ranging between 0 and 360. + /// + public float H => this.backingVector.X; + + /// + /// Gets the saturation component. + /// A value ranging between 0 and 1. + /// + public float S => this.backingVector.Y; + + /// + /// Gets the lightness component. + /// A value ranging between 0 and 1. + /// + public float L => this.backingVector.Z; + + /// + /// Gets a value indicating whether this is empty. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public bool IsEmpty => this.Equals(Empty); + + /// + public Vector3 Vector => this.backingVector; + + /// + /// Compares two objects for equality. + /// + /// + /// The on the left side of the operand. + /// + /// + /// The on the right side of the operand. + /// + /// + /// True if the current left is equal to the parameter; otherwise, false. + /// + public static bool operator ==(Hsl left, Hsl right) + { + return left.Equals(right); + } + + /// + /// Compares two objects for inequality. + /// + /// + /// The on the left side of the operand. + /// + /// + /// The on the right side of the operand. + /// + /// + /// True if the current left is unequal to the parameter; otherwise, false. + /// + public static bool operator !=(Hsl left, Hsl right) + { + return !left.Equals(right); + } + + /// + public override int GetHashCode() + { + return this.backingVector.GetHashCode(); + } + + /// + public override string ToString() + { + if (this.IsEmpty) + { + return "Hsl [ Empty ]"; + } + + return $"Hsl [ H={this.H:#0.##}, S={this.S:#0.##}, L={this.L:#0.##} ]"; + } + + /// + public override bool Equals(object obj) + { + if (obj is Hsl) + { + return this.Equals((Hsl)obj); + } + + return false; + } + + /// + public bool Equals(Hsl other) + { + return this.backingVector.Equals(other.backingVector); + } + + /// + public bool AlmostEquals(Hsl other, float precision) + { + Vector3 result = Vector3.Abs(this.backingVector - other.backingVector); + + return result.X <= precision + && result.Y <= precision + && result.Z <= precision; + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Colors/Colorspaces/ColorSpaceEqualityTests.cs b/tests/ImageSharp.Tests/Colors/Colorspaces/ColorSpaceEqualityTests.cs index c82fc6d803..d3af7d43ea 100644 --- a/tests/ImageSharp.Tests/Colors/Colorspaces/ColorSpaceEqualityTests.cs +++ b/tests/ImageSharp.Tests/Colors/Colorspaces/ColorSpaceEqualityTests.cs @@ -27,6 +27,7 @@ namespace ImageSharp.Tests.Colors Lms.Empty, LinearRgb.Empty, Rgb.Empty, + Hsl.Empty }; public static readonly TheoryData EqualityData = @@ -40,6 +41,7 @@ namespace ImageSharp.Tests.Colors { new Lms(Vector3.One), new Lms(Vector3.One), typeof(Lms) }, { new LinearRgb(Vector3.One), new LinearRgb(Vector3.One), typeof(LinearRgb) }, { new Rgb(Vector3.One), new Rgb(Vector3.One), typeof(Rgb) }, + { new Hsl(Vector3.One), new Hsl(Vector3.One), typeof(Hsl) }, }; public static readonly TheoryData NotEqualityDataNulls = @@ -54,6 +56,7 @@ namespace ImageSharp.Tests.Colors { new Lms(Vector3.One), null, typeof(Lms) }, { new LinearRgb(Vector3.One), null, typeof(LinearRgb) }, { new Rgb(Vector3.One), null, typeof(Rgb) }, + { new Hsl(Vector3.One), null, typeof(Hsl) }, }; public static readonly TheoryData NotEqualityDataDifferentObjects = @@ -64,6 +67,7 @@ namespace ImageSharp.Tests.Colors { new CieXyz(Vector3.One), new HunterLab(Vector3.Zero), null }, { new Rgb(Vector3.One), new LinearRgb(Vector3.Zero), null }, { new Rgb(Vector3.One), new Lms(Vector3.Zero), null }, + { new Cmyk(Vector4.One), new Hsl(Vector3.Zero), null }, }; public static readonly TheoryData NotEqualityData = @@ -78,6 +82,8 @@ namespace ImageSharp.Tests.Colors { new Lms(Vector3.One), new Lms(Vector3.Zero), typeof(Lms) }, { new LinearRgb(Vector3.One), new LinearRgb(Vector3.Zero), typeof(LinearRgb) }, { new Rgb(Vector3.One), new Rgb(Vector3.Zero), typeof(Rgb) }, + { new Cmyk(Vector4.One), new Cmyk(Vector4.Zero), typeof(Cmyk) }, + { new Hsl(Vector3.One), new Hsl(Vector3.Zero), typeof(Hsl) }, }; public static readonly TheoryData AlmostEqualsData = @@ -94,6 +100,7 @@ namespace ImageSharp.Tests.Colors { new CieXyz(380F, 380F, 380F), new CieXyz(380.001F, 380F, 380F), typeof(CieXyz), .01F }, { new CieXyz(380F, 380F, 380F), new CieXyz(380F, 380.001F, 380F), typeof(CieXyz), .01F }, { new CieXyz(380F, 380F, 380F), new CieXyz(380F, 380F, 380.001F), typeof(CieXyz), .01F }, + { new Cmyk(1, 1, 1, 1), new Cmyk(1, 1, 1, .99F), typeof(Cmyk), .01F }, }; public static readonly TheoryData AlmostNotEqualsData = diff --git a/tests/ImageSharp.Tests/Colors/Colorspaces/RgbAndCmykConversionTest.cs b/tests/ImageSharp.Tests/Colors/Colorspaces/RgbAndCmykConversionTest.cs index 50e187254c..e95dc65f60 100644 --- a/tests/ImageSharp.Tests/Colors/Colorspaces/RgbAndCmykConversionTest.cs +++ b/tests/ImageSharp.Tests/Colors/Colorspaces/RgbAndCmykConversionTest.cs @@ -8,7 +8,7 @@ using Xunit; /// - /// Tests - conversions. + /// Tests - conversions. /// /// /// Test data generated using: diff --git a/tests/ImageSharp.Tests/Colors/Colorspaces/RgbAndHslConversionTest.cs b/tests/ImageSharp.Tests/Colors/Colorspaces/RgbAndHslConversionTest.cs new file mode 100644 index 0000000000..1f5c2a82df --- /dev/null +++ b/tests/ImageSharp.Tests/Colors/Colorspaces/RgbAndHslConversionTest.cs @@ -0,0 +1,72 @@ +namespace ImageSharp.Tests.Colors.Colorspaces +{ + using System.Collections.Generic; + + using ImageSharp.Colors.Spaces; + using ImageSharp.Colors.Spaces.Conversion; + + using Xunit; + + /// + /// Tests - conversions. + /// + /// + /// Test data generated using: + /// + /// + /// + public class RgbAndHslConversionTest + { + private static readonly IEqualityComparer FloatRoundingComparer = new FloatRoundingComparer(4); + + private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); + + /// + /// Tests conversion from to . + /// + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(0, 1, 1, 1, 1, 1)] + [InlineData(360, 1, 1, 1, 1, 1)] + [InlineData(0, 1, .5F, 1, 0, 0)] + [InlineData(120, 1, .5F, 0, 1, 0)] + [InlineData(240, 1, .5F, 0, 0, 1)] + public void Convert_Hsl_To_Rgb(float h, float s, float l, float r, float g, float b) + { + // Arrange + Hsl input = new Hsl(h, s, l); + + // Act + Rgb output = Converter.ToRgb(input); + + // Assert + Assert.Equal(Rgb.DefaultWorkingSpace, output.WorkingSpace); + Assert.Equal(r, output.R, FloatRoundingComparer); + Assert.Equal(g, output.G, FloatRoundingComparer); + Assert.Equal(b, output.B, FloatRoundingComparer); + } + + /// + /// Tests conversion from to . + /// + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(1, 1, 1, 0, 0, 1)] + [InlineData(1, 0, 0, 0, 1, .5F)] + [InlineData(0, 1, 0, 120, 1, .5F)] + [InlineData(0, 0, 1, 240, 1, .5F)] + public void Convert_Rgb_To_Hsl(float r, float g, float b, float h, float s, float l) + { + // Arrange + Rgb input = new Rgb(r, g, b); + + // Act + Hsl output = Converter.ToHsl(input); + + // Assert + Assert.Equal(h, output.H, FloatRoundingComparer); + Assert.Equal(s, output.S, FloatRoundingComparer); + Assert.Equal(l, output.L, FloatRoundingComparer); + } + } +}