From 9fdf204086a399aa6991e62440e92d223a8d8078 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Fri, 10 May 2024 23:53:24 +1000 Subject: [PATCH] Complete conversion tests --- src/ImageSharp/ColorProfiles/CieLuv.cs | 10 +-- ...olorProfileConverterExtensionsCieLabRgb.cs | 57 +++++++++++++ ...olorProfileConverterExtensionsRgbCieLab.cs | 57 +++++++++++++ src/ImageSharp/ColorProfiles/Hsl.cs | 2 +- src/ImageSharp/ColorProfiles/Hsv.cs | 6 +- .../ColorProfiles/LmsAdaptationMatrix.cs | 2 +- .../CieXyyAndHsvConversionTests.cs | 4 +- .../CieXyyAndHunterLabConversionTests.cs | 4 +- .../CieXyzAndCieLuvConversionTest.cs | 49 +++++------ .../CieXyzAndHslConversionTests.cs | 70 ++++++++++++++++ .../CieXyzAndHsvConversionTests.cs | 70 ++++++++++++++++ .../CieXyzAndHunterLabConversionTest.cs | 74 +++++++++++++++++ .../CieXyzAndLmsConversionTest.cs | 4 +- .../CieXyzAndYCbCrConversionTests.cs | 70 ++++++++++++++++ .../CmykAndCieLchConversionTests.cs | 69 +++++++++++++++ .../CmykAndCieLuvConversionTests.cs | 70 ++++++++++++++++ .../CmykAndYCbCrConversionTests.cs | 4 +- .../RgbAndCieXyzConversionTest.cs | 8 +- .../ColorProfiles/RgbAndHslConversionTest.cs | 83 +++++++++++++++++++ .../ColorProfiles/RgbAndHsvConversionTest.cs | 81 ++++++++++++++++++ 20 files changed, 745 insertions(+), 49 deletions(-) create mode 100644 src/ImageSharp/ColorProfiles/ColorProfileConverterExtensionsCieLabRgb.cs create mode 100644 src/ImageSharp/ColorProfiles/ColorProfileConverterExtensionsRgbCieLab.cs create mode 100644 tests/ImageSharp.Tests/ColorProfiles/CieXyzAndHslConversionTests.cs create mode 100644 tests/ImageSharp.Tests/ColorProfiles/CieXyzAndHsvConversionTests.cs create mode 100644 tests/ImageSharp.Tests/ColorProfiles/CieXyzAndHunterLabConversionTest.cs create mode 100644 tests/ImageSharp.Tests/ColorProfiles/CieXyzAndYCbCrConversionTests.cs create mode 100644 tests/ImageSharp.Tests/ColorProfiles/CmykAndCieLchConversionTests.cs create mode 100644 tests/ImageSharp.Tests/ColorProfiles/CmykAndCieLuvConversionTests.cs create mode 100644 tests/ImageSharp.Tests/ColorProfiles/RgbAndHslConversionTest.cs create mode 100644 tests/ImageSharp.Tests/ColorProfiles/RgbAndHsvConversionTest.cs diff --git a/src/ImageSharp/ColorProfiles/CieLuv.cs b/src/ImageSharp/ColorProfiles/CieLuv.cs index 304a14c7a0..64541e4961 100644 --- a/src/ImageSharp/ColorProfiles/CieLuv.cs +++ b/src/ImageSharp/ColorProfiles/CieLuv.cs @@ -46,11 +46,6 @@ public readonly struct CieLuv : IColorProfile /// public readonly float V { get; } - /// - /// Gets the reference white point of this color - /// - public readonly CieXyz WhitePoint { get; } - /// /// Compares two objects for equality. /// @@ -185,7 +180,7 @@ public readonly struct CieLuv : IColorProfile => ChromaticAdaptionWhitePointSource.WhitePoint; /// - public override int GetHashCode() => HashCode.Combine(this.L, this.U, this.V, this.WhitePoint); + public override int GetHashCode() => HashCode.Combine(this.L, this.U, this.V); /// public override string ToString() => FormattableString.Invariant($"CieLuv({this.L:#0.##}, {this.U:#0.##}, {this.V:#0.##})"); @@ -198,8 +193,7 @@ public readonly struct CieLuv : IColorProfile public bool Equals(CieLuv other) => this.L.Equals(other.L) && this.U.Equals(other.U) - && this.V.Equals(other.V) - && this.WhitePoint.Equals(other.WhitePoint); + && this.V.Equals(other.V); [MethodImpl(MethodImplOptions.AggressiveInlining)] private static double ComputeU(in CieXyz source) diff --git a/src/ImageSharp/ColorProfiles/ColorProfileConverterExtensionsCieLabRgb.cs b/src/ImageSharp/ColorProfiles/ColorProfileConverterExtensionsCieLabRgb.cs new file mode 100644 index 0000000000..bbedb2e2b8 --- /dev/null +++ b/src/ImageSharp/ColorProfiles/ColorProfileConverterExtensionsCieLabRgb.cs @@ -0,0 +1,57 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using System.Buffers; +using SixLabors.ImageSharp.Memory; + +namespace SixLabors.ImageSharp.ColorProfiles; + +internal static class ColorProfileConverterExtensionsCieLabRgb +{ + public static TTo Convert(this ColorProfileConverter converter, TFrom source) + where TFrom : struct, IColorProfile + where TTo : struct, IColorProfile + { + ColorConversionOptions options = converter.Options; + + // Convert to input PCS + CieLab pcsFromA = source.ToProfileConnectingSpace(options); + CieXyz pcsFromB = pcsFromA.ToProfileConnectingSpace(options); + + // Adapt to target white point + pcsFromB = VonKriesChromaticAdaptation.Transform(options, in pcsFromB); + + // Convert between PCS + Rgb pcsTo = Rgb.FromProfileConnectingSpace(options, in pcsFromB); + + // Convert to output from PCS + return TTo.FromProfileConnectingSpace(options, pcsTo); + } + + public static void Convert(this ColorProfileConverter converter, ReadOnlySpan source, Span destination) + where TFrom : struct, IColorProfile + where TTo : struct, IColorProfile + { + ColorConversionOptions options = converter.Options; + + // Convert to input PCS. + using IMemoryOwner pcsFromAOwner = options.MemoryAllocator.Allocate(source.Length); + Span pcsFromA = pcsFromAOwner.GetSpan(); + TFrom.ToProfileConnectionSpace(options, source, pcsFromA); + + using IMemoryOwner pcsFromBOwner = options.MemoryAllocator.Allocate(source.Length); + Span pcsFromB = pcsFromBOwner.GetSpan(); + CieLab.ToProfileConnectionSpace(options, pcsFromA, pcsFromB); + + // Adapt to target white point + VonKriesChromaticAdaptation.Transform(options, pcsFromB, pcsFromB); + + // Convert between PCS. + using IMemoryOwner pcsToOwner = options.MemoryAllocator.Allocate(source.Length); + Span pcsTo = pcsToOwner.GetSpan(); + Rgb.FromProfileConnectionSpace(options, pcsFromB, pcsTo); + + // Convert to output from PCS + TTo.FromProfileConnectionSpace(options, pcsTo, destination); + } +} diff --git a/src/ImageSharp/ColorProfiles/ColorProfileConverterExtensionsRgbCieLab.cs b/src/ImageSharp/ColorProfiles/ColorProfileConverterExtensionsRgbCieLab.cs new file mode 100644 index 0000000000..baa92755cc --- /dev/null +++ b/src/ImageSharp/ColorProfiles/ColorProfileConverterExtensionsRgbCieLab.cs @@ -0,0 +1,57 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using System.Buffers; +using SixLabors.ImageSharp.Memory; + +namespace SixLabors.ImageSharp.ColorProfiles; + +internal static class ColorProfileConverterExtensionsRgbCieLab +{ + public static TTo Convert(this ColorProfileConverter converter, TFrom source) + where TFrom : struct, IColorProfile + where TTo : struct, IColorProfile + { + ColorConversionOptions options = converter.Options; + + // Convert to input PCS + Rgb pcsFromA = source.ToProfileConnectingSpace(options); + CieXyz pcsFromB = pcsFromA.ToProfileConnectingSpace(options); + + // Adapt to target white point + pcsFromB = VonKriesChromaticAdaptation.Transform(options, in pcsFromB); + + // Convert between PCS + CieLab pcsTo = CieLab.FromProfileConnectingSpace(options, in pcsFromB); + + // Convert to output from PCS + return TTo.FromProfileConnectingSpace(options, pcsTo); + } + + public static void Convert(this ColorProfileConverter converter, ReadOnlySpan source, Span destination) + where TFrom : struct, IColorProfile + where TTo : struct, IColorProfile + { + ColorConversionOptions options = converter.Options; + + // Convert to input PCS. + using IMemoryOwner pcsFromAOwner = options.MemoryAllocator.Allocate(source.Length); + Span pcsFromA = pcsFromAOwner.GetSpan(); + TFrom.ToProfileConnectionSpace(options, source, pcsFromA); + + using IMemoryOwner pcsFromBOwner = options.MemoryAllocator.Allocate(source.Length); + Span pcsFromB = pcsFromBOwner.GetSpan(); + Rgb.ToProfileConnectionSpace(options, pcsFromA, pcsFromB); + + // Adapt to target white point + VonKriesChromaticAdaptation.Transform(options, pcsFromB, pcsFromB); + + // Convert between PCS. + using IMemoryOwner pcsToOwner = options.MemoryAllocator.Allocate(source.Length); + Span pcsTo = pcsToOwner.GetSpan(); + CieLab.FromProfileConnectionSpace(options, pcsFromB, pcsTo); + + // Convert to output from PCS + TTo.FromProfileConnectionSpace(options, pcsTo, destination); + } +} diff --git a/src/ImageSharp/ColorProfiles/Hsl.cs b/src/ImageSharp/ColorProfiles/Hsl.cs index dd8772d962..8dcef23c4b 100644 --- a/src/ImageSharp/ColorProfiles/Hsl.cs +++ b/src/ImageSharp/ColorProfiles/Hsl.cs @@ -114,7 +114,7 @@ public readonly struct Hsl : IColorProfile } h *= 60F; - if (h < 0F) + if (h < -Constants.Epsilon) { h += 360F; } diff --git a/src/ImageSharp/ColorProfiles/Hsv.cs b/src/ImageSharp/ColorProfiles/Hsv.cs index 787b8ad411..b3922d11f5 100644 --- a/src/ImageSharp/ColorProfiles/Hsv.cs +++ b/src/ImageSharp/ColorProfiles/Hsv.cs @@ -111,10 +111,10 @@ public readonly struct Hsv : IColorProfile h = 4 + ((r - g) / chroma); } - h *= 60; - if (h < 0f) + h *= 60F; + if (h < -Constants.Epsilon) { - h += 360; + h += 360F; } s = chroma / v; diff --git a/src/ImageSharp/ColorProfiles/LmsAdaptationMatrix.cs b/src/ImageSharp/ColorProfiles/LmsAdaptationMatrix.cs index 70bc5aef26..b5b2887cc4 100644 --- a/src/ImageSharp/ColorProfiles/LmsAdaptationMatrix.cs +++ b/src/ImageSharp/ColorProfiles/LmsAdaptationMatrix.cs @@ -10,7 +10,7 @@ namespace SixLabors.ImageSharp.ColorProfiles; /// /// /// Matrix data obtained from: -/// Two New von Kries Based Chromatic Adaptation Transforms Found by Numerical Optimization +/// Two New Von Kries Based Chromatic Adaptation Transforms Found by Numerical Optimization /// S. Bianco, R. Schettini /// DISCo, Department of Informatics, Systems and Communication, University of Milan-Bicocca, viale Sarca 336, 20126 Milan, Italy /// https://web.stanford.edu/~sujason/ColorBalancing/Papers/Two%20New%20von%20Kries%20Based%20Chromatic%20Adaptation.pdf diff --git a/tests/ImageSharp.Tests/ColorProfiles/CieXyyAndHsvConversionTests.cs b/tests/ImageSharp.Tests/ColorProfiles/CieXyyAndHsvConversionTests.cs index 4e2bea427f..c2547ca847 100644 --- a/tests/ImageSharp.Tests/ColorProfiles/CieXyyAndHsvConversionTests.cs +++ b/tests/ImageSharp.Tests/ColorProfiles/CieXyyAndHsvConversionTests.cs @@ -15,7 +15,7 @@ public class CieXyyAndHsvConversionTests [Theory] [InlineData(0, 0, 0, 0, 0, 0)] [InlineData(0.360555, 0.936901, 0.1001514, 120, 1, 0.42770)] - public void Convert_CieXyy_to_Hsv(float x, float y, float yl, float h, float s, float v) + public void Convert_CieXyy_To_Hsv(float x, float y, float yl, float h, float s, float v) { // Arrange CieXyy input = new(x, y, yl); @@ -43,7 +43,7 @@ public class CieXyyAndHsvConversionTests [Theory] [InlineData(0, 0, 0, 0, 0, 0)] [InlineData(120, 1, 0.42770, 0.32114, 0.59787, 0.10976)] - public void Convert_Hsv_to_CieXyy(float h, float s, float v, float x, float y, float yl) + public void Convert_Hsv_To_CieXyy(float h, float s, float v, float x, float y, float yl) { // Arrange Hsv input = new(h, s, v); diff --git a/tests/ImageSharp.Tests/ColorProfiles/CieXyyAndHunterLabConversionTests.cs b/tests/ImageSharp.Tests/ColorProfiles/CieXyyAndHunterLabConversionTests.cs index a3b7d4b0f1..4f66538f0f 100644 --- a/tests/ImageSharp.Tests/ColorProfiles/CieXyyAndHunterLabConversionTests.cs +++ b/tests/ImageSharp.Tests/ColorProfiles/CieXyyAndHunterLabConversionTests.cs @@ -15,7 +15,7 @@ public class CieXyyAndHunterLabConversionTests [Theory] [InlineData(0, 0, 0, 0, 0, 0)] [InlineData(0.360555, 0.936901, 0.1001514, 31.6467056, -33.00599, 25.67032)] - public void Convert_CieXyy_to_HunterLab(float x, float y, float yl, float l, float a, float b) + public void Convert_CieXyy_To_HunterLab(float x, float y, float yl, float l, float a, float b) { // Arrange CieXyy input = new(x, y, yl); @@ -43,7 +43,7 @@ public class CieXyyAndHunterLabConversionTests [Theory] [InlineData(0, 0, 0, 0, 0, 0)] [InlineData(31.6467056, -33.00599, 25.67032, 0.360555, 0.936901, 0.1001514)] - public void Convert_HunterLab_to_CieXyy(float l, float a, float b, float x, float y, float yl) + public void Convert_HunterLab_To_CieXyy(float l, float a, float b, float x, float y, float yl) { // Arrange HunterLab input = new(l, a, b); diff --git a/tests/ImageSharp.Tests/ColorProfiles/CieXyzAndCieLuvConversionTest.cs b/tests/ImageSharp.Tests/ColorProfiles/CieXyzAndCieLuvConversionTest.cs index 68151eaa08..4a6c3c4f8a 100644 --- a/tests/ImageSharp.Tests/ColorProfiles/CieXyzAndCieLuvConversionTest.cs +++ b/tests/ImageSharp.Tests/ColorProfiles/CieXyzAndCieLuvConversionTest.cs @@ -18,29 +18,28 @@ public class CieXyzAndCieLuvConversionTest [Theory] [InlineData(0, 0, 0, 0, 0, 0)] - [InlineData(0, 100, 50, 0, 0, 0)] - [InlineData(0.1, 100, 50, 0.000493, 0.000111, -0.000709)] - [InlineData(70.0000, 86.3525, 2.8240, 0.569310, 0.407494, 0.365843)] - [InlineData(10.0000, -1.2345, -10.0000, 0.012191, 0.011260, 0.025939)] - [InlineData(100, 0, 0, 0.950470, 1.000000, 1.088830)] - [InlineData(1, 1, 1, 0.001255, 0.001107, 0.000137)] - public void Convert_Luv_to_Xyz(float l, float u, float v, float x, float y, float z) + [InlineData(0.000493, 0.000111, 0, 0.10026589, 0.9332349, -0.00704865158)] + [InlineData(0.569310, 0.407494, 0.365843, 70.0000, 86.3524, 2.8240)] + [InlineData(0.012191, 0.011260, 0.025939, 9.9998, -1.2343, -9.9999)] + [InlineData(0.950470, 1.000000, 1.088830, 100, 0, 0)] + [InlineData(0.001255, 0.001107, 0.000137, 0.9999, 0.9998, 1.0004)] + public void Convert_Xyz_To_Luv(float x, float y, float z, float l, float u, float v) { // Arrange - CieLuv input = new(l, u, v); - CieXyz expected = new(x, y, z); + CieXyz input = new(x, y, z); + CieLuv expected = new(l, u, v); ColorConversionOptions options = new() { WhitePoint = Illuminants.D65, TargetWhitePoint = Illuminants.D65 }; ColorProfileConverter converter = new(options); - Span inputSpan = new CieLuv[5]; + Span inputSpan = new CieXyz[5]; inputSpan.Fill(input); - Span actualSpan = new CieXyz[5]; + Span actualSpan = new CieLuv[5]; // Act - CieXyz actual = converter.Convert(input); - converter.Convert(inputSpan, actualSpan); + CieLuv actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, Comparer); @@ -53,27 +52,29 @@ public class CieXyzAndCieLuvConversionTest [Theory] [InlineData(0, 0, 0, 0, 0, 0)] - [InlineData(0.000493, 0.000111, 0, 0.1003, 0.9332, -0.0070)] - [InlineData(0.569310, 0.407494, 0.365843, 70.0000, 86.3524, 2.8240)] - [InlineData(0.012191, 0.011260, 0.025939, 9.9998, -1.2343, -9.9999)] - [InlineData(0.950470, 1.000000, 1.088830, 100, 0, 0)] - [InlineData(0.001255, 0.001107, 0.000137, 0.9999, 0.9998, 1.0004)] - public void Convert_Xyz_to_Luv(float x, float y, float z, float l, float u, float v) + [InlineData(0, 100, 50, 0, 0, 0)] + [InlineData(0.1, 100, 50, 0.000493, 0.000111, -0.000709)] + [InlineData(70.0000, 86.3525, 2.8240, 0.569310, 0.407494, 0.365843)] + [InlineData(10.0000, -1.2345, -10.0000, 0.012191, 0.011260, 0.025939)] + [InlineData(100, 0, 0, 0.950470, 1.000000, 1.088830)] + [InlineData(1, 1, 1, 0.001255, 0.001107, 0.000137)] + public void Convert_Luv_To_Xyz(float l, float u, float v, float x, float y, float z) { // Arrange - CieXyz input = new(x, y, z); - CieLuv expected = new(l, u, v); + CieLuv input = new(l, u, v); + CieXyz expected = new(x, y, z); ColorConversionOptions options = new() { WhitePoint = Illuminants.D65, TargetWhitePoint = Illuminants.D65 }; ColorProfileConverter converter = new(options); - Span inputSpan = new CieXyz[5]; + Span inputSpan = new CieLuv[5]; inputSpan.Fill(input); - Span actualSpan = new CieLuv[5]; + Span actualSpan = new CieXyz[5]; // Act - CieLuv actual = converter.Convert(input); + CieXyz actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, Comparer); diff --git a/tests/ImageSharp.Tests/ColorProfiles/CieXyzAndHslConversionTests.cs b/tests/ImageSharp.Tests/ColorProfiles/CieXyzAndHslConversionTests.cs new file mode 100644 index 0000000000..cffdb008b8 --- /dev/null +++ b/tests/ImageSharp.Tests/ColorProfiles/CieXyzAndHslConversionTests.cs @@ -0,0 +1,70 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using SixLabors.ImageSharp.ColorProfiles; + +namespace SixLabors.ImageSharp.Tests.ColorProfiles; + +/// +/// Tests - conversions. +/// +public class CieXyzAndHslConversionTests +{ + private static readonly ApproximateColorProfileComparer Comparer = new(.0002F); + + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(0.360555, 0.936901, 0.1001514, 120, 1, 0.5)] + public void Convert_CieXyz_to_Hsl(float x, float y, float yl, float h, float s, float l) + { + // Arrange + CieXyz input = new(x, y, yl); + Hsl expected = new(h, s, l); + ColorProfileConverter converter = new(); + + Span inputSpan = new CieXyz[5]; + inputSpan.Fill(input); + + Span actualSpan = new Hsl[5]; + + // Act + Hsl actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } + + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(120, 1, 0.5, 0.38506496, 0.716878653, 0.09710451)] + public void Convert_Hsl_to_CieXyz(float h, float s, float l, float x, float y, float yl) + { + // Arrange + Hsl input = new(h, s, l); + CieXyz expected = new(x, y, yl); + ColorProfileConverter converter = new(); + + Span inputSpan = new Hsl[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieXyz[5]; + + // Act + CieXyz actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } +} diff --git a/tests/ImageSharp.Tests/ColorProfiles/CieXyzAndHsvConversionTests.cs b/tests/ImageSharp.Tests/ColorProfiles/CieXyzAndHsvConversionTests.cs new file mode 100644 index 0000000000..d4a0022a47 --- /dev/null +++ b/tests/ImageSharp.Tests/ColorProfiles/CieXyzAndHsvConversionTests.cs @@ -0,0 +1,70 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using SixLabors.ImageSharp.ColorProfiles; + +namespace SixLabors.ImageSharp.Tests.ColorProfiles; + +/// +/// Tests - conversions. +/// +public class CieXyzAndHsvConversionTests +{ + private static readonly ApproximateColorProfileComparer Comparer = new(.0002F); + + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(0.360555, 0.936901, 0.1001514, 120, 1, 0.9999999)] + public void Convert_CieXyz_to_Hsv(float x, float y, float yl, float h, float s, float v) + { + // Arrange + CieXyz input = new(x, y, yl); + Hsv expected = new(h, s, v); + ColorProfileConverter converter = new(); + + Span inputSpan = new CieXyz[5]; + inputSpan.Fill(input); + + Span actualSpan = new Hsv[5]; + + // Act + Hsv actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } + + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(120, 1, 0.9999999, 0.3850648, 0.7168785, 0.09710446)] + public void Convert_Hsv_to_CieXyz(float h, float s, float v, float x, float y, float yl) + { + // Arrange + Hsv input = new(h, s, v); + CieXyz expected = new(x, y, yl); + ColorProfileConverter converter = new(); + + Span inputSpan = new Hsv[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieXyz[5]; + + // Act + CieXyz actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } +} diff --git a/tests/ImageSharp.Tests/ColorProfiles/CieXyzAndHunterLabConversionTest.cs b/tests/ImageSharp.Tests/ColorProfiles/CieXyzAndHunterLabConversionTest.cs new file mode 100644 index 0000000000..aef26fe9a3 --- /dev/null +++ b/tests/ImageSharp.Tests/ColorProfiles/CieXyzAndHunterLabConversionTest.cs @@ -0,0 +1,74 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using SixLabors.ImageSharp.ColorProfiles; + +namespace SixLabors.ImageSharp.Tests.ColorProfiles; + +/// +/// Tests - conversions. +/// +/// +/// Test data generated using: +/// +/// +public class CieXyzAndHunterLabConversionTest +{ + private static readonly ApproximateColorProfileComparer Comparer = new(.0002f); + + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(0.360555, 0.936901, 0.1001514, 96.79365, -100.951096, 49.35507)] + public void Convert_Xyz_To_HunterLab(float x, float y, float z, float l, float a, float b) + { + // Arrange + CieXyz input = new(x, y, z); + HunterLab expected = new(l, a, b); + ColorProfileConverter converter = new(); + + Span inputSpan = new CieXyz[5]; + inputSpan.Fill(input); + + Span actualSpan = new HunterLab[5]; + + // Act + HunterLab actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } + + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(31.6467056, -33.00599, 25.67032, 0.0385420471, 0.10015139, -0.0317969956)] + public void Convert_HunterLab_To_Xyz(float l, float a, float b, float x, float y, float z) + { + // Arrange + HunterLab input = new(l, a, b); + CieXyz expected = new(x, y, z); + ColorProfileConverter converter = new(); + + Span inputSpan = new HunterLab[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieXyz[5]; + + // Act + CieXyz actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } +} diff --git a/tests/ImageSharp.Tests/ColorProfiles/CieXyzAndLmsConversionTest.cs b/tests/ImageSharp.Tests/ColorProfiles/CieXyzAndLmsConversionTest.cs index 60938991e8..185fcd256c 100644 --- a/tests/ImageSharp.Tests/ColorProfiles/CieXyzAndLmsConversionTest.cs +++ b/tests/ImageSharp.Tests/ColorProfiles/CieXyzAndLmsConversionTest.cs @@ -22,7 +22,7 @@ public class CieXyzAndLmsConversionTest [InlineData(0.2664, 1.7135, -0.0685, 0, 1, 0)] [InlineData(-0.175737162, 0.039960061, 1.121059368, 0, 0, 1.08883)] [InlineData(0.2262677362, 0.0961411609, 0.0484570397, 0.216938, 0.150041, 0.048850)] - public void Convert_Lms_to_CieXyz(float l, float m, float s, float x, float y, float z) + public void Convert_Lms_To_CieXyz(float l, float m, float s, float x, float y, float z) { // Arrange Lms input = new(l, m, s); @@ -54,7 +54,7 @@ public class CieXyzAndLmsConversionTest [InlineData(0, 1, 0, 0.2664, 1.7135, -0.0685)] [InlineData(0, 0, 1.08883, -0.175737162, 0.039960061, 1.121059368)] [InlineData(0.216938, 0.150041, 0.048850, 0.2262677362, 0.0961411609, 0.0484570397)] - public void Convert_CieXyz_to_Lms(float x, float y, float z, float l, float m, float s) + public void Convert_CieXyz_To_Lms(float x, float y, float z, float l, float m, float s) { // Arrange CieXyz input = new(x, y, z); diff --git a/tests/ImageSharp.Tests/ColorProfiles/CieXyzAndYCbCrConversionTests.cs b/tests/ImageSharp.Tests/ColorProfiles/CieXyzAndYCbCrConversionTests.cs new file mode 100644 index 0000000000..475673da84 --- /dev/null +++ b/tests/ImageSharp.Tests/ColorProfiles/CieXyzAndYCbCrConversionTests.cs @@ -0,0 +1,70 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using SixLabors.ImageSharp.ColorProfiles; + +namespace SixLabors.ImageSharp.Tests.ColorProfiles; + +/// +/// Tests - conversions. +/// +public class CieXyzAndYCbCrConversionTests +{ + private static readonly ApproximateColorProfileComparer Comparer = new(.0002f); + + [Theory] + [InlineData(0, 0, 0, 0, 128, 128)] + [InlineData(0.360555, 0.936901, 0.1001514, 149.685, 43.52769, 21.23457)] + public void Convert_CieXyz_to_YCbCr(float x, float y, float z, float y2, float cb, float cr) + { + // Arrange + CieXyz input = new(x, y, z); + YCbCr expected = new(y2, cb, cr); + ColorProfileConverter converter = new(); + + Span inputSpan = new CieXyz[5]; + inputSpan.Fill(input); + + Span actualSpan = new YCbCr[5]; + + // Act + YCbCr actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } + + [Theory] + [InlineData(0, 128, 128, 0, 0, 0)] + [InlineData(149.685, 43.52769, 21.23457, 0.38506496, 0.716878653, 0.0971045)] + public void Convert_YCbCr_to_CieXyz(float y2, float cb, float cr, float x, float y, float z) + { + // Arrange + YCbCr input = new(y2, cb, cr); + CieXyz expected = new(x, y, z); + ColorProfileConverter converter = new(); + + Span inputSpan = new YCbCr[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieXyz[5]; + + // Act + CieXyz actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } +} diff --git a/tests/ImageSharp.Tests/ColorProfiles/CmykAndCieLchConversionTests.cs b/tests/ImageSharp.Tests/ColorProfiles/CmykAndCieLchConversionTests.cs new file mode 100644 index 0000000000..a5230eb312 --- /dev/null +++ b/tests/ImageSharp.Tests/ColorProfiles/CmykAndCieLchConversionTests.cs @@ -0,0 +1,69 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using SixLabors.ImageSharp.ColorProfiles; + +namespace SixLabors.ImageSharp.Tests.ColorProfiles; + +/// +/// Tests - conversions. +/// +public class CmykAndCieLchConversionTests +{ + private static readonly ApproximateColorProfileComparer Comparer = new(.0002f); + + [Theory] + [InlineData(0.360555, 0.1036901, 0.818514, 0.274615, 62.85025, 64.77041, 118.2425)] + public void Convert_Cmyk_To_CieLch(float c, float m, float y, float k, float l, float c2, float h) + { + // Arrange + Cmyk input = new(c, m, y, k); + CieLch expected = new(l, c2, h); + ColorProfileConverter converter = new(); + + Span inputSpan = new Cmyk[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieLch[5]; + + // Act + CieLch actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } + + [Theory] + [InlineData(100, 3.81656E-05, 218.6598, 0, 1.192093E-07, 0, 5.960464E-08)] + [InlineData(62.85025, 64.77041, 118.2425, 0.286581, 0, 0.7975187, 0.34983)] + public void Convert_CieLch_To_Cmyk(float l, float c2, float h, float c, float m, float y, float k) + { + // Arrange + CieLch input = new(l, c2, h); + Cmyk expected = new(c, m, y, k); + ColorProfileConverter converter = new(); + + Span inputSpan = new CieLch[5]; + inputSpan.Fill(input); + + Span actualSpan = new Cmyk[5]; + + // Act + Cmyk actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } +} diff --git a/tests/ImageSharp.Tests/ColorProfiles/CmykAndCieLuvConversionTests.cs b/tests/ImageSharp.Tests/ColorProfiles/CmykAndCieLuvConversionTests.cs new file mode 100644 index 0000000000..cfbd080541 --- /dev/null +++ b/tests/ImageSharp.Tests/ColorProfiles/CmykAndCieLuvConversionTests.cs @@ -0,0 +1,70 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using SixLabors.ImageSharp.ColorProfiles; + +namespace SixLabors.ImageSharp.Tests.ColorProfiles; + +/// +/// Tests - conversions. +/// +public class CmykAndCieLuvConversionTests +{ + private static readonly ApproximateColorProfileComparer Comparer = new(.0002f); + + [Theory] + [InlineData(0, 0, 0, 0, 100, -1.937151E-05, -3.874302E-05)] + [InlineData(0.360555, 0.1036901, 0.818514, 0.274615, 62.85024, -24.4844189, 54.8588524)] + public void Convert_Cmyk_To_CieLuv(float c, float m, float y, float k, float l, float u, float v) + { + // Arrange + Cmyk input = new(c, m, y, k); + CieLuv expected = new(l, u, v); + ColorProfileConverter converter = new(); + + Span inputSpan = new Cmyk[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieLuv[5]; + + // Act + CieLuv actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } + + [Theory] + [InlineData(100, -1.937151E-05, -3.874302E-05, 0, 5.96046448E-08, 0, 0)] + [InlineData(62.85024, -24.4844189, 54.8588524, 0.2865809, 0, 0.797518551, 0.3498301)] + public void Convert_CieLuv_To_Cmyk(float l, float u, float v, float c, float m, float y, float k) + { + // Arrange + CieLuv input = new(l, u, v); + Cmyk expected = new(c, m, y, k); + ColorProfileConverter converter = new(); + + Span inputSpan = new CieLuv[5]; + inputSpan.Fill(input); + + Span actualSpan = new Cmyk[5]; + + // Act + Cmyk actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } +} diff --git a/tests/ImageSharp.Tests/ColorProfiles/CmykAndYCbCrConversionTests.cs b/tests/ImageSharp.Tests/ColorProfiles/CmykAndYCbCrConversionTests.cs index df7490b967..64b47e2b97 100644 --- a/tests/ImageSharp.Tests/ColorProfiles/CmykAndYCbCrConversionTests.cs +++ b/tests/ImageSharp.Tests/ColorProfiles/CmykAndYCbCrConversionTests.cs @@ -15,7 +15,7 @@ public class CmykAndYCbCrConversionTests [Theory] [InlineData(0, 0, 0, 0, 255, 128, 128)] [InlineData(0.360555, 0.1036901, 0.818514, 0.274615, 136.5134, 69.90555, 114.9948)] - public void Convert_Cmyk_to_YCbCr(float c, float m, float y, float k, float y2, float cb, float cr) + public void Convert_Cmyk_To_YCbCr(float c, float m, float y, float k, float y2, float cb, float cr) { // Arrange Cmyk input = new(c, m, y, k); @@ -43,7 +43,7 @@ public class CmykAndYCbCrConversionTests [Theory] [InlineData(255, 128, 128, 0, 0, 0, 5.960464E-08)] [InlineData(136.5134, 69.90555, 114.9948, 0.2891567, 0, 0.7951807, 0.3490196)] - public void Convert_YCbCr_to_Cmyk(float y2, float cb, float cr, float c, float m, float y, float k) + public void Convert_YCbCr_To_Cmyk(float y2, float cb, float cr, float c, float m, float y, float k) { // Arrange YCbCr input = new(y2, cb, cr); diff --git a/tests/ImageSharp.Tests/ColorProfiles/RgbAndCieXyzConversionTest.cs b/tests/ImageSharp.Tests/ColorProfiles/RgbAndCieXyzConversionTest.cs index 783e38e7f0..f84892561f 100644 --- a/tests/ImageSharp.Tests/ColorProfiles/RgbAndCieXyzConversionTest.cs +++ b/tests/ImageSharp.Tests/ColorProfiles/RgbAndCieXyzConversionTest.cs @@ -24,7 +24,7 @@ public class RgbAndCieXyzConversionTest [InlineData(0.00000, 0.00000, 0.82521, 0, 0.181415, 1)] [InlineData(0, 0, 0, 0, 0, 0)] [InlineData(0.297676, 0.267854, 0.045504, 0.720315, 0.509999, 0.168112)] - public void Convert_XYZ_D50_to_SRGB(float x, float y, float z, float r, float g, float b) + public void Convert_XYZ_D50_To_SRGB(float x, float y, float z, float r, float g, float b) { // Arrange CieXyz input = new(x, y, z); @@ -57,7 +57,7 @@ public class RgbAndCieXyzConversionTest [InlineData(0, 0, 1.088830, 0, 0.235458, 1)] [InlineData(0, 0, 0, 0, 0, 0)] [InlineData(0.297676, 0.267854, 0.045504, 0.754903, 0.501961, 0.099998)] - public void Convert_XYZ_D65_to_SRGB(float x, float y, float z, float r, float g, float b) + public void Convert_XYZ_D65_To_SRGB(float x, float y, float z, float r, float g, float b) { // Arrange CieXyz input = new(x, y, z); @@ -90,7 +90,7 @@ public class RgbAndCieXyzConversionTest [InlineData(0, 1, 0, 0.385065, 0.716879, 0.0971045)] [InlineData(0, 0, 1, 0.143080, 0.060617, 0.714173)] [InlineData(0.754902, 0.501961, 0.100000, 0.315757, 0.273323, 0.035506)] - public void Convert_SRGB_to_XYZ_D50(float r, float g, float b, float x, float y, float z) + public void Convert_SRGB_To_XYZ_D50(float r, float g, float b, float x, float y, float z) { // Arrange Rgb input = new(r, g, b); @@ -123,7 +123,7 @@ public class RgbAndCieXyzConversionTest [InlineData(0, 1, 0, 0.357576, 0.715152, 0.119192)] [InlineData(0, 0, 1, 0.1804375, 0.072175, 0.950304)] [InlineData(0.754902, 0.501961, 0.100000, 0.297676, 0.267854, 0.045504)] - public void Convert_SRGB_to_XYZ_D65(float r, float g, float b, float x, float y, float z) + public void Convert_SRGB_To_XYZ_D65(float r, float g, float b, float x, float y, float z) { // Arrange Rgb input = new(r, g, b); diff --git a/tests/ImageSharp.Tests/ColorProfiles/RgbAndHslConversionTest.cs b/tests/ImageSharp.Tests/ColorProfiles/RgbAndHslConversionTest.cs new file mode 100644 index 0000000000..b63b9ca842 --- /dev/null +++ b/tests/ImageSharp.Tests/ColorProfiles/RgbAndHslConversionTest.cs @@ -0,0 +1,83 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using SixLabors.ImageSharp.ColorProfiles; + +namespace SixLabors.ImageSharp.Tests.ColorProfiles.Conversion; + +/// +/// Tests - conversions. +/// +/// +/// Test data generated using: +/// +/// +/// +public class RgbAndHslConversionTest +{ + private static readonly ApproximateColorProfileComparer Comparer = new(.0001f); + + [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(h, s, l); + Rgb expected = new(r, g, b); + ColorProfileConverter converter = new(); + + Span inputSpan = new Hsl[5]; + inputSpan.Fill(input); + + Span actualSpan = new Rgb[5]; + + // Act + Rgb actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } + + [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)] + [InlineData(0.7, 0.8, 0.6, 90, 0.3333, 0.7F)] + public void Convert_Rgb_To_Hsl(float r, float g, float b, float h, float s, float l) + { + // Arrange + Rgb input = new(r, g, b); + Hsl expected = new(h, s, l); + ColorProfileConverter converter = new(); + + Span inputSpan = new Rgb[5]; + inputSpan.Fill(input); + + Span actualSpan = new Hsl[5]; + + // Act + Hsl actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } +} diff --git a/tests/ImageSharp.Tests/ColorProfiles/RgbAndHsvConversionTest.cs b/tests/ImageSharp.Tests/ColorProfiles/RgbAndHsvConversionTest.cs new file mode 100644 index 0000000000..b89b576b6c --- /dev/null +++ b/tests/ImageSharp.Tests/ColorProfiles/RgbAndHsvConversionTest.cs @@ -0,0 +1,81 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using SixLabors.ImageSharp.ColorProfiles; + +namespace SixLabors.ImageSharp.Tests.ColorProfiles; + +/// +/// Tests - conversions. +/// +/// +/// Test data generated using: +/// +/// +public class RgbAndHsvConversionTest +{ + private static readonly ApproximateColorProfileComparer Comparer = new(.0001f); + + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(0, 0, 1, 1, 1, 1)] + [InlineData(360, 1, 1, 1, 0, 0)] + [InlineData(0, 1, 1, 1, 0, 0)] + [InlineData(120, 1, 1, 0, 1, 0)] + [InlineData(240, 1, 1, 0, 0, 1)] + public void Convert_Hsv_To_Rgb(float h, float s, float v, float r, float g, float b) + { + // Arrange + Hsv input = new(h, s, v); + Rgb expected = new(r, g, b); + ColorProfileConverter converter = new(); + + Span inputSpan = new Hsv[5]; + inputSpan.Fill(input); + + Span actualSpan = new Rgb[5]; + + // Act + Rgb actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } + + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(1, 1, 1, 0, 0, 1)] + [InlineData(1, 0, 0, 0, 1, 1)] + [InlineData(0, 1, 0, 120, 1, 1)] + [InlineData(0, 0, 1, 240, 1, 1)] + public void Convert_Rgb_To_Hsv(float r, float g, float b, float h, float s, float v) + { + // Arrange + Rgb input = new(r, g, b); + Hsv expected = new(h, s, v); + ColorProfileConverter converter = new(); + + Span inputSpan = new Rgb[5]; + inputSpan.Fill(input); + + Span actualSpan = new Hsv[5]; + + // Act + Hsv actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } +}