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);
}