diff --git a/src/ImageProcessor/Colors/ColorTransforms.cs b/src/ImageProcessor/Colors/ColorTransforms.cs index 5b7ca2a41..e5ef27697 100644 --- a/src/ImageProcessor/Colors/ColorTransforms.cs +++ b/src/ImageProcessor/Colors/ColorTransforms.cs @@ -67,29 +67,27 @@ namespace ImageProcessor return new Color(r, g, b); } + /// + /// Allows the implicit conversion of an instance of to a + /// . + /// + /// The instance of to convert. + /// + /// An instance of . + /// public static implicit operator Color(CieXyz color) { - var x = color.X; - var y = color.Y; - var z = color.Z; - - // assume sRGB - // http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html - float r = (x * 3.240969941904521F) + (y * -1.537383177570093F) + (z * -0.498610760293F); - float g = (x * -0.96924363628087F) + (y * 1.87596750150772F) + (z * 0.041555057407175F); - float b = (x * 0.055630079696993F) + (y * -0.20397695888897F) + (z * 1.056971514242878F); - - r = r > 0.0031308 ? (float)((1.055 * Math.Pow(r, 1.0 / 2.4)) - 0.055) : r = (r * 12.92F); + float x = color.X / 100F; + float y = color.Y / 100F; + float z = color.Z / 100F; - g = g > 0.0031308 ? (float)((1.055 * Math.Pow(g, 1.0 / 2.4)) - 0.055) : g = (g * 12.92F); - - b = b > 0.0031308 ? (float)((1.055 * Math.Pow(b, 1.0 / 2.4)) - 0.055) : b = (b * 12.92F); + // Then XYZ to RGB (multiplication by 100 was done above already) - r = Math.Min(Math.Max(0, r), 1); - g = Math.Min(Math.Max(0, g), 1); - b = Math.Min(Math.Max(0, b), 1); + float r = (x * 3.2406F) + (y * -1.5372F) + (z * -0.4986F); + float g = (x * -0.9689F) + (y * 1.8758F) + (z * 0.0415F); + float b = (x * 0.0557F) + (y * -0.2040F) + (z * 1.0570F); - return new Color(r, g, b); + return Color.Compress(new Color(r, g, b)); } /// diff --git a/src/ImageProcessor/Colors/Colorspaces/CieXyz.cs b/src/ImageProcessor/Colors/Colorspaces/CieXyz.cs index db8f57b38..9f577da81 100644 --- a/src/ImageProcessor/Colors/Colorspaces/CieXyz.cs +++ b/src/ImageProcessor/Colors/Colorspaces/CieXyz.cs @@ -34,10 +34,10 @@ namespace ImageProcessor public CieXyz(float x, float y, float z) : this() { - // ToDo: check clamp values - this.backingVector.X = x.Clamp(0, 2); - this.backingVector.Y = y.Clamp(0, 2); - this.backingVector.Z = z.Clamp(0, 2); + // Not clamping as documentation about this space seems to indicate "usual" ranges + this.backingVector.X = x; + this.backingVector.Y = y; + this.backingVector.Z = z; } /// @@ -76,18 +76,15 @@ namespace ImageProcessor /// public static implicit operator CieXyz(Color color) { - var r = color.R; - var g = color.G; - var b = color.B; - - // assume sRGB - r = r > 0.04045 ? (float)Math.Pow(((r + 0.055) / 1.055), 2.4) : (float)(r / 12.92); - g = g > 0.04045 ? (float)Math.Pow(((g + 0.055) / 1.055), 2.4) : (float)(g / 12.92); - b = b > 0.04045 ? (float)Math.Pow(((b + 0.055) / 1.055), 2.4) : (float)(b / 12.92); - - var x = (r * 0.41239079926595F) + (g * 0.35758433938387F) + (b * 0.18048078840183F); - var y = (r * 0.21263900587151F) + (g * 0.71516867876775F) + (b * 0.072192315360733F); - var z = (r * 0.019330818715591F) + (g * 0.11919477979462F) + (b * 0.95053215224966F); + color = Color.Expand(color.Limited); + + float x = (color.R * 0.4124F) + (color.G * 0.3576F) + (color.B * 0.1805F); + float y = (color.R * 0.2126F) + (color.G * 0.7152F) + (color.B * 0.0722F); + float z = (color.R * 0.0193F) + (color.G * 0.1192F) + (color.B * 0.9505F); + + x *= 100F; + y *= 100F; + z *= 100F; return new CieXyz(x, y, z); } diff --git a/tests/ImageProcessor.Tests/Colors/ColorConversionTests.cs b/tests/ImageProcessor.Tests/Colors/ColorConversionTests.cs index f63d4d0f8..0a1563cc6 100644 --- a/tests/ImageProcessor.Tests/Colors/ColorConversionTests.cs +++ b/tests/ImageProcessor.Tests/Colors/ColorConversionTests.cs @@ -91,32 +91,84 @@ namespace ImageProcessor.Tests Assert.Equal(1f, color3.A, 1); } + /// + /// Tests the implicit conversion from to . + /// Comparison values obtained from + /// http://colormine.org/convert/rgb-to-xyz + /// [Fact] public void ColorToCieXyz() { + // White Color color = new Color(1, 1, 1); - CieXyz cieXyz = color; + CieXyz ciexyz = color; + + Assert.Equal(95.05f, ciexyz.X, 3); + Assert.Equal(100.0f, ciexyz.Y, 3); + Assert.Equal(108.900f, ciexyz.Z, 3); + + // Black + Color color2 = new Color(0, 0, 0); + CieXyz ciexyz2 = color2; + Assert.Equal(0, ciexyz2.X, 3); + Assert.Equal(0, ciexyz2.Y, 3); + Assert.Equal(0, ciexyz2.Z, 3); + + //// Grey + Color color3 = new Color(128 / 255f, 128 / 255f, 128 / 255f); + CieXyz ciexyz3 = color3; + Assert.Equal(20.518, ciexyz3.X, 3); + Assert.Equal(21.586, ciexyz3.Y, 3); + Assert.Equal(23.507, ciexyz3.Z, 3); - Assert.Equal(0.9505F, cieXyz.X, 4); - Assert.Equal(1.0000F, cieXyz.Y, 4); - Assert.Equal(1.089F, cieXyz.Z, 3); - + //// Cyan + Color color4 = new Color(0, 1, 1); + CieXyz ciexyz4 = color4; + Assert.Equal(53.810f, ciexyz4.X, 3); + Assert.Equal(78.740f, ciexyz4.Y, 3); + Assert.Equal(106.970f, ciexyz4.Z, 3); } + /// + /// Tests the implicit conversion from to . + /// Comparison values obtained from + /// http://colormine.org/convert/rgb-to-xyz + /// [Fact] public void CieXyzToColor() { - CieXyz cieXyz = new CieXyz(0.25F, 0.40F, 0.10F); - Color color = cieXyz; + // Dark moderate pink. + CieXyz ciexyz = new CieXyz(13.337f, 9.297f, 14.727f); + Color color = ciexyz; - Assert.Equal(0.4174F, color.R, 3); - Assert.Equal(0.7434F, color.G, 3); - Assert.Equal(0.2162F, color.B, 2); + Assert.Equal(128 / 255f, color.R, 3); + Assert.Equal(64 / 255f, color.G, 3); + Assert.Equal(106 / 255f, color.B, 3); - //xyz2rgb([0.25 0.40 0.10]) - //ans = 0.4174 0.7434 0.2152 + // Ochre + CieXyz ciexyz2 = new CieXyz(31.787f, 26.147f, 4.885f); + Color color2 = ciexyz2; + + Assert.Equal(204 / 255f, color2.R, 3); + Assert.Equal(119 / 255f, color2.G, 3); + Assert.Equal(34 / 255f, color2.B, 3); + + //// White + CieXyz ciexyz3 = new CieXyz(0, 0, 0); + Color color3 = ciexyz3; + Assert.Equal(0f, color3.R, 3); + Assert.Equal(0f, color3.G, 3); + Assert.Equal(0f, color3.B, 3); + //// Check others. + Random random = new Random(0); + for (int i = 0; i < 1000; i++) + { + Color color4 = new Color(random.Next(1), random.Next(1), random.Next(1)); + CieXyz ciexyz4 = color4; + Assert.Equal(color4, (Color)ciexyz4); + } } ///