Browse Source

Add CieLuv

af/merge-core
James Jackson-South 9 years ago
parent
commit
84a1273167
  1. 13
      src/ImageSharp/ColorSpaces/CieLab.cs
  2. 17
      src/ImageSharp/ColorSpaces/CieLch.cs
  3. 229
      src/ImageSharp/ColorSpaces/CieLuv.cs
  4. 77
      src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Adapt.cs
  5. 13
      src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLab.cs
  6. 13
      src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLch.cs
  7. 178
      src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLuv.cs
  8. 14
      src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieXyy.cs
  9. 23
      src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieXyz.cs
  10. 14
      src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Cmyk.cs
  11. 14
      src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Hsl.cs
  12. 14
      src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Hsv.cs
  13. 13
      src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.HunterLab.cs
  14. 13
      src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.LinearRgb.cs
  15. 13
      src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Lms.cs
  16. 13
      src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Rgb.cs
  17. 14
      src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.YCbCr.cs
  18. 7
      src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.cs
  19. 80
      src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLuv/CieLuvToCieXyzConverter.cs
  20. 102
      src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLuv/CieXyzToCieLuvConverter.cs
  21. 17
      src/ImageSharp/ColorSpaces/HunterLab.cs
  22. 4
      src/ImageSharp/ColorSpaces/Lms.cs
  23. 2
      tests/ImageSharp.Tests/Colorspaces/CieLabAndCieLchConversionTests.cs
  24. 0
      tests/ImageSharp.Tests/Colorspaces/CieXyzAndCieLabConversionTest.cs
  25. 71
      tests/ImageSharp.Tests/Colorspaces/CieXyzAndCieLuvConversionTest.cs
  26. 2
      tests/ImageSharp.Tests/Colorspaces/CieXyzAndCieXyyConversionTest.cs
  27. 0
      tests/ImageSharp.Tests/Colorspaces/CieXyzAndHunterLabConversionTest.cs
  28. 0
      tests/ImageSharp.Tests/Colorspaces/CieXyzAndLmsConversionTest.cs
  29. 4
      tests/ImageSharp.Tests/Colorspaces/ColorConverterAdaptTest.cs
  30. 7
      tests/ImageSharp.Tests/Colorspaces/ColorSpaceEqualityTests.cs
  31. 0
      tests/ImageSharp.Tests/Colorspaces/RgbAndCieXyzConversionTest.cs
  32. 2
      tests/ImageSharp.Tests/Colorspaces/RgbAndCmykConversionTest.cs
  33. 2
      tests/ImageSharp.Tests/Colorspaces/RgbAndHslConversionTest.cs
  34. 2
      tests/ImageSharp.Tests/Colorspaces/RgbAndHsvConversionTest.cs
  35. 2
      tests/ImageSharp.Tests/Colorspaces/RgbAndYCbCrConversionTest.cs
  36. 8
      tests/ImageSharp.Tests/Helpers/MathFTests.cs

13
src/ImageSharp/ColorSpaces/CieLab.cs

@ -173,7 +173,12 @@ namespace ImageSharp.ColorSpaces
/// <inheritdoc/>
public override int GetHashCode()
{
return this.backingVector.GetHashCode();
unchecked
{
int hashCode = this.WhitePoint.GetHashCode();
hashCode = (hashCode * 397) ^ this.backingVector.GetHashCode();
return hashCode;
}
}
/// <inheritdoc/>
@ -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);
}
/// <inheritdoc/>
@ -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;
}

17
src/ImageSharp/ColorSpaces/CieLch.cs

@ -173,7 +173,12 @@ namespace ImageSharp.ColorSpaces
/// <inheritdoc/>
public override int GetHashCode()
{
return this.backingVector.GetHashCode();
unchecked
{
int hashCode = this.WhitePoint.GetHashCode();
hashCode = (hashCode * 397) ^ this.backingVector.GetHashCode();
return hashCode;
}
}
/// <inheritdoc/>
@ -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);
}
/// <inheritdoc/>
@ -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;
}
/// <summary>

