mirror of https://github.com/SixLabors/ImageSharp
30 changed files with 866 additions and 58 deletions
@ -0,0 +1,247 @@ |
|||
// <copyright file="CieLchuv.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>
|
|||
/// Represents the CIE L*C*h°, cylindrical form of the CIE L*u*v* 1976 color.
|
|||
/// <see href="https://en.wikipedia.org/wiki/Lab_color_space#Cylindrical_representation:_CieLchuv_or_CIEHLC"/>
|
|||
/// </summary>
|
|||
public struct CieLchuv : IColorVector, IEquatable<CieLchuv>, IAlmostEquatable<CieLchuv, float> |
|||
{ |
|||
/// <summary>
|
|||
/// D50 standard illuminant.
|
|||
/// Used when reference white is not specified explicitly.
|
|||
/// </summary>
|
|||
public static readonly CieXyz DefaultWhitePoint = Illuminants.D65; |
|||
|
|||
/// <summary>
|
|||
/// Represents a <see cref="CieLchuv"/> that has L, C, H values set to zero.
|
|||
/// </summary>
|
|||
public static readonly CieLchuv Empty = default(CieLchuv); |
|||
|
|||
/// <summary>
|
|||
/// The backing vector for SIMD support.
|
|||
/// </summary>
|
|||
private readonly Vector3 backingVector; |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="CieLchuv"/> struct.
|
|||
/// </summary>
|
|||
/// <param name="l">The lightness dimension.</param>
|
|||
/// <param name="c">The chroma, relative saturation.</param>
|
|||
/// <param name="h">The hue in degrees.</param>
|
|||
/// <remarks>Uses <see cref="DefaultWhitePoint"/> as white point.</remarks>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public CieLchuv(float l, float c, float h) |
|||
: this(new Vector3(l, c, h), DefaultWhitePoint) |
|||
{ |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="CieLchuv"/> struct.
|
|||
/// </summary>
|
|||
/// <param name="l">The lightness dimension.</param>
|
|||
/// <param name="c">The chroma, relative saturation.</param>
|
|||
/// <param name="h">The hue in degrees.</param>
|
|||
/// <param name="whitePoint">The reference white point. <see cref="Illuminants"/></param>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public CieLchuv(float l, float c, float h, CieXyz whitePoint) |
|||
: this(new Vector3(l, c, h), whitePoint) |
|||
{ |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="CieLchuv"/> struct.
|
|||
/// </summary>
|
|||
/// <param name="vector">The vector representing the l, c, h components.</param>
|
|||
/// <remarks>Uses <see cref="DefaultWhitePoint"/> as white point.</remarks>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public CieLchuv(Vector3 vector) |
|||
: this(vector, DefaultWhitePoint) |
|||
{ |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="CieLchuv"/> struct.
|
|||
/// </summary>
|
|||
/// <param name="vector">The vector representing the l, c, h components.</param>
|
|||
/// <param name="whitePoint">The reference white point. <see cref="Illuminants"/></param>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public CieLchuv(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 ranging between 0 (black), 100 (diffuse white) or higher (specular white).</remarks>
|
|||
/// </summary>
|
|||
public float L |
|||
{ |
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
get => this.backingVector.X; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets the a chroma component.
|
|||
/// <remarks>A value ranging from 0 to 100.</remarks>
|
|||
/// </summary>
|
|||
public float C |
|||
{ |
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
get => this.backingVector.Y; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets the h° hue component in degrees.
|
|||
/// <remarks>A value ranging from 0 to 360.</remarks>
|
|||
/// </summary>
|
|||
public float H |
|||
{ |
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
get => this.backingVector.Z; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets a value indicating whether this <see cref="CieLchuv"/> 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="CieLchuv"/> objects for equality.
|
|||
/// </summary>
|
|||
/// <param name="left">
|
|||
/// The <see cref="CieLchuv"/> on the left side of the operand.
|
|||
/// </param>
|
|||
/// <param name="right">
|
|||
/// The <see cref="CieLchuv"/> 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 ==(CieLchuv left, CieLchuv right) |
|||
{ |
|||
return left.Equals(right); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Compares two <see cref="CieLchuv"/> objects for inequality
|
|||
/// </summary>
|
|||
/// <param name="left">
|
|||
/// The <see cref="CieLchuv"/> on the left side of the operand.
|
|||
/// </param>
|
|||
/// <param name="right">
|
|||
/// The <see cref="CieLchuv"/> 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 !=(CieLchuv left, CieLchuv 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 "CieLchuv [Empty]"; |
|||
} |
|||
|
|||
return $"CieLchuv [ L={this.L:#0.##}, C={this.C:#0.##}, H={this.H:#0.##}]"; |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public override bool Equals(object obj) |
|||
{ |
|||
if (obj is CieLchuv) |
|||
{ |
|||
return this.Equals((CieLchuv)obj); |
|||
} |
|||
|
|||
return false; |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public bool Equals(CieLchuv other) |
|||
{ |
|||
return this.backingVector.Equals(other.backingVector) |
|||
&& this.WhitePoint.Equals(other.WhitePoint); |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public bool AlmostEquals(CieLchuv 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; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Computes the saturation of the color (chroma normalized by lightness)
|
|||
/// </summary>
|
|||
/// <remarks>
|
|||
/// A value ranging from 0 to 100.
|
|||
/// </remarks>
|
|||
/// <returns>The <see cref="float"/></returns>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public float Saturation() |
|||
{ |
|||
float result = 100 * (this.C / this.L); |
|||
|
|||
if (float.IsNaN(result)) |
|||
{ |
|||
return 0; |
|||
} |
|||
|
|||
return result; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,192 @@ |
|||
// <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.Conversion.Implementation.CieLchuv; |
|||
|
|||
/// <content>
|
|||
/// Allows conversion to <see cref="CieLchuv"/>.
|
|||
/// </content>
|
|||
public partial class ColorSpaceConverter |
|||
{ |
|||
/// <summary>
|
|||
/// The converter for converting between CieLab to CieLchuv.
|
|||
/// </summary>
|
|||
private static readonly CieLuvToCieLchuvConverter CieLuvToCieLchuvConverter = new CieLuvToCieLchuvConverter(); |
|||
|
|||
/// <summary>
|
|||
/// Converts a <see cref="CieLab"/> into a <see cref="CieLchuv"/>
|
|||
/// </summary>
|
|||
/// <param name="color">The color to convert.</param>
|
|||
/// <returns>The <see cref="CieLchuv"/></returns>
|
|||
public CieLchuv ToCieLchuv(CieLab color) |
|||
{ |
|||
Guard.NotNull(color, nameof(color)); |
|||
|
|||
CieXyz xyzColor = this.ToCieXyz(color); |
|||
return this.ToCieLchuv(xyzColor); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Converts a <see cref="CieLch"/> into a <see cref="CieLchuv"/>
|
|||
/// </summary>
|
|||
/// <param name="color">The color to convert.</param>
|
|||
/// <returns>The <see cref="CieLchuv"/></returns>
|
|||
public CieLchuv ToCieLchuv(CieLch color) |
|||
{ |
|||
Guard.NotNull(color, nameof(color)); |
|||
|
|||
CieXyz xyzColor = this.ToCieXyz(color); |
|||
return this.ToCieLchuv(xyzColor); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Converts a <see cref="CieLuv"/> into a <see cref="CieLchuv"/>
|
|||
/// </summary>
|
|||
/// <param name="color">The color to convert.</param>
|
|||
/// <returns>The <see cref="CieLchuv"/></returns>
|
|||
public CieLchuv ToCieLchuv(CieLuv color) |
|||
{ |
|||
Guard.NotNull(color, nameof(color)); |
|||
|
|||
// Adaptation
|
|||
CieLuv adapted = this.IsChromaticAdaptationPerformed ? this.Adapt(color) : color; |
|||
|
|||
// Conversion
|
|||
return CieLuvToCieLchuvConverter.Convert(adapted); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Converts a <see cref="CieXyy"/> into a <see cref="CieLchuv"/>
|
|||
/// </summary>
|
|||
/// <param name="color">The color to convert.</param>
|
|||
/// <returns>The <see cref="CieLchuv"/></returns>
|
|||
public CieLchuv ToCieLchuv(CieXyy color) |
|||
{ |
|||
Guard.NotNull(color, nameof(color)); |
|||
|
|||
CieXyz xyzColor = this.ToCieXyz(color); |
|||
return this.ToCieLchuv(xyzColor); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Converts a <see cref="CieXyz"/> into a <see cref="CieLchuv"/>
|
|||
/// </summary>
|
|||
/// <param name="color">The color to convert.</param>
|
|||
/// <returns>The <see cref="CieLchuv"/></returns>
|
|||
public CieLchuv ToCieLchuv(CieXyz color) |
|||
{ |
|||
Guard.NotNull(color, nameof(color)); |
|||
|
|||
CieLab labColor = this.ToCieLab(color); |
|||
return this.ToCieLchuv(labColor); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Converts a <see cref="Cmyk"/> into a <see cref="CieLchuv"/>
|
|||
/// </summary>
|
|||
/// <param name="color">The color to convert.</param>
|
|||
/// <returns>The <see cref="CieLchuv"/></returns>
|
|||
public CieLchuv ToCieLchuv(Cmyk color) |
|||
{ |
|||
Guard.NotNull(color, nameof(color)); |
|||
|
|||
CieXyz xyzColor = this.ToCieXyz(color); |
|||
return this.ToCieLchuv(xyzColor); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Converts a <see cref="Hsl"/> into a <see cref="CieLchuv"/>
|
|||
/// </summary>
|
|||
/// <param name="color">The color to convert.</param>
|
|||
/// <returns>The <see cref="CieLchuv"/></returns>
|
|||
public CieLchuv ToCieLchuv(Hsl color) |
|||
{ |
|||
Guard.NotNull(color, nameof(color)); |
|||
|
|||
CieXyz xyzColor = this.ToCieXyz(color); |
|||
return this.ToCieLchuv(xyzColor); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Converts a <see cref="Hsv"/> into a <see cref="CieLchuv"/>
|
|||
/// </summary>
|
|||
/// <param name="color">The color to convert.</param>
|
|||
/// <returns>The <see cref="CieLchuv"/></returns>
|
|||
public CieLchuv ToCieLchuv(Hsv color) |
|||
{ |
|||
Guard.NotNull(color, nameof(color)); |
|||
|
|||
CieXyz xyzColor = this.ToCieXyz(color); |
|||
return this.ToCieLchuv(xyzColor); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Converts a <see cref="HunterLab"/> into a <see cref="CieLchuv"/>
|
|||
/// </summary>
|
|||
/// <param name="color">The color to convert.</param>
|
|||
/// <returns>The <see cref="CieLchuv"/></returns>
|
|||
public CieLchuv ToCieLchuv(HunterLab color) |
|||
{ |
|||
Guard.NotNull(color, nameof(color)); |
|||
|
|||
CieXyz xyzColor = this.ToCieXyz(color); |
|||
return this.ToCieLchuv(xyzColor); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Converts a <see cref="LinearRgb"/> into a <see cref="CieLchuv"/>
|
|||
/// </summary>
|
|||
/// <param name="color">The color to convert.</param>
|
|||
/// <returns>The <see cref="CieLchuv"/></returns>
|
|||
public CieLchuv ToCieLchuv(LinearRgb color) |
|||
{ |
|||
Guard.NotNull(color, nameof(color)); |
|||
|
|||
CieXyz xyzColor = this.ToCieXyz(color); |
|||
return this.ToCieLchuv(xyzColor); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Converts a <see cref="Lms"/> into a <see cref="CieLchuv"/>
|
|||
/// </summary>
|
|||
/// <param name="color">The color to convert.</param>
|
|||
/// <returns>The <see cref="CieLchuv"/></returns>
|
|||
public CieLchuv ToCieLchuv(Lms color) |
|||
{ |
|||
Guard.NotNull(color, nameof(color)); |
|||
|
|||
CieXyz xyzColor = this.ToCieXyz(color); |
|||
return this.ToCieLchuv(xyzColor); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Converts a <see cref="Rgb"/> into a <see cref="CieLchuv"/>
|
|||
/// </summary>
|
|||
/// <param name="color">The color to convert.</param>
|
|||
/// <returns>The <see cref="CieLchuv"/></returns>
|
|||
public CieLchuv ToCieLchuv(Rgb color) |
|||
{ |
|||
Guard.NotNull(color, nameof(color)); |
|||
|
|||
CieXyz xyzColor = this.ToCieXyz(color); |
|||
return this.ToCieLchuv(xyzColor); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Converts a <see cref="YCbCr"/> into a <see cref="CieLchuv"/>
|
|||
/// </summary>
|
|||
/// <param name="color">The color to convert.</param>
|
|||
/// <returns>The <see cref="CieLchuv"/></returns>
|
|||
public CieLchuv ToCieLchuv(YCbCr color) |
|||
{ |
|||
Guard.NotNull(color, nameof(color)); |
|||
|
|||
CieXyz xyzColor = this.ToCieXyz(color); |
|||
return this.ToCieLchuv(xyzColor); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,34 @@ |
|||
// <copyright file="CieLchuvToCieLuvConverter.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.CieLchuv |
|||
{ |
|||
using System.Runtime.CompilerServices; |
|||
|
|||
using ImageSharp.ColorSpaces; |
|||
|
|||
/// <summary>
|
|||
/// Converts from <see cref="CieLch"/> to <see cref="CieLab"/>.
|
|||
/// </summary>
|
|||
internal class CieLchuvToCieLuvConverter : IColorConversion<CieLchuv, CieLuv> |
|||
{ |
|||
/// <inheritdoc/>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public CieLuv Convert(CieLchuv input) |
|||
{ |
|||
DebugGuard.NotNull(input, nameof(input)); |
|||
|
|||
// Conversion algorithm described here:
|
|||
// https://en.wikipedia.org/wiki/CIELUV#Cylindrical_representation_.28CIELCH.29
|
|||
float l = input.L, c = input.C, hDegrees = input.H; |
|||
float hRadians = MathF.DegreeToRadian(hDegrees); |
|||
|
|||
float u = c * MathF.Cos(hRadians); |
|||
float v = c * MathF.Sin(hRadians); |
|||
|
|||
return new CieLuv(l, u, v, input.WhitePoint); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,42 @@ |
|||
// <copyright file="CieLuvToCieLchuvConverter.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.CieLchuv |
|||
{ |
|||
using System.Runtime.CompilerServices; |
|||
|
|||
using ImageSharp.ColorSpaces; |
|||
|
|||
/// <summary>
|
|||
/// Converts from <see cref="CieLab"/> to <see cref="CieLch"/>.
|
|||
/// </summary>
|
|||
internal class CieLuvToCieLchuvConverter : IColorConversion<CieLuv, CieLchuv> |
|||
{ |
|||
/// <inheritdoc/>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public CieLchuv Convert(CieLuv input) |
|||
{ |
|||
DebugGuard.NotNull(input, nameof(input)); |
|||
|
|||
// Conversion algorithm described here:
|
|||
// https://en.wikipedia.org/wiki/CIELUV#Cylindrical_representation_.28CIELCH.29
|
|||
float l = input.L, a = input.U, b = input.V; |
|||
float c = MathF.Sqrt((a * a) + (b * b)); |
|||
float hRadians = MathF.Atan2(b, a); |
|||
float hDegrees = MathF.RadianToDegree(hRadians); |
|||
|
|||
// Wrap the angle round at 360.
|
|||
hDegrees = hDegrees % 360; |
|||
|
|||
// Make sure it's not negative.
|
|||
while (hDegrees < 0) |
|||
{ |
|||
hDegrees += 360; |
|||
} |
|||
|
|||
return new CieLchuv(l, c, hDegrees, input.WhitePoint); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,77 @@ |
|||
namespace ImageSharp.Tests.Colorspaces |
|||
{ |
|||
using System.Collections.Generic; |
|||
using ImageSharp.ColorSpaces; |
|||
using ImageSharp.ColorSpaces.Conversion; |
|||
|
|||
using Xunit; |
|||
|
|||
/// <summary>
|
|||
/// Tests <see cref="CieLuv"/>-<see cref="CieLchuv"/> conversions.
|
|||
/// </summary>
|
|||
/// <remarks>
|
|||
/// Test data generated using:
|
|||
/// <see href="http://www.brucelindbloom.com/index.html?ColorCalculator.html"/>
|
|||
/// </remarks>
|
|||
public class CieLuvAndCieLchuvuvConversionTests |
|||
{ |
|||
private static readonly IEqualityComparer<float> FloatRoundingComparer = new FloatRoundingComparer(4); |
|||
|
|||
private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); |
|||
|
|||
/// <summary>
|
|||
/// Tests conversion from <see cref="CieLchuv"/> to <see cref="CieLuv"/>.
|
|||
/// </summary>
|
|||
[Theory] |
|||
[InlineData(0, 0, 0, 0, 0, 0)] |
|||
[InlineData(54.2917, 106.8391, 40.8526, 54.2917, 80.8125, 69.8851)] |
|||
[InlineData(100, 0, 0, 100, 0, 0)] |
|||
[InlineData(100, 50, 180, 100, -50, 0)] |
|||
[InlineData(10, 36.0555, 56.3099, 10, 20, 30)] |
|||
[InlineData(10, 36.0555, 56.3099, 10, 20, 30)] |
|||
[InlineData(10, 36.0555, 123.6901, 10, -20, 30)] |
|||
[InlineData(10, 36.0555, 303.6901, 10, 20, -30)] |
|||
[InlineData(10, 36.0555, 236.3099, 10, -20, -30)] |
|||
public void Convert_Lchuv_to_Luv(float l, float c, float h, float l2, float u, float v) |
|||
{ |
|||
// Arrange
|
|||
CieLchuv input = new CieLchuv(l, c, h); |
|||
|
|||
// Act
|
|||
CieLuv output = Converter.ToCieLuv(input); |
|||
|
|||
// Assert
|
|||
Assert.Equal(l2, output.L, FloatRoundingComparer); |
|||
Assert.Equal(u, output.U, FloatRoundingComparer); |
|||
Assert.Equal(v, output.V, FloatRoundingComparer); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Tests conversion from <see cref="CieLuv"/> to <see cref="CieLchuv"/>.
|
|||
/// </summary>
|
|||
[Theory] |
|||
[InlineData(0, 0, 0, 0, 0, 0)] |
|||
[InlineData(54.2917, 80.8125, 69.8851, 54.2917, 106.8391, 40.8526)] |
|||
[InlineData(100, 0, 0, 100, 0, 0)] |
|||
[InlineData(100, -50, 0, 100, 50, 180)] |
|||
[InlineData(10, 20, 30, 10, 36.0555, 56.3099)] |
|||
[InlineData(10, 20, 30, 10, 36.0555, 56.3099)] |
|||
[InlineData(10, -20, 30, 10, 36.0555, 123.6901)] |
|||
[InlineData(10, 20, -30, 10, 36.0555, 303.6901)] |
|||
[InlineData(10, -20, -30, 10, 36.0555, 236.3099)] |
|||
[InlineData(37.3511, 24.1720, 16.0684, 37.3511, 29.0255, 33.6141)] |
|||
public void Convert_Luv_to_LCHuv(float l, float u, float v, float l2, float c, float h) |
|||
{ |
|||
// Arrange
|
|||
CieLuv input = new CieLuv(l, u, v); |
|||
|
|||
// Act
|
|||
CieLchuv output = Converter.ToCieLchuv(input); |
|||
|
|||
// Assert
|
|||
Assert.Equal(l2, output.L, FloatRoundingComparer); |
|||
Assert.Equal(c, output.C, FloatRoundingComparer); |
|||
Assert.Equal(h, output.H, FloatRoundingComparer); |
|||
} |
|||
} |
|||
} |
|||
Loading…
Reference in new issue