diff --git a/src/ImageSharp/ColorSpaces/CieLab.cs b/src/ImageSharp/ColorSpaces/CieLab.cs index 40dfb9e6a..e572cab92 100644 --- a/src/ImageSharp/ColorSpaces/CieLab.cs +++ b/src/ImageSharp/ColorSpaces/CieLab.cs @@ -173,7 +173,12 @@ namespace ImageSharp.ColorSpaces /// public override int GetHashCode() { - return this.backingVector.GetHashCode(); + unchecked + { + int hashCode = this.WhitePoint.GetHashCode(); + hashCode = (hashCode * 397) ^ this.backingVector.GetHashCode(); + return hashCode; + } } /// @@ -203,7 +208,8 @@ namespace ImageSharp.ColorSpaces [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool Equals(CieLab other) { - return this.backingVector.Equals(other.backingVector); + return this.backingVector.Equals(other.backingVector) + && this.WhitePoint.Equals(other.WhitePoint); } /// @@ -212,7 +218,8 @@ namespace ImageSharp.ColorSpaces { Vector3 result = Vector3.Abs(this.backingVector - other.backingVector); - return result.X <= precision + return this.WhitePoint.Equals(other.WhitePoint) + && result.X <= precision && result.Y <= precision && result.Z <= precision; } diff --git a/src/ImageSharp/ColorSpaces/CieLch.cs b/src/ImageSharp/ColorSpaces/CieLch.cs index 866e1870f..863785623 100644 --- a/src/ImageSharp/ColorSpaces/CieLch.cs +++ b/src/ImageSharp/ColorSpaces/CieLch.cs @@ -173,7 +173,12 @@ namespace ImageSharp.ColorSpaces /// public override int GetHashCode() { - return this.backingVector.GetHashCode(); + unchecked + { + int hashCode = this.WhitePoint.GetHashCode(); + hashCode = (hashCode * 397) ^ this.backingVector.GetHashCode(); + return hashCode; + } } /// @@ -203,7 +208,8 @@ namespace ImageSharp.ColorSpaces [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool Equals(CieLch other) { - return this.backingVector.Equals(other.backingVector); + return this.backingVector.Equals(other.backingVector) + && this.WhitePoint.Equals(other.WhitePoint); } /// @@ -212,9 +218,10 @@ namespace ImageSharp.ColorSpaces { Vector3 result = Vector3.Abs(this.backingVector - other.backingVector); - return result.X <= precision - && result.Y <= precision - && result.Z <= precision; + return this.WhitePoint.Equals(other.WhitePoint) + && result.X <= precision + && result.Y <= precision + && result.Z <= precision; } /// diff --git a/src/ImageSharp/ColorSpaces/CieLuv.cs b/src/ImageSharp/ColorSpaces/CieLuv.cs new file mode 100644 index 000000000..608d24485 --- /dev/null +++ b/src/ImageSharp/ColorSpaces/CieLuv.cs @@ -0,0 +1,229 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageSharp.ColorSpaces +{ + using System; + using System.ComponentModel; + using System.Numerics; + using System.Runtime.CompilerServices; + + /// + /// The CIE 1976 (L*, u*, v*) color space, commonly known by its abbreviation CIELUV, is a color space adopted by the International + /// Commission on Illumination (CIE) in 1976, as a simple-to-compute transformation of the 1931 CIE XYZ color space, but which + /// attempted perceptual uniformity + /// + /// + public struct CieLuv : IColorVector, IEquatable, IAlmostEquatable + { + /// + /// D65 standard illuminant. + /// Used when reference white is not specified explicitly. + /// + public static readonly CieXyz DefaultWhitePoint = Illuminants.D65; + + /// + /// Represents a that has L, U, and V values set to zero. + /// + public static readonly CieLuv Empty = default(CieLuv); + + /// + /// The backing vector for SIMD support. + /// + private readonly Vector3 backingVector; + + /// + /// Initializes a new instance of the struct. + /// + /// The lightness dimension. + /// The blue-yellow chromaticity coordinate of the given whitepoint. + /// The red-green chromaticity coordinate of the given whitepoint. + /// Uses as white point. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public CieLuv(float l, float u, float v) + : this(new Vector3(l, u, v), DefaultWhitePoint) + { + } + + /// + /// Initializes a new instance of the struct. + /// + /// The lightness dimension. + /// The blue-yellow chromaticity coordinate of the given whitepoint. + /// The red-green chromaticity coordinate of the given whitepoint. + /// The reference white point. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public CieLuv(float l, float u, float v, CieXyz whitePoint) + : this(new Vector3(l, u, v), whitePoint) + { + } + + /// + /// Initializes a new instance of the struct. + /// + /// The vector representing the l, u, v components. + /// Uses as white point. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public CieLuv(Vector3 vector) + : this(vector, DefaultWhitePoint) + { + } + + /// + /// Initializes a new instance of the struct. + /// + /// The vector representing the l, u, v components. + /// The reference white point. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public CieLuv(Vector3 vector, CieXyz whitePoint) + : this() + { + this.backingVector = vector; + this.WhitePoint = whitePoint; + } + + /// + /// Gets the reference white point of this color + /// + public CieXyz WhitePoint + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get; + } + + /// + /// Gets the lightness dimension + /// A value usually ranging between 0 and 100. + /// + public float L + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => this.backingVector.X; + } + + /// + /// Gets the blue-yellow chromaticity coordinate of the given whitepoint. + /// A value usually ranging between -100 and 100. + /// + public float U + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => this.backingVector.Y; + } + + /// + /// Gets the red-green chromaticity coordinate of the given whitepoint. + /// A value usually ranging between -100 and 100. + /// + public float V + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => this.backingVector.Z; + } + + /// + /// Gets a value indicating whether this is empty. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public bool IsEmpty => this.Equals(Empty); + + /// + public Vector3 Vector + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => 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. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool operator ==(CieLuv left, CieLuv 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. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool operator !=(CieLuv left, CieLuv right) + { + return !left.Equals(right); + } + + /// + public override int GetHashCode() + { + unchecked + { + int hashCode = this.WhitePoint.GetHashCode(); + hashCode = (hashCode * 397) ^ this.backingVector.GetHashCode(); + return hashCode; + } + } + + /// + public override string ToString() + { + if (this.IsEmpty) + { + return "CieLuv [ Empty ]"; + } + + return $"CieLuv [ L={this.L:#0.##}, U={this.U:#0.##}, V={this.V:#0.##} ]"; + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public override bool Equals(object obj) + { + if (obj is CieLuv) + { + return this.Equals((CieLuv)obj); + } + + return false; + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool Equals(CieLuv other) + { + return this.backingVector.Equals(other.backingVector) + && this.WhitePoint.Equals(other.WhitePoint); + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool AlmostEquals(CieLuv other, float precision) + { + Vector3 result = Vector3.Abs(this.backingVector - other.backingVector); + + return this.WhitePoint.Equals(other.WhitePoint) + && result.X <= precision + && result.Y <= precision + && result.Z <= precision; + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Adapt.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Adapt.cs index 9dede6ee6..f51ce06e6 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Adapt.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Adapt.cs @@ -36,11 +36,11 @@ namespace ImageSharp.ColorSpaces.Conversion } /// - /// Adapts a color from the source working space to working space set in . + /// Adapts color from the source white point to white point set in . /// /// The color to adapt /// The adapted color - public LinearRgb Adapt(LinearRgb color) + public CieLab Adapt(CieLab color) { Guard.NotNull(color, nameof(color)); @@ -49,43 +49,44 @@ namespace ImageSharp.ColorSpaces.Conversion throw new InvalidOperationException("Cannot perform chromatic adaptation, provide a chromatic adaptation method and white point."); } - if (color.WorkingSpace.Equals(this.TargetRgbWorkingSpace)) + if (color.WhitePoint.Equals(this.TargetLabWhitePoint)) { return color; } - // Conversion to XYZ - LinearRgbToCieXyzConverter converterToXYZ = this.GetLinearRgbToCieXyzConverter(color.WorkingSpace); - CieXyz unadapted = converterToXYZ.Convert(color); - - // Adaptation - CieXyz adapted = this.ChromaticAdaptation.Transform(unadapted, color.WorkingSpace.WhitePoint, this.TargetRgbWorkingSpace.WhitePoint); - - // Conversion back to RGB - CieXyzToLinearRgbConverter converterToRGB = this.GetCieXyxToLinearRgbConverter(this.TargetRgbWorkingSpace); - return converterToRGB.Convert(adapted); + CieXyz xyzColor = this.ToCieXyz(color); + return this.ToCieLab(xyzColor); } /// - /// Adapts an color from the source working space to working space set in . + /// Adapts color from the source white point to white point set in . /// /// The color to adapt /// The adapted color - public Rgb Adapt(Rgb color) + public CieLch Adapt(CieLch color) { Guard.NotNull(color, nameof(color)); - LinearRgb linearInput = this.ToLinearRgb(color); - LinearRgb linearOutput = this.Adapt(linearInput); - return this.ToRgb(linearOutput); + if (!this.IsChromaticAdaptationPerformed) + { + throw new InvalidOperationException("Cannot perform chromatic adaptation, provide a chromatic adaptation method and white point."); + } + + if (color.WhitePoint.Equals(this.TargetLabWhitePoint)) + { + return color; + } + + CieLab labColor = this.ToCieLab(color); + return this.ToCieLch(labColor); } /// - /// Adapts color from the source white point to white point set in . + /// Adapts color from the source white point to white point set in . /// /// The color to adapt /// The adapted color - public CieLab Adapt(CieLab color) + public CieLuv Adapt(CieLuv color) { Guard.NotNull(color, nameof(color)); @@ -94,13 +95,13 @@ namespace ImageSharp.ColorSpaces.Conversion throw new InvalidOperationException("Cannot perform chromatic adaptation, provide a chromatic adaptation method and white point."); } - if (color.WhitePoint.Equals(this.TargetLabWhitePoint)) + if (color.WhitePoint.Equals(this.TargetLuvWhitePoint)) { return color; } CieXyz xyzColor = this.ToCieXyz(color); - return this.ToCieLab(xyzColor); + return this.ToCieLuv(xyzColor); } /// @@ -127,11 +128,11 @@ namespace ImageSharp.ColorSpaces.Conversion } /// - /// Adapts color from the source white point to white point set in . + /// Adapts a color from the source working space to working space set in . /// /// The color to adapt /// The adapted color - public CieLch Adapt(CieLch color) + public LinearRgb Adapt(LinearRgb color) { Guard.NotNull(color, nameof(color)); @@ -140,13 +141,35 @@ namespace ImageSharp.ColorSpaces.Conversion throw new InvalidOperationException("Cannot perform chromatic adaptation, provide a chromatic adaptation method and white point."); } - if (color.WhitePoint.Equals(this.TargetLabWhitePoint)) + if (color.WorkingSpace.Equals(this.TargetRgbWorkingSpace)) { return color; } - CieLab labColor = this.ToCieLab(color); - return this.ToCieLch(labColor); + // Conversion to XYZ + LinearRgbToCieXyzConverter converterToXYZ = this.GetLinearRgbToCieXyzConverter(color.WorkingSpace); + CieXyz unadapted = converterToXYZ.Convert(color); + + // Adaptation + CieXyz adapted = this.ChromaticAdaptation.Transform(unadapted, color.WorkingSpace.WhitePoint, this.TargetRgbWorkingSpace.WhitePoint); + + // Conversion back to RGB + CieXyzToLinearRgbConverter converterToRGB = this.GetCieXyxToLinearRgbConverter(this.TargetRgbWorkingSpace); + return converterToRGB.Convert(adapted); + } + + /// + /// Adapts an color from the source working space to working space set in . + /// + /// The color to adapt + /// The adapted color + public Rgb Adapt(Rgb color) + { + Guard.NotNull(color, nameof(color)); + + LinearRgb linearInput = this.ToLinearRgb(color); + LinearRgb linearOutput = this.Adapt(linearInput); + return this.ToRgb(linearOutput); } } } \ No newline at end of file diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLab.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLab.cs index 50cdf98fc..9f6daf7af 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLab.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLab.cs @@ -40,6 +40,19 @@ namespace ImageSharp.ColorSpaces.Conversion return this.Adapt(unadapted); } + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public CieLab ToCieLab(CieLuv color) + { + Guard.NotNull(color, nameof(color)); + + CieXyz xyzColor = this.ToCieXyz(color); + return this.ToCieLab(xyzColor); + } + /// /// Converts a into a /// diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLch.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLch.cs index b46968aa7..ba7b4fed9 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLch.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLch.cs @@ -33,6 +33,19 @@ namespace ImageSharp.ColorSpaces.Conversion return CieLabToCieLchConverter.Convert(adapted); } + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public CieLch ToCieLch(CieLuv color) + { + Guard.NotNull(color, nameof(color)); + + CieXyz xyzColor = this.ToCieXyz(color); + return this.ToCieLch(xyzColor); + } + /// /// Converts a into a /// diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLuv.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLuv.cs new file mode 100644 index 000000000..7012116dc --- /dev/null +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLuv.cs @@ -0,0 +1,178 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageSharp.ColorSpaces.Conversion +{ + using ImageSharp.ColorSpaces; + using ImageSharp.ColorSpaces.Conversion.Implementation.CieLuv; + + /// + /// Converts between color spaces ensuring that the color is adapted using chromatic adaptation. + /// + public partial class ColorSpaceConverter + { + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public CieLuv ToCieLuv(CieLab color) + { + Guard.NotNull(color, nameof(color)); + + CieXyz xyzColor = this.ToCieXyz(color); + return this.ToCieLuv(xyzColor); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public CieLuv ToCieLuv(CieLch color) + { + Guard.NotNull(color, nameof(color)); + + CieXyz xyzColor = this.ToCieXyz(color); + return this.ToCieLuv(xyzColor); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public CieLuv ToCieLuv(CieXyy color) + { + Guard.NotNull(color, nameof(color)); + + CieXyz xyzColor = this.ToCieXyz(color); + return this.ToCieLuv(xyzColor); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public CieLuv ToCieLuv(CieXyz color) + { + Guard.NotNull(color, nameof(color)); + + // Adaptation + CieXyz adapted = !this.WhitePoint.Equals(this.TargetLabWhitePoint) && this.IsChromaticAdaptationPerformed + ? this.ChromaticAdaptation.Transform(color, this.WhitePoint, this.TargetLabWhitePoint) + : color; + + // Conversion + CieXyzToCieLuvConverter converter = new CieXyzToCieLuvConverter(this.TargetLuvWhitePoint); + return converter.Convert(adapted); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public CieLuv ToCieLuv(Cmyk color) + { + Guard.NotNull(color, nameof(color)); + + CieXyz xyzColor = this.ToCieXyz(color); + return this.ToCieLuv(xyzColor); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public CieLuv ToCieLuv(Hsl color) + { + Guard.NotNull(color, nameof(color)); + + CieXyz xyzColor = this.ToCieXyz(color); + return this.ToCieLuv(xyzColor); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public CieLuv ToCieLuv(Hsv color) + { + Guard.NotNull(color, nameof(color)); + + CieXyz xyzColor = this.ToCieXyz(color); + return this.ToCieLuv(xyzColor); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public CieLuv ToCieLuv(HunterLab color) + { + Guard.NotNull(color, nameof(color)); + + CieXyz xyzColor = this.ToCieXyz(color); + return this.ToCieLuv(xyzColor); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public CieLuv ToCieLuv(Lms color) + { + Guard.NotNull(color, nameof(color)); + + CieXyz xyzColor = this.ToCieXyz(color); + return this.ToCieLuv(xyzColor); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public CieLuv ToCieLuv(LinearRgb color) + { + Guard.NotNull(color, nameof(color)); + + CieXyz xyzColor = this.ToCieXyz(color); + return this.ToCieLuv(xyzColor); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public CieLuv ToCieLuv(Rgb color) + { + Guard.NotNull(color, nameof(color)); + + CieXyz xyzColor = this.ToCieXyz(color); + return this.ToCieLuv(xyzColor); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public CieLuv ToCieLuv(YCbCr color) + { + Guard.NotNull(color, nameof(color)); + + CieXyz xyzColor = this.ToCieXyz(color); + return this.ToCieLuv(xyzColor); + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieXyy.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieXyy.cs index 3ebed820f..25055f446 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieXyy.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieXyy.cs @@ -42,6 +42,20 @@ namespace ImageSharp.ColorSpaces.Conversion return this.ToCieXyy(xyzColor); } + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public CieXyy ToCieXyy(CieLuv color) + { + Guard.NotNull(color, nameof(color)); + + CieXyz xyzColor = this.ToCieXyz(color); + + return this.ToCieXyy(xyzColor); + } + /// /// Converts a into a /// diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieXyz.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieXyz.cs index 9c5e38209..e21c7afc7 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieXyz.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieXyz.cs @@ -7,6 +7,7 @@ namespace ImageSharp.ColorSpaces.Conversion { using ImageSharp.ColorSpaces; using ImageSharp.ColorSpaces.Conversion.Implementation.CieLab; + using ImageSharp.ColorSpaces.Conversion.Implementation.CieLuv; using ImageSharp.ColorSpaces.Conversion.Implementation.HunterLab; using ImageSharp.ColorSpaces.Conversion.Implementation.Rgb; @@ -17,6 +18,8 @@ namespace ImageSharp.ColorSpaces.Conversion { private static readonly CieLabToCieXyzConverter CieLabToCieXyzConverter = new CieLabToCieXyzConverter(); + private static readonly CieLuvToCieXyzConverter CieLuvToCieXyzConverter = new CieLuvToCieXyzConverter(); + private static readonly HunterLabToCieXyzConverter HunterLabToCieXyzConverter = new HunterLabToCieXyzConverter(); private LinearRgbToCieXyzConverter linearRgbToCieXyzConverter; @@ -57,6 +60,26 @@ namespace ImageSharp.ColorSpaces.Conversion return this.ToCieXyz(labColor); } + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public CieXyz ToCieXyz(CieLuv color) + { + Guard.NotNull(color, nameof(color)); + + // Conversion + CieXyz unadapted = CieLuvToCieXyzConverter.Convert(color); + + // Adaptation + CieXyz adapted = color.WhitePoint.Equals(this.WhitePoint) || !this.IsChromaticAdaptationPerformed + ? unadapted + : this.Adapt(unadapted, color.WhitePoint); + + return adapted; + } + /// /// Converts a into a /// diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Cmyk.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Cmyk.cs index 1363cf8e4..377d7e290 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Cmyk.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Cmyk.cs @@ -43,6 +43,20 @@ namespace ImageSharp.ColorSpaces.Conversion return this.ToCmyk(xyzColor); } + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public Cmyk ToCmyk(CieLuv color) + { + Guard.NotNull(color, nameof(color)); + + CieXyz xyzColor = this.ToCieXyz(color); + + return this.ToCmyk(xyzColor); + } + /// /// Converts a into a /// diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Hsl.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Hsl.cs index 5ad7c990e..a35f27f34 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Hsl.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Hsl.cs @@ -43,6 +43,20 @@ namespace ImageSharp.ColorSpaces.Conversion return this.ToHsl(xyzColor); } + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public Hsl ToHsl(CieLuv color) + { + Guard.NotNull(color, nameof(color)); + + CieXyz xyzColor = this.ToCieXyz(color); + + return this.ToHsl(xyzColor); + } + /// /// Converts a into a /// diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Hsv.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Hsv.cs index f1f8cf28f..e3c2e0c1d 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Hsv.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Hsv.cs @@ -43,6 +43,20 @@ namespace ImageSharp.ColorSpaces.Conversion return this.ToHsv(xyzColor); } + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public Hsv ToHsv(CieLuv color) + { + Guard.NotNull(color, nameof(color)); + + CieXyz xyzColor = this.ToCieXyz(color); + + return this.ToHsv(xyzColor); + } + /// /// Converts a into a /// diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.HunterLab.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.HunterLab.cs index cad9897fd..c13a6ea84 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.HunterLab.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.HunterLab.cs @@ -38,6 +38,19 @@ namespace ImageSharp.ColorSpaces.Conversion return this.ToHunterLab(xyzColor); } + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public HunterLab ToHunterLab(CieLuv color) + { + Guard.NotNull(color, nameof(color)); + + CieXyz xyzColor = this.ToCieXyz(color); + return this.ToHunterLab(xyzColor); + } + /// /// Converts a into a /// diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.LinearRgb.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.LinearRgb.cs index cfa7663d2..0cc930e08 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.LinearRgb.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.LinearRgb.cs @@ -42,6 +42,19 @@ namespace ImageSharp.ColorSpaces.Conversion return this.ToLinearRgb(xyzColor); } + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public LinearRgb ToLinearRgb(CieLuv color) + { + Guard.NotNull(color, nameof(color)); + + CieXyz xyzColor = this.ToCieXyz(color); + return this.ToLinearRgb(xyzColor); + } + /// /// Converts a into a /// diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Lms.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Lms.cs index 40b4db989..2b0979a02 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Lms.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Lms.cs @@ -38,6 +38,19 @@ namespace ImageSharp.ColorSpaces.Conversion return this.ToLms(xyzColor); } + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public Lms ToLms(CieLuv color) + { + Guard.NotNull(color, nameof(color)); + + CieXyz xyzColor = this.ToCieXyz(color); + return this.ToLms(xyzColor); + } + /// /// Converts a into a /// diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Rgb.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Rgb.cs index d405bd365..5f669fbcf 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Rgb.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Rgb.cs @@ -40,6 +40,19 @@ namespace ImageSharp.ColorSpaces.Conversion return this.ToRgb(xyzColor); } + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public Rgb ToRgb(CieLuv color) + { + Guard.NotNull(color, nameof(color)); + + CieXyz xyzColor = this.ToCieXyz(color); + return this.ToRgb(xyzColor); + } + /// /// Converts a into a /// diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.YCbCr.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.YCbCr.cs index 44612c318..cfd71081b 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.YCbCr.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.YCbCr.cs @@ -43,6 +43,20 @@ namespace ImageSharp.ColorSpaces.Conversion return this.ToYCbCr(xyzColor); } + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public YCbCr ToYCbCr(CieLuv color) + { + Guard.NotNull(color, nameof(color)); + + CieXyz xyzColor = this.ToCieXyz(color); + + return this.ToYCbCr(xyzColor); + } + /// /// Converts a into a /// diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.cs index 61fa9c5af..92644a85e 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.cs @@ -33,6 +33,7 @@ namespace ImageSharp.ColorSpaces.Conversion this.WhitePoint = DefaultWhitePoint; this.LmsAdaptationMatrix = CieXyzAndLmsConverter.DefaultTransformationMatrix; this.ChromaticAdaptation = new VonKriesChromaticAdaptation(this.cachedCieXyzAndLmsConverter, this.cachedCieXyzAndLmsConverter); + this.TargetLuvWhitePoint = CieLuv.DefaultWhitePoint; this.TargetLabWhitePoint = CieLab.DefaultWhitePoint; this.TargetHunterLabWhitePoint = HunterLab.DefaultWhitePoint; this.TargetRgbWorkingSpace = Rgb.DefaultWorkingSpace; @@ -44,6 +45,12 @@ namespace ImageSharp.ColorSpaces.Conversion /// public CieXyz WhitePoint { get; set; } + /// + /// Gets or sets the white point used *when creating* Luv/LChuv colors. (Luv/LChuv colors on the input already contain the white point information) + /// Defaults to: . + /// + public CieXyz TargetLuvWhitePoint { get; set; } + /// /// Gets or sets the white point used *when creating* Lab/LChab colors. (Lab/LChab colors on the input already contain the white point information) /// Defaults to: . diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLuv/CieLuvToCieXyzConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLuv/CieLuvToCieXyzConverter.cs new file mode 100644 index 000000000..36c458828 --- /dev/null +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLuv/CieLuvToCieXyzConverter.cs @@ -0,0 +1,80 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageSharp.ColorSpaces.Conversion.Implementation.CieLuv +{ + using System.Runtime.CompilerServices; + using ImageSharp.ColorSpaces; + + /// + /// Converts from to . + /// + internal class CieLuvToCieXyzConverter : IColorConversion + { + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public CieXyz Convert(CieLuv input) + { + DebugGuard.NotNull(input, nameof(input)); + + // Conversion algorithm described here: http://www.brucelindbloom.com/index.html?Eqn_Luv_to_XYZ.html + float l = input.L, u = input.U, v = input.V; + + float u0 = ComputeU0(input.WhitePoint); + float v0 = ComputeV0(input.WhitePoint); + + float y = l > CieConstants.Kappa * CieConstants.Epsilon + ? MathF.Pow((l + 16) / 116, 3) + : l / CieConstants.Kappa; + + float a = ((52 * l / (u + (13 * l * u0))) - 1) / 3; + float b = -5 * y; + float c = -0.3333333F; + float d = y * ((39 * l / (v + (13 * l * v0))) - 5); + + float x = (d - b) / (a - c); + float z = (x * a) + b; + + if (float.IsNaN(x) || x < 0) + { + x = 0; + } + + if (float.IsNaN(y) || y < 0) + { + y = 0; + } + + if (float.IsNaN(z) || z < 0) + { + z = 0; + } + + return new CieXyz(x, y, z); + } + + /// + /// Calculates the blue-yellow chromacity based on the given whitepoint. + /// + /// The whitepoint + /// The + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static float ComputeU0(CieXyz input) + { + return (4 * input.X) / (input.X + (15 * input.Y) + (3 * input.Z)); + } + + /// + /// Calculates the red-green chromacity based on the given whitepoint. + /// + /// The whitepoint + /// The + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static float ComputeV0(CieXyz input) + { + return (9 * input.Y) / (input.X + (15 * input.Y) + (3 * input.Z)); + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLuv/CieXyzToCieLuvConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLuv/CieXyzToCieLuvConverter.cs new file mode 100644 index 000000000..3883f3a1e --- /dev/null +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLuv/CieXyzToCieLuvConverter.cs @@ -0,0 +1,102 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageSharp.ColorSpaces.Conversion.Implementation.CieLuv +{ + using System.Runtime.CompilerServices; + + using ImageSharp.ColorSpaces; + + /// + /// Converts from to . + /// + internal class CieXyzToCieLuvConverter : IColorConversion + { + /// + /// Initializes a new instance of the class. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public CieXyzToCieLuvConverter() + : this(CieLuv.DefaultWhitePoint) + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The target reference luv white point + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public CieXyzToCieLuvConverter(CieXyz luvWhitePoint) + { + this.LuvWhitePoint = luvWhitePoint; + } + + /// + /// Gets the target reference whitepoint. When not set, is used. + /// + public CieXyz LuvWhitePoint + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get; + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public CieLuv Convert(CieXyz input) + { + DebugGuard.NotNull(input, nameof(input)); + + // Conversion algorithm described here: http://www.brucelindbloom.com/index.html?Eqn_XYZ_to_Luv.html + float yr = input.Y / this.LuvWhitePoint.Y; + float up = ComputeUp(input); + float vp = ComputeVp(input); + float upr = ComputeUp(this.LuvWhitePoint); + float vpr = ComputeVp(this.LuvWhitePoint); + + float l = yr > CieConstants.Epsilon ? ((116 * MathF.Pow(yr, 0.3333333F)) - 16F) : (CieConstants.Kappa * yr); + + if (float.IsNaN(l) || l < 0) + { + l = 0; + } + + float u = 13 * l * (up - upr); + float v = 13 * l * (vp - vpr); + + if (float.IsNaN(u)) + { + u = 0; + } + + if (float.IsNaN(v)) + { + v = 0; + } + + return new CieLuv(l, u, v, this.LuvWhitePoint); + } + + /// + /// Calculates the blue-yellow chromacity based on the given whitepoint. + /// + /// The whitepoint + /// The + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static float ComputeUp(CieXyz input) + { + return (4 * input.X) / (input.X + (15 * input.Y) + (3 * input.Z)); + } + + /// + /// Calculates the red-green chromacity based on the given whitepoint. + /// + /// The whitepoint + /// The + private static float ComputeVp(CieXyz input) + { + return (9 * input.Y) / (input.X + (15 * input.Y) + (3 * input.Z)); + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/ColorSpaces/HunterLab.cs b/src/ImageSharp/ColorSpaces/HunterLab.cs index c273c1213..a5f63b5f9 100644 --- a/src/ImageSharp/ColorSpaces/HunterLab.cs +++ b/src/ImageSharp/ColorSpaces/HunterLab.cs @@ -169,7 +169,12 @@ namespace ImageSharp.ColorSpaces /// public override int GetHashCode() { - return this.backingVector.GetHashCode(); + unchecked + { + int hashCode = this.WhitePoint.GetHashCode(); + hashCode = (hashCode * 397) ^ this.backingVector.GetHashCode(); + return hashCode; + } } /// @@ -199,7 +204,8 @@ namespace ImageSharp.ColorSpaces [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool Equals(HunterLab other) { - return this.backingVector.Equals(other.backingVector); + return this.backingVector.Equals(other.backingVector) + && this.WhitePoint.Equals(other.WhitePoint); } /// @@ -208,9 +214,10 @@ namespace ImageSharp.ColorSpaces { Vector3 result = Vector3.Abs(this.backingVector - other.backingVector); - return result.X <= precision - && result.Y <= precision - && result.Z <= precision; + return this.WhitePoint.Equals(other.WhitePoint) + && result.X <= precision + && result.Y <= precision + && result.Z <= precision; } } } \ No newline at end of file diff --git a/src/ImageSharp/ColorSpaces/Lms.cs b/src/ImageSharp/ColorSpaces/Lms.cs index 2b6eae809..0d08659e6 100644 --- a/src/ImageSharp/ColorSpaces/Lms.cs +++ b/src/ImageSharp/ColorSpaces/Lms.cs @@ -18,7 +18,7 @@ namespace ImageSharp.ColorSpaces public struct Lms : IColorVector, IEquatable, IAlmostEquatable { /// - /// Represents a that has Y, Cb, and Cr values set to zero. + /// Represents a that has L, M, and S values set to zero. /// public static readonly Lms Empty = default(Lms); @@ -42,7 +42,7 @@ namespace ImageSharp.ColorSpaces /// /// Initializes a new instance of the struct. /// - /// The vector representing the x, y, z components. + /// The vector representing the l, m, s components. [MethodImpl(MethodImplOptions.AggressiveInlining)] public Lms(Vector3 vector) : this() diff --git a/tests/ImageSharp.Tests/Colors/Colorspaces/CieLabAndCieLchConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/CieLabAndCieLchConversionTests.cs similarity index 98% rename from tests/ImageSharp.Tests/Colors/Colorspaces/CieLabAndCieLchConversionTests.cs rename to tests/ImageSharp.Tests/Colorspaces/CieLabAndCieLchConversionTests.cs index 554ff9383..1248b0c7f 100644 --- a/tests/ImageSharp.Tests/Colors/Colorspaces/CieLabAndCieLchConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/CieLabAndCieLchConversionTests.cs @@ -1,4 +1,4 @@ -namespace ImageSharp.Tests.Colors.Colorspaces +namespace ImageSharp.Tests.Colorspaces { using System.Collections.Generic; using ImageSharp.ColorSpaces; diff --git a/tests/ImageSharp.Tests/Colors/Colorspaces/CieXyzAndCieLabConversionTest.cs b/tests/ImageSharp.Tests/Colorspaces/CieXyzAndCieLabConversionTest.cs similarity index 100% rename from tests/ImageSharp.Tests/Colors/Colorspaces/CieXyzAndCieLabConversionTest.cs rename to tests/ImageSharp.Tests/Colorspaces/CieXyzAndCieLabConversionTest.cs diff --git a/tests/ImageSharp.Tests/Colorspaces/CieXyzAndCieLuvConversionTest.cs b/tests/ImageSharp.Tests/Colorspaces/CieXyzAndCieLuvConversionTest.cs new file mode 100644 index 000000000..a93cf19c8 --- /dev/null +++ b/tests/ImageSharp.Tests/Colorspaces/CieXyzAndCieLuvConversionTest.cs @@ -0,0 +1,71 @@ +namespace ImageSharp.Tests +{ + using System.Collections.Generic; + using ImageSharp.ColorSpaces; + using ImageSharp.ColorSpaces.Conversion; + + using Xunit; + + /// + /// Tests - conversions. + /// + /// + /// Test data generated using: + /// + /// + public class CieXyzAndCieLuvConversionTest + { + private static readonly IEqualityComparer FloatRoundingComparer = new FloatRoundingComparer(4); + + /// + /// Tests conversion from to (). + /// + [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)] + [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 + CieLuv input = new CieLuv(l, u, v, Illuminants.D65); + ColorSpaceConverter converter = new ColorSpaceConverter { WhitePoint = Illuminants.D65, TargetLabWhitePoint = Illuminants.D65 }; + + // Act + CieXyz output = converter.ToCieXyz(input); + + // Assert + Assert.Equal(x, output.X, FloatRoundingComparer); + Assert.Equal(y, output.Y, FloatRoundingComparer); + Assert.Equal(z, output.Z, FloatRoundingComparer); + } + + /// + /// Tests conversion from () to . + /// + [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) + { + // Arrange + CieXyz input = new CieXyz(x, y, z); + ColorSpaceConverter converter = new ColorSpaceConverter { WhitePoint = Illuminants.D65, TargetLabWhitePoint = Illuminants.D65 }; + + // Act + CieLuv output = converter.ToCieLuv(input); + + // Assert + Assert.Equal(l, output.L, FloatRoundingComparer); + Assert.Equal(u, output.U, FloatRoundingComparer); + Assert.Equal(v, output.V, FloatRoundingComparer); + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Colors/Colorspaces/CieXyzAndCieXyyConversionTest.cs b/tests/ImageSharp.Tests/Colorspaces/CieXyzAndCieXyyConversionTest.cs similarity index 97% rename from tests/ImageSharp.Tests/Colors/Colorspaces/CieXyzAndCieXyyConversionTest.cs rename to tests/ImageSharp.Tests/Colorspaces/CieXyzAndCieXyyConversionTest.cs index 455d58394..9b441f452 100644 --- a/tests/ImageSharp.Tests/Colors/Colorspaces/CieXyzAndCieXyyConversionTest.cs +++ b/tests/ImageSharp.Tests/Colorspaces/CieXyzAndCieXyyConversionTest.cs @@ -1,4 +1,4 @@ -namespace ImageSharp.Tests.Colors.Colorspaces +namespace ImageSharp.Tests.Colorspaces { using System.Collections.Generic; diff --git a/tests/ImageSharp.Tests/Colors/Colorspaces/CieXyzAndHunterLabConversionTest.cs b/tests/ImageSharp.Tests/Colorspaces/CieXyzAndHunterLabConversionTest.cs similarity index 100% rename from tests/ImageSharp.Tests/Colors/Colorspaces/CieXyzAndHunterLabConversionTest.cs rename to tests/ImageSharp.Tests/Colorspaces/CieXyzAndHunterLabConversionTest.cs diff --git a/tests/ImageSharp.Tests/Colors/Colorspaces/CieXyzAndLmsConversionTest.cs b/tests/ImageSharp.Tests/Colorspaces/CieXyzAndLmsConversionTest.cs similarity index 100% rename from tests/ImageSharp.Tests/Colors/Colorspaces/CieXyzAndLmsConversionTest.cs rename to tests/ImageSharp.Tests/Colorspaces/CieXyzAndLmsConversionTest.cs diff --git a/tests/ImageSharp.Tests/Colors/Colorspaces/ColorConverterAdaptTest.cs b/tests/ImageSharp.Tests/Colorspaces/ColorConverterAdaptTest.cs similarity index 97% rename from tests/ImageSharp.Tests/Colors/Colorspaces/ColorConverterAdaptTest.cs rename to tests/ImageSharp.Tests/Colorspaces/ColorConverterAdaptTest.cs index 331af82ff..6c03028c1 100644 --- a/tests/ImageSharp.Tests/Colors/Colorspaces/ColorConverterAdaptTest.cs +++ b/tests/ImageSharp.Tests/Colorspaces/ColorConverterAdaptTest.cs @@ -9,7 +9,7 @@ namespace ImageSharp.Tests using Xunit; /// - /// Tests methods. + /// Tests methods. /// Test data generated using: /// /// @@ -63,7 +63,7 @@ namespace ImageSharp.Tests [Theory] [InlineData(0, 0, 0, 0, 0, 0)] [InlineData(22, 33, 1, 22.269869, 32.841164, 1.633926)] - public void Adapt_Lab_D65_To_D50(float l1, float a1, float b1, float l2, float a2, float b2) + public void Adapt_Lab_D50_To_D65(float l1, float a1, float b1, float l2, float a2, float b2) { // Arrange CieLab input = new CieLab(l1, a1, b1, Illuminants.D65); diff --git a/tests/ImageSharp.Tests/Colors/Colorspaces/ColorSpaceEqualityTests.cs b/tests/ImageSharp.Tests/Colorspaces/ColorSpaceEqualityTests.cs similarity index 96% rename from tests/ImageSharp.Tests/Colors/Colorspaces/ColorSpaceEqualityTests.cs rename to tests/ImageSharp.Tests/Colorspaces/ColorSpaceEqualityTests.cs index d0aa5fb1a..07c726733 100644 --- a/tests/ImageSharp.Tests/Colors/Colorspaces/ColorSpaceEqualityTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/ColorSpaceEqualityTests.cs @@ -21,6 +21,7 @@ namespace ImageSharp.Tests.Colors { CieLab.Empty, CieLch.Empty, + CieLuv.Empty, CieXyz.Empty, CieXyy.Empty, Hsl.Empty, @@ -37,6 +38,7 @@ namespace ImageSharp.Tests.Colors { { new CieLab(Vector3.One), new CieLab(Vector3.One), typeof(CieLab) }, { new CieLch(Vector3.One), new CieLch(Vector3.One), typeof(CieLch) }, + { new CieLuv(Vector3.One), new CieLuv(Vector3.One), typeof(CieLuv) }, { new CieXyz(Vector3.One), new CieXyz(Vector3.One), typeof(CieXyz) }, { new CieXyy(Vector3.One), new CieXyy(Vector3.One), typeof(CieXyy) }, { new HunterLab(Vector3.One), new HunterLab(Vector3.One), typeof(HunterLab) }, @@ -54,6 +56,7 @@ namespace ImageSharp.Tests.Colors // Valid object against null { new CieLab(Vector3.One), null, typeof(CieLab) }, { new CieLch(Vector3.One), null, typeof(CieLch) }, + { new CieLuv(Vector3.One), null, typeof(CieLuv) }, { new CieXyz(Vector3.One), null, typeof(CieXyz) }, { new CieXyy(Vector3.One), null, typeof(CieXyy) }, { new HunterLab(Vector3.One), null, typeof(HunterLab) }, @@ -70,6 +73,7 @@ namespace ImageSharp.Tests.Colors { // Valid objects of different types but not equal { new CieLab(Vector3.One), new CieLch(Vector3.Zero), null }, + { new CieLuv(Vector3.One), new CieLuv(Vector3.Zero), null }, { 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 }, @@ -84,6 +88,7 @@ namespace ImageSharp.Tests.Colors // Valid objects of the same type but not equal { new CieLab(Vector3.One), new CieLab(Vector3.Zero), typeof(CieLab) }, { new CieLch(Vector3.One), new CieLch(Vector3.Zero), typeof(CieLch) }, + { new CieLuv(Vector3.One), new CieLuv(Vector3.Zero), typeof(CieLuv) }, { new CieXyz(Vector3.One), new CieXyz(Vector3.Zero), typeof(CieXyz) }, { new CieXyy(Vector3.One), new CieXyy(Vector3.Zero), typeof(CieXyy) }, { new HunterLab(Vector3.One), new HunterLab(Vector3.Zero), typeof(HunterLab) }, @@ -106,6 +111,8 @@ namespace ImageSharp.Tests.Colors { new CieLab(0F, 0F, 0F), new CieLab(0F, .001F, 0F), typeof(CieLab), .001F }, { new CieLab(0F, 0F, 0F), new CieLab(0F, 0F, .0001F), typeof(CieLab), .0001F }, { new CieLab(0F, 0F, 0F), new CieLab(.0005F, 0F, 0F), typeof(CieLab), .0005F }, + { new CieLch(0F, 0F, 0F), new CieLch(0F, .001F, 0F), typeof(CieLch), .001F }, + { new CieLuv(0F, 0F, 0F), new CieLuv(0F, .001F, 0F), typeof(CieLuv), .001F }, { new CieXyz(380F, 380F, 380F), new CieXyz(380F, 380F, 380F), typeof(CieXyz), 0F }, { 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 }, diff --git a/tests/ImageSharp.Tests/Colors/Colorspaces/RgbAndCieXyzConversionTest.cs b/tests/ImageSharp.Tests/Colorspaces/RgbAndCieXyzConversionTest.cs similarity index 100% rename from tests/ImageSharp.Tests/Colors/Colorspaces/RgbAndCieXyzConversionTest.cs rename to tests/ImageSharp.Tests/Colorspaces/RgbAndCieXyzConversionTest.cs diff --git a/tests/ImageSharp.Tests/Colors/Colorspaces/RgbAndCmykConversionTest.cs b/tests/ImageSharp.Tests/Colorspaces/RgbAndCmykConversionTest.cs similarity index 97% rename from tests/ImageSharp.Tests/Colors/Colorspaces/RgbAndCmykConversionTest.cs rename to tests/ImageSharp.Tests/Colorspaces/RgbAndCmykConversionTest.cs index b1a41fcae..8fe64e915 100644 --- a/tests/ImageSharp.Tests/Colors/Colorspaces/RgbAndCmykConversionTest.cs +++ b/tests/ImageSharp.Tests/Colorspaces/RgbAndCmykConversionTest.cs @@ -1,4 +1,4 @@ -namespace ImageSharp.Tests.Colors.Colorspaces +namespace ImageSharp.Tests.Colorspaces { using System.Collections.Generic; diff --git a/tests/ImageSharp.Tests/Colors/Colorspaces/RgbAndHslConversionTest.cs b/tests/ImageSharp.Tests/Colorspaces/RgbAndHslConversionTest.cs similarity index 97% rename from tests/ImageSharp.Tests/Colors/Colorspaces/RgbAndHslConversionTest.cs rename to tests/ImageSharp.Tests/Colorspaces/RgbAndHslConversionTest.cs index 3ea4aab18..fa02f887f 100644 --- a/tests/ImageSharp.Tests/Colors/Colorspaces/RgbAndHslConversionTest.cs +++ b/tests/ImageSharp.Tests/Colorspaces/RgbAndHslConversionTest.cs @@ -1,4 +1,4 @@ -namespace ImageSharp.Tests.Colors.Colorspaces +namespace ImageSharp.Tests.Colorspaces { using System.Collections.Generic; diff --git a/tests/ImageSharp.Tests/Colors/Colorspaces/RgbAndHsvConversionTest.cs b/tests/ImageSharp.Tests/Colorspaces/RgbAndHsvConversionTest.cs similarity index 97% rename from tests/ImageSharp.Tests/Colors/Colorspaces/RgbAndHsvConversionTest.cs rename to tests/ImageSharp.Tests/Colorspaces/RgbAndHsvConversionTest.cs index 0ee7e81f8..f8d8c773a 100644 --- a/tests/ImageSharp.Tests/Colors/Colorspaces/RgbAndHsvConversionTest.cs +++ b/tests/ImageSharp.Tests/Colorspaces/RgbAndHsvConversionTest.cs @@ -1,4 +1,4 @@ -namespace ImageSharp.Tests.Colors.Colorspaces +namespace ImageSharp.Tests.Colorspaces { using System.Collections.Generic; diff --git a/tests/ImageSharp.Tests/Colors/Colorspaces/RgbAndYCbCrConversionTest.cs b/tests/ImageSharp.Tests/Colorspaces/RgbAndYCbCrConversionTest.cs similarity index 97% rename from tests/ImageSharp.Tests/Colors/Colorspaces/RgbAndYCbCrConversionTest.cs rename to tests/ImageSharp.Tests/Colorspaces/RgbAndYCbCrConversionTest.cs index 05898016c..3f741ea3d 100644 --- a/tests/ImageSharp.Tests/Colors/Colorspaces/RgbAndYCbCrConversionTest.cs +++ b/tests/ImageSharp.Tests/Colorspaces/RgbAndYCbCrConversionTest.cs @@ -1,4 +1,4 @@ -namespace ImageSharp.Tests.Colors.Colorspaces +namespace ImageSharp.Tests.Colorspaces { using System.Collections.Generic; diff --git a/tests/ImageSharp.Tests/Helpers/MathFTests.cs b/tests/ImageSharp.Tests/Helpers/MathFTests.cs index e9a964f78..62a971f9f 100644 --- a/tests/ImageSharp.Tests/Helpers/MathFTests.cs +++ b/tests/ImageSharp.Tests/Helpers/MathFTests.cs @@ -88,7 +88,7 @@ public void MathF_SinC_Is_Equal() { float f = 1.2345F; - float expected; + float expected = 1F; if (Math.Abs(f) > Constants.Epsilon) { f *= (float)Math.PI; @@ -96,11 +96,7 @@ expected = Math.Abs(sinC) < Constants.Epsilon ? 0F : sinC; } - else - { - expected = 1F; - } - + Assert.Equal(MathF.SinC(1.2345F), expected); }