229
src/ImageSharp/ColorSpaces/CieLuv.cs

@ -0,0 +1,229 @@
// <copyright file="CieLuv.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp.ColorSpaces
{
using System;
using System.ComponentModel;
using System.Numerics;
using System.Runtime.CompilerServices;
/// <summary>
/// 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
/// <see href="https://en.wikipedia.org/wiki/CIELUV"/>
/// </summary>
public struct CieLuv : IColorVector, IEquatable<CieLuv>, IAlmostEquatable<CieLuv, float>
{
/// <summary>
/// D65 standard illuminant.
/// Used when reference white is not specified explicitly.
/// </summary>
public static readonly CieXyz DefaultWhitePoint = Illuminants.D65;
/// <summary>
/// Represents a <see cref="CieLuv"/> that has L, U, and V values set to zero.
/// </summary>
public static readonly CieLuv Empty = default(CieLuv);
/// <summary>
/// The backing vector for SIMD support.
/// </summary>
private readonly Vector3 backingVector;
/// <summary>
/// Initializes a new instance of the <see cref="CieLuv"/> struct.
/// </summary>
/// <param name="l">The lightness dimension.</param>
/// <param name="u">The blue-yellow chromaticity coordinate of the given whitepoint.</param>
/// <param name="v">The red-green chromaticity coordinate of the given whitepoint.</param>
/// <remarks>Uses <see cref="DefaultWhitePoint"/> as white point.</remarks>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public CieLuv(float l, float u, float v)
: this(new Vector3(l, u, v), DefaultWhitePoint)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="CieLuv"/> struct.
/// </summary>
/// <param name="l">The lightness dimension.</param>
/// <param name="u">The blue-yellow chromaticity coordinate of the given whitepoint.</param>
/// <param name="v">The red-green chromaticity coordinate of the given whitepoint.</param>
/// <param name="whitePoint">The reference white point. <see cref="Illuminants"/></param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public CieLuv(float l, float u, float v, CieXyz whitePoint)
: this(new Vector3(l, u, v), whitePoint)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="CieLuv"/> struct.
/// </summary>
/// <param name="vector">The vector representing the l, u, v components.</param>
/// <remarks>Uses <see cref="DefaultWhitePoint"/> as white point.</remarks>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public CieLuv(Vector3 vector)
: this(vector, DefaultWhitePoint)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="CieLuv"/> struct.
/// </summary>
/// <param name="vector">The vector representing the l, u, v components.</param>
/// <param name="whitePoint">The reference white point. <see cref="Illuminants"/></param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public CieLuv(Vector3 vector, CieXyz whitePoint)
: this()
{
this.backingVector = vector;
this.WhitePoint = whitePoint;
}
/// <summary>
/// Gets the reference white point of this color
/// </summary>
public CieXyz WhitePoint
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get;
}
/// <summary>
/// Gets the lightness dimension
/// <remarks>A value usually ranging between 0 and 100.</remarks>
/// </summary>
public float L
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => this.backingVector.X;
}
/// <summary>
/// Gets the blue-yellow chromaticity coordinate of the given whitepoint.
/// <remarks>A value usually ranging between -100 and 100.</remarks>
/// </summary>
public float U
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => this.backingVector.Y;
}
/// <summary>
/// Gets the red-green chromaticity coordinate of the given whitepoint.
/// <remarks>A value usually ranging between -100 and 100.</remarks>
/// </summary>
public float V
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => this.backingVector.Z;
}
/// <summary>
/// Gets a value indicating whether this <see cref="CieLuv"/> is empty.
/// </summary>
[EditorBrowsable(EditorBrowsableState.Never)]
public bool IsEmpty => this.Equals(Empty);
/// <inheritdoc />
public Vector3 Vector
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => this.backingVector;
}
/// <summary>
/// Compares two <see cref="CieLuv"/> objects for equality.
/// </summary>
/// <param name="left">
/// The <see cref="CieLuv"/> on the left side of the operand.
/// </param>
/// <param name="right">
/// The <see cref="CieLuv"/> on the right side of the operand.
/// </param>
/// <returns>
/// True if the current left is equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator ==(CieLuv left, CieLuv right)
{
return left.Equals(right);
}
/// <summary>
/// Compares two <see cref="CieLuv"/> objects for inequality.
/// </summary>
/// <param name="left">
/// The <see cref="CieLuv"/> on the left side of the operand.
/// </param>
/// <param name="right">
/// The <see cref="CieLuv"/> on the right side of the operand.
/// </param>
/// <returns>
/// True if the current left is unequal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator !=(CieLuv left, CieLuv right)
{
return !left.Equals(right);
}
/// <inheritdoc/>
public override int GetHashCode()
{
unchecked
{
int hashCode = this.WhitePoint.GetHashCode();
hashCode = (hashCode * 397) ^ this.backingVector.GetHashCode();
return hashCode;
}
}
/// <inheritdoc/>
public override string ToString()
{
if (this.IsEmpty)
{
return "CieLuv [ Empty ]";
}
return $"CieLuv [ L={this.L:#0.##}, U={this.U:#0.##}, V={this.V:#0.##} ]";
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override bool Equals(object obj)
{
if (obj is CieLuv)
{
return this.Equals((CieLuv)obj);
}
return false;
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Equals(CieLuv other)
{
return this.backingVector.Equals(other.backingVector)
&& this.WhitePoint.Equals(other.WhitePoint);
}
/// <inheritdoc/>
[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;
}
}
}

77
src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Adapt.cs

@ -36,11 +36,11 @@ namespace ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Adapts a <see cref="LinearRgb"/> color from the source working space to working space set in <see cref="TargetRgbWorkingSpace"/>.
/// Adapts <see cref="CieLab"/> color from the source white point to white point set in <see cref="TargetLabWhitePoint"/>.
/// </summary>
/// <param name="color">The color to adapt</param>
/// <returns>The adapted color</returns>
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);
}
/// <summary>
/// Adapts an <see cref="Rgb"/> color from the source working space to working space set in <see cref="TargetRgbWorkingSpace"/>.
/// Adapts <see cref="CieLch"/> color from the source white point to white point set in <see cref="TargetLabWhitePoint"/>.
/// </summary>
/// <param name="color">The color to adapt</param>
/// <returns>The adapted color</returns>
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);
}
/// <summary>
/// Adapts <see cref="CieLab"/> color from the source white point to white point set in <see cref="TargetLabWhitePoint"/>.
/// Adapts <see cref="CieLuv"/> color from the source white point to white point set in <see cref="TargetLuvWhitePoint"/>.
/// </summary>
/// <param name="color">The color to adapt</param>
/// <returns>The adapted color</returns>
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);
}
/// <summary>
@ -127,11 +128,11 @@ namespace ImageSharp.ColorSpaces.Conversion
}
/// <summary>
/// Adapts <see cref="CieLch"/> color from the source white point to white point set in <see cref="TargetLabWhitePoint"/>.
/// Adapts a <see cref="LinearRgb"/> color from the source working space to working space set in <see cref="TargetRgbWorkingSpace"/>.
/// </summary>
/// <param name="color">The color to adapt</param>
/// <returns>The adapted color</returns>
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);
}
/// <summary>
/// Adapts an <see cref="Rgb"/> color from the source working space to working space set in <see cref="TargetRgbWorkingSpace"/>.
/// </summary>
/// <param name="color">The color to adapt</param>
/// <returns>The adapted color</returns>
public Rgb Adapt(Rgb color)
{
Guard.NotNull(color, nameof(color));
LinearRgb linearInput = this.ToLinearRgb(color);
LinearRgb linearOutput = this.Adapt(linearInput);
return this.ToRgb(linearOutput);
}
}
}

13
src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLab.cs

@ -40,6 +40,19 @@ namespace ImageSharp.ColorSpaces.Conversion
return this.Adapt(unadapted);
}
/// <summary>
/// Converts a <see cref="CieLuv"/> into a <see cref="CieLab"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLab"/></returns>
public CieLab ToCieLab(CieLuv color)
{
Guard.NotNull(color, nameof(color));
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCieLab(xyzColor);
}
/// <summary>
/// Converts a <see cref="CieXyy"/> into a <see cref="CieLab"/>
/// </summary>

13
src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLch.cs

@ -33,6 +33,19 @@ namespace ImageSharp.ColorSpaces.Conversion
return CieLabToCieLchConverter.Convert(adapted);
}
/// <summary>
/// Converts a <see cref="CieLuv"/> into a <see cref="CieLch"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLch"/></returns>
public CieLch ToCieLch(CieLuv color)
{
Guard.NotNull(color, nameof(color));
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCieLch(xyzColor);
}
/// <summary>
/// Converts a <see cref="CieXyy"/> into a <see cref="CieLch"/>
/// </summary>

178
src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLuv.cs

@ -0,0 +1,178 @@
// <copyright file="ColorSpaceConverter.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp.ColorSpaces.Conversion
{
using ImageSharp.ColorSpaces;
using ImageSharp.ColorSpaces.Conversion.Implementation.CieLuv;
/// <summary>
/// Converts between color spaces ensuring that the color is adapted using chromatic adaptation.
/// </summary>
public partial class ColorSpaceConverter
{
/// <summary>
/// Converts a <see cref="CieLab"/> into a <see cref="CieLuv"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLuv"/></returns>
public CieLuv ToCieLuv(CieLab color)
{
Guard.NotNull(color, nameof(color));
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCieLuv(xyzColor);
}
/// <summary>
/// Converts a <see cref="CieLch"/> into a <see cref="CieLuv"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLuv"/></returns>
public CieLuv ToCieLuv(CieLch color)
{
Guard.NotNull(color, nameof(color));
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCieLuv(xyzColor);
}
/// <summary>
/// Converts a <see cref="CieXyy"/> into a <see cref="CieLuv"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLuv"/></returns>
public CieLuv ToCieLuv(CieXyy color)
{
Guard.NotNull(color, nameof(color));
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCieLuv(xyzColor);
}
/// <summary>
/// Converts a <see cref="CieXyz"/> into a <see cref="CieLuv"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLuv"/></returns>
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);
}
/// <summary>
/// Converts a <see cref="Cmyk"/> into a <see cref="CieLuv"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLuv"/></returns>
public CieLuv ToCieLuv(Cmyk color)
{
Guard.NotNull(color, nameof(color));
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCieLuv(xyzColor);
}
/// <summary>
/// Converts a <see cref="Hsl"/> into a <see cref="CieLuv"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLuv"/></returns>
public CieLuv ToCieLuv(Hsl color)
{
Guard.NotNull(color, nameof(color));
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCieLuv(xyzColor);
}
/// <summary>
/// Converts a <see cref="Hsv"/> into a <see cref="CieLuv"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLuv"/></returns>
public CieLuv ToCieLuv(Hsv color)
{
Guard.NotNull(color, nameof(color));
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCieLuv(xyzColor);
}
/// <summary>
/// Converts a <see cref="HunterLab"/> into a <see cref="CieLuv"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLuv"/></returns>
public CieLuv ToCieLuv(HunterLab color)
{
Guard.NotNull(color, nameof(color));
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCieLuv(xyzColor);
}
/// <summary>
/// Converts a <see cref="Lms"/> into a <see cref="CieLuv"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLuv"/></returns>
public CieLuv ToCieLuv(Lms color)
{
Guard.NotNull(color, nameof(color));
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCieLuv(xyzColor);
}
/// <summary>
/// Converts a <see cref="LinearRgb"/> into a <see cref="CieLuv"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLuv"/></returns>
public CieLuv ToCieLuv(LinearRgb color)
{
Guard.NotNull(color, nameof(color));
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCieLuv(xyzColor);
}
/// <summary>
/// Converts a <see cref="Rgb"/> into a <see cref="CieLuv"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLuv"/></returns>
public CieLuv ToCieLuv(Rgb color)
{
Guard.NotNull(color, nameof(color));
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCieLuv(xyzColor);
}
/// <summary>
/// Converts a <see cref="YCbCr"/> into a <see cref="CieLuv"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLuv"/></returns>
public CieLuv ToCieLuv(YCbCr color)
{
Guard.NotNull(color, nameof(color));
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCieLuv(xyzColor);
}
}
}

14
src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieXyy.cs

@ -42,6 +42,20 @@ namespace ImageSharp.ColorSpaces.Conversion
return this.ToCieXyy(xyzColor);
}
/// <summary>
/// Converts a <see cref="CieLuv"/> into a <see cref="CieXyy"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieXyy"/></returns>
public CieXyy ToCieXyy(CieLuv color)
{
Guard.NotNull(color, nameof(color));
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCieXyy(xyzColor);
}
/// <summary>
/// Converts a <see cref="CieXyz"/> into a <see cref="CieXyy"/>
/// </summary>

23
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);
}
/// <summary>
/// Converts a <see cref="CieLuv"/> into a <see cref="CieXyz"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieXyz"/></returns>
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;
}
/// <summary>
/// Converts a <see cref="CieXyy"/> into a <see cref="CieXyz"/>
/// </summary>

14
src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Cmyk.cs

@ -43,6 +43,20 @@ namespace ImageSharp.ColorSpaces.Conversion
return this.ToCmyk(xyzColor);
}
/// <summary>
/// Converts a <see cref="CieLuv"/> into a <see cref="Cmyk"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Cmyk"/></returns>
public Cmyk ToCmyk(CieLuv color)
{
Guard.NotNull(color, nameof(color));
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCmyk(xyzColor);
}
/// <summary>
/// Converts a <see cref="CieXyy"/> into a <see cref="Cmyk"/>
/// </summary>

14
src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Hsl.cs

@ -43,6 +43,20 @@ namespace ImageSharp.ColorSpaces.Conversion
return this.ToHsl(xyzColor);
}
/// <summary>
/// Converts a <see cref="CieLuv"/> into a <see cref="Hsl"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Hsl"/></returns>
public Hsl ToHsl(CieLuv color)
{
Guard.NotNull(color, nameof(color));
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToHsl(xyzColor);
}
/// <summary>
/// Converts a <see cref="CieXyy"/> into a <see cref="Hsl"/>
/// </summary>

14
src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Hsv.cs

@ -43,6 +43,20 @@ namespace ImageSharp.ColorSpaces.Conversion
return this.ToHsv(xyzColor);
}
/// <summary>
/// Converts a <see cref="CieLuv"/> into a <see cref="Hsv"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Hsv"/></returns>
public Hsv ToHsv(CieLuv color)
{
Guard.NotNull(color, nameof(color));
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToHsv(xyzColor);
}
/// <summary>
/// Converts a <see cref="CieXyy"/> into a <see cref="Hsv"/>
/// </summary>

13
src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.HunterLab.cs

@ -38,6 +38,19 @@ namespace ImageSharp.ColorSpaces.Conversion
return this.ToHunterLab(xyzColor);
}
/// <summary>
/// Converts a <see cref="CieLuv"/> into a <see cref="HunterLab"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="HunterLab"/></returns>
public HunterLab ToHunterLab(CieLuv color)
{
Guard.NotNull(color, nameof(color));
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToHunterLab(xyzColor);
}
/// <summary>
/// Converts a <see cref="CieXyy"/> into a <see cref="HunterLab"/>
/// </summary>

13
src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.LinearRgb.cs

@ -42,6 +42,19 @@ namespace ImageSharp.ColorSpaces.Conversion
return this.ToLinearRgb(xyzColor);
}
/// <summary>
/// Converts a <see cref="CieLuv"/> into a <see cref="LinearRgb"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="LinearRgb"/></returns>
public LinearRgb ToLinearRgb(CieLuv color)
{
Guard.NotNull(color, nameof(color));
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToLinearRgb(xyzColor);
}
/// <summary>
/// Converts a <see cref="CieXyy"/> into a <see cref="LinearRgb"/>
/// </summary>

13
src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Lms.cs

@ -38,6 +38,19 @@ namespace ImageSharp.ColorSpaces.Conversion
return this.ToLms(xyzColor);
}
/// <summary>
/// Converts a <see cref="CieLuv"/> into a <see cref="Lms"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Lms"/></returns>
public Lms ToLms(CieLuv color)
{
Guard.NotNull(color, nameof(color));
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToLms(xyzColor);
}
/// <summary>
/// Converts a <see cref="CieXyy"/> into a <see cref="Lms"/>
/// </summary>

13
src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Rgb.cs

@ -40,6 +40,19 @@ namespace ImageSharp.ColorSpaces.Conversion
return this.ToRgb(xyzColor);
}
/// <summary>
/// Converts a <see cref="CieLuv"/> into a <see cref="Rgb"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Rgb"/></returns>
public Rgb ToRgb(CieLuv color)
{
Guard.NotNull(color, nameof(color));
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToRgb(xyzColor);
}
/// <summary>
/// Converts a <see cref="CieXyy"/> into a <see cref="Rgb"/>
/// </summary>

14
src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.YCbCr.cs

@ -43,6 +43,20 @@ namespace ImageSharp.ColorSpaces.Conversion
return this.ToYCbCr(xyzColor);
}
/// <summary>
/// Converts a <see cref="CieLuv"/> into a <see cref="YCbCr"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="YCbCr"/></returns>
public YCbCr ToYCbCr(CieLuv color)
{
Guard.NotNull(color, nameof(color));
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToYCbCr(xyzColor);
}
/// <summary>
/// Converts a <see cref="CieXyy"/> into a <see cref="YCbCr"/>
/// </summary>

7
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
/// </summary>
public CieXyz WhitePoint { get; set; }
/// <summary>
/// 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: <see cref="CieLuv.DefaultWhitePoint"/>.
/// </summary>
public CieXyz TargetLuvWhitePoint { get; set; }
/// <summary>
/// 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: <see cref="CieLab.DefaultWhitePoint"/>.

80
src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLuv/CieLuvToCieXyzConverter.cs

@ -0,0 +1,80 @@
// <copyright file="CieLuvToCieXyzConverter.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp.ColorSpaces.Conversion.Implementation.CieLuv
{
using System.Runtime.CompilerServices;
using ImageSharp.ColorSpaces;
/// <summary>
/// Converts from <see cref="CieLuv"/> to <see cref="CieXyz"/>.
/// </summary>
internal class CieLuvToCieXyzConverter : IColorConversion<CieLuv, CieXyz>
{
/// <inheritdoc/>
[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);
}
/// <summary>
/// Calculates the blue-yellow chromacity based on the given whitepoint.
/// </summary>
/// <param name="input">The whitepoint</param>
/// <returns>The <see cref="float"/></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static float ComputeU0(CieXyz input)
{
return (4 * input.X) / (input.X + (15 * input.Y) + (3 * input.Z));
}
/// <summary>
/// Calculates the red-green chromacity based on the given whitepoint.
/// </summary>
/// <param name="input">The whitepoint</param>
/// <returns>The <see cref="float"/></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static float ComputeV0(CieXyz input)
{
return (9 * input.Y) / (input.X + (15 * input.Y) + (3 * input.Z));
}
}
}

102
src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLuv/CieXyzToCieLuvConverter.cs

@ -0,0 +1,102 @@
// <copyright file="CieXyzToCieLuvConverter.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp.ColorSpaces.Conversion.Implementation.CieLuv
{
using System.Runtime.CompilerServices;
using ImageSharp.ColorSpaces;
/// <summary>
/// Converts from <see cref="CieXyz"/> to <see cref="CieLuv"/>.
/// </summary>
internal class CieXyzToCieLuvConverter : IColorConversion<CieXyz, CieLuv>
{
/// <summary>
/// Initializes a new instance of the <see cref="CieXyzToCieLuvConverter"/> class.
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public CieXyzToCieLuvConverter()
: this(CieLuv.DefaultWhitePoint)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="CieXyzToCieLuvConverter"/> class.
/// </summary>
/// <param name="luvWhitePoint">The target reference luv white point</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public CieXyzToCieLuvConverter(CieXyz luvWhitePoint)
{
this.LuvWhitePoint = luvWhitePoint;
}
/// <summary>
/// Gets the target reference whitepoint. When not set, <see cref="CieLuv.DefaultWhitePoint"/> is used.
/// </summary>
public CieXyz LuvWhitePoint
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get;
}
/// <inheritdoc />
[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);
}
/// <summary>
/// Calculates the blue-yellow chromacity based on the given whitepoint.
/// </summary>
/// <param name="input">The whitepoint</param>
/// <returns>The <see cref="float"/></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static float ComputeUp(CieXyz input)
{
return (4 * input.X) / (input.X + (15 * input.Y) + (3 * input.Z));
}
/// <summary>
/// Calculates the red-green chromacity based on the given whitepoint.
/// </summary>
/// <param name="input">The whitepoint</param>
/// <returns>The <see cref="float"/></returns>
private static float ComputeVp(CieXyz input)
{
return (9 * input.Y) / (input.X + (15 * input.Y) + (3 * input.Z));
}
}
}

17
src/ImageSharp/ColorSpaces/HunterLab.cs

@ -169,7 +169,12 @@ namespace ImageSharp.ColorSpaces
/// <inheritdoc/>
public override int GetHashCode()
{
return this.backingVector.GetHashCode();
unchecked
{
int hashCode = this.WhitePoint.GetHashCode();
hashCode = (hashCode * 397) ^ this.backingVector.GetHashCode();
return hashCode;
}
}
/// <inheritdoc/>
@ -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);
}
/// <inheritdoc/>
@ -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;
}
}
}

4
src/ImageSharp/ColorSpaces/Lms.cs

@ -18,7 +18,7 @@ namespace ImageSharp.ColorSpaces
public struct Lms : IColorVector, IEquatable<Lms>, IAlmostEquatable<Lms, float>
{
/// <summary>
/// Represents a <see cref="Lms"/> that has Y, Cb, and Cr values set to zero.
/// Represents a <see cref="Lms"/> that has L, M, and S values set to zero.
/// </summary>
public static readonly Lms Empty = default(Lms);
@ -42,7 +42,7 @@ namespace ImageSharp.ColorSpaces
/// <summary>
/// Initializes a new instance of the <see cref="Lms"/> struct.
/// </summary>
/// <param name="vector">The vector representing the x, y, z components.</param>
/// <param name="vector">The vector representing the l, m, s components.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Lms(Vector3 vector)
: this()

2
tests/ImageSharp.Tests/Colors/Colorspaces/CieLabAndCieLchConversionTests.cs → 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;

0
tests/ImageSharp.Tests/Colors/Colorspaces/CieXyzAndCieLabConversionTest.cs → tests/ImageSharp.Tests/Colorspaces/CieXyzAndCieLabConversionTest.cs

71
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;
/// <summary>
/// Tests <see cref="CieXyz"/>-<see cref="CieLuv"/> conversions.
/// </summary>
/// <remarks>
/// Test data generated using:
/// <see href="http://www.brucelindbloom.com/index.html?ColorCalculator.html"/>
/// </remarks>
public class CieXyzAndCieLuvConversionTest
{
private static readonly IEqualityComparer<float> FloatRoundingComparer = new FloatRoundingComparer(4);
/// <summary>
/// Tests conversion from <see cref="CieLuv"/> to <see cref="CieXyz"/> (<see cref="Illuminants.D65"/>).
/// </summary>
[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);
}
/// <summary>
/// Tests conversion from <see cref="CieXyz"/> (<see cref="Illuminants.D65"/>) to <see cref="CieLuv"/>.
/// </summary>
[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);
}
}
}

2
tests/ImageSharp.Tests/Colors/Colorspaces/CieXyzAndCieXyyConversionTest.cs → tests/ImageSharp.Tests/Colorspaces/CieXyzAndCieXyyConversionTest.cs

@ -1,4 +1,4 @@
namespace ImageSharp.Tests.Colors.Colorspaces
namespace ImageSharp.Tests.Colorspaces
{
using System.Collections.Generic;

0
tests/ImageSharp.Tests/Colors/Colorspaces/CieXyzAndHunterLabConversionTest.cs → tests/ImageSharp.Tests/Colorspaces/CieXyzAndHunterLabConversionTest.cs

0
tests/ImageSharp.Tests/Colors/Colorspaces/CieXyzAndLmsConversionTest.cs → tests/ImageSharp.Tests/Colorspaces/CieXyzAndLmsConversionTest.cs

4
tests/ImageSharp.Tests/Colors/Colorspaces/ColorConverterAdaptTest.cs → tests/ImageSharp.Tests/Colorspaces/ColorConverterAdaptTest.cs

@ -9,7 +9,7 @@ namespace ImageSharp.Tests
using Xunit;
/// <summary>
/// Tests <see cref="ColorSpaceConverter.Adapt" /> methods.
/// Tests <see cref="M:ColorSpaceConverter.Adapt" /> methods.
/// Test data generated using:
/// <see cref="http://www.brucelindbloom.com/index.html?ChromAdaptCalc.html"/>
/// <see cref="http://www.brucelindbloom.com/index.html?ColorCalculator.html"/>
@ -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);

7
tests/ImageSharp.Tests/Colors/Colorspaces/ColorSpaceEqualityTests.cs → 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 },

0
tests/ImageSharp.Tests/Colors/Colorspaces/RgbAndCieXyzConversionTest.cs → tests/ImageSharp.Tests/Colorspaces/RgbAndCieXyzConversionTest.cs

2
tests/ImageSharp.Tests/Colors/Colorspaces/RgbAndCmykConversionTest.cs → tests/ImageSharp.Tests/Colorspaces/RgbAndCmykConversionTest.cs

@ -1,4 +1,4 @@
namespace ImageSharp.Tests.Colors.Colorspaces
namespace ImageSharp.Tests.Colorspaces
{
using System.Collections.Generic;

2
tests/ImageSharp.Tests/Colors/Colorspaces/RgbAndHslConversionTest.cs → tests/ImageSharp.Tests/Colorspaces/RgbAndHslConversionTest.cs

@ -1,4 +1,4 @@
namespace ImageSharp.Tests.Colors.Colorspaces
namespace ImageSharp.Tests.Colorspaces
{
using System.Collections.Generic;

2
tests/ImageSharp.Tests/Colors/Colorspaces/RgbAndHsvConversionTest.cs → tests/ImageSharp.Tests/Colorspaces/RgbAndHsvConversionTest.cs

@ -1,4 +1,4 @@
namespace ImageSharp.Tests.Colors.Colorspaces
namespace ImageSharp.Tests.Colorspaces
{
using System.Collections.Generic;

2
tests/ImageSharp.Tests/Colors/Colorspaces/RgbAndYCbCrConversionTest.cs → tests/ImageSharp.Tests/Colorspaces/RgbAndYCbCrConversionTest.cs

@ -1,4 +1,4 @@
namespace ImageSharp.Tests.Colors.Colorspaces
namespace ImageSharp.Tests.Colorspaces
{
using System.Collections.Generic;

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

Loading…
Cancel
Save