Browse Source

Remove all current colorspaces

af/merge-core
James Jackson-South 9 years ago
parent
commit
0be847e373
  1. 288
      src/ImageSharp/Colors/ColorspaceTransforms.cs
  2. 166
      src/ImageSharp/Colors/Spaces/Bgra32.cs
  3. 187
      src/ImageSharp/Colors/Spaces/CieLab.cs
  4. 168
      src/ImageSharp/Colors/Spaces/CieXyz.cs
  5. 189
      src/ImageSharp/Colors/Spaces/Cmyk.cs
  6. 207
      src/ImageSharp/Colors/Spaces/Hsl.cs
  7. 200
      src/ImageSharp/Colors/Spaces/Hsv.cs
  8. 30
      src/ImageSharp/Colors/Spaces/IAlmostEquatable.cs
  9. 165
      src/ImageSharp/Colors/Spaces/YCbCr.cs
  10. 493
      tests/ImageSharp.Tests/Colors/ColorConversionTests.cs
  11. 3
      tests/ImageSharp.Tests/Colors/ColorDefinitionTests.cs
  12. 216
      tests/ImageSharp.Tests/Colors/ColorEqualityTests.cs

288
src/ImageSharp/Colors/ColorspaceTransforms.cs

@ -1,288 +0,0 @@
// <copyright file="ColorspaceTransforms.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp
{
using System;
using System.Numerics;
using Colors.Spaces;
/// <summary>
/// Packed vector type containing four 8-bit unsigned normalized values ranging from 0 to 255.
/// The color components are stored in red, green, blue, and alpha order.
/// </summary>
/// <remarks>
/// This struct is fully mutable. This is done (against the guidelines) for the sake of performance,
/// as it avoids the need to create new values for modification operations.
/// </remarks>
public partial struct Color
{
/// <summary>
/// Allows the implicit conversion of an instance of <see cref="Color"/> to a
/// <see cref="Bgra32"/>.
/// </summary>
/// <param name="color">The instance of <see cref="Color"/> to convert.</param>
/// <returns>
/// An instance of <see cref="Bgra32"/>.
/// </returns>
public static implicit operator Color(Bgra32 color)
{
return new Color(color.R, color.G, color.B, color.A);
}
/// <summary>
/// Allows the implicit conversion of an instance of <see cref="Cmyk"/> to a
/// <see cref="Color"/>.
/// </summary>
/// <param name="cmykColor">The instance of <see cref="Cmyk"/> to convert.</param>
/// <returns>
/// An instance of <see cref="Color"/>.
/// </returns>
public static implicit operator Color(Cmyk cmykColor)
{
float r = (1 - cmykColor.C) * (1 - cmykColor.K);
float g = (1 - cmykColor.M) * (1 - cmykColor.K);
float b = (1 - cmykColor.Y) * (1 - cmykColor.K);
return new Color(r, g, b, 1);
}
/// <summary>
/// Allows the implicit conversion of an instance of <see cref="YCbCr"/> to a
/// <see cref="Color"/>.
/// </summary>
/// <param name="color">The instance of <see cref="YCbCr"/> to convert.</param>
/// <returns>
/// An instance of <see cref="Color"/>.
/// </returns>
public static implicit operator Color(YCbCr color)
{
float y = color.Y;
float cb = color.Cb - 128;
float cr = color.Cr - 128;
byte r = (byte)(y + (1.402F * cr)).Clamp(0, 255);
byte g = (byte)(y - (0.34414F * cb) - (0.71414F * cr)).Clamp(0, 255);
byte b = (byte)(y + (1.772F * cb)).Clamp(0, 255);
return new Color(r, g, b);
}
/// <summary>
/// Allows the implicit conversion of an instance of <see cref="CieXyz"/> to a
/// <see cref="Color"/>.
/// </summary>
/// <param name="color">The instance of <see cref="CieXyz"/> to convert.</param>
/// <returns>
/// An instance of <see cref="Color"/>.
/// </returns>
public static implicit operator Color(CieXyz color)
{
float x = color.X / 100F;
float y = color.Y / 100F;
float z = color.Z / 100F;
// Then XYZ to RGB (multiplication by 100 was done above already)
float r = (x * 3.2406F) + (y * -1.5372F) + (z * -0.4986F);
float g = (x * -0.9689F) + (y * 1.8758F) + (z * 0.0415F);
float b = (x * 0.0557F) + (y * -0.2040F) + (z * 1.0570F);
Vector4 vector = new Vector4(r, g, b, 1).Compress();
return new Color(vector);
}
/// <summary>
/// Allows the implicit conversion of an instance of <see cref="Hsv"/> to a
/// <see cref="Color"/>.
/// </summary>
/// <param name="color">The instance of <see cref="Hsv"/> to convert.</param>
/// <returns>
/// An instance of <see cref="Color"/>.
/// </returns>
public static implicit operator Color(Hsv color)
{
float s = color.S;
float v = color.V;
if (Math.Abs(s) < Constants.Epsilon)
{
return new Color(v, v, v, 1);
}
float h = (Math.Abs(color.H - 360) < Constants.Epsilon) ? 0 : color.H / 60;
int i = (int)Math.Truncate(h);
float f = h - i;
float p = v * (1.0F - s);
float q = v * (1.0F - (s * f));
float t = v * (1.0F - (s * (1.0F - f)));
float r, g, b;
switch (i)
{
case 0:
r = v;
g = t;
b = p;
break;
case 1:
r = q;
g = v;
b = p;
break;
case 2:
r = p;
g = v;
b = t;
break;
case 3:
r = p;
g = q;
b = v;
break;
case 4:
r = t;
g = p;
b = v;
break;
default:
r = v;
g = p;
b = q;
break;
}
return new Color(r, g, b, 1);
}
/// <summary>
/// Allows the implicit conversion of an instance of <see cref="Hsl"/> to a
/// <see cref="Color"/>.
/// </summary>
/// <param name="color">The instance of <see cref="Hsl"/> to convert.</param>
/// <returns>
/// An instance of <see cref="Color"/>.
/// </returns>
public static implicit operator Color(Hsl color)
{
float rangedH = color.H / 360F;
float r = 0;
float g = 0;
float b = 0;
float s = color.S;
float l = color.L;
if (Math.Abs(l) > Constants.Epsilon)
{
if (Math.Abs(s) < Constants.Epsilon)
{
r = g = b = l;
}
else
{
float temp2 = (l < 0.5f) ? l * (1f + s) : l + s - (l * s);
float temp1 = (2f * l) - temp2;
r = GetColorComponent(temp1, temp2, rangedH + 0.3333333F);
g = GetColorComponent(temp1, temp2, rangedH);
b = GetColorComponent(temp1, temp2, rangedH - 0.3333333F);
}
}
return new Color(r, g, b, 1);
}
/// <summary>
/// Allows the implicit conversion of an instance of <see cref="CieLab"/> to a
/// <see cref="Color"/>.
/// </summary>
/// <param name="cieLabColor">The instance of <see cref="CieLab"/> to convert.</param>
/// <returns>
/// An instance of <see cref="Color"/>.
/// </returns>
public static implicit operator Color(CieLab cieLabColor)
{
// First convert back to XYZ...
float y = (cieLabColor.L + 16F) / 116F;
float x = (cieLabColor.A / 500F) + y;
float z = y - (cieLabColor.B / 200F);
float x3 = x * x * x;
float y3 = y * y * y;
float z3 = z * z * z;
x = x3 > 0.008856F ? x3 : (x - 0.137931F) / 7.787F;
y = (cieLabColor.L > 7.999625F) ? y3 : (cieLabColor.L / 903.3F);
z = (z3 > 0.008856F) ? z3 : (z - 0.137931F) / 7.787F;
x *= 0.95047F;
z *= 1.08883F;
// Then XYZ to RGB (multiplication by 100 was done above already)
float r = (x * 3.2406F) + (y * -1.5372F) + (z * -0.4986F);
float g = (x * -0.9689F) + (y * 1.8758F) + (z * 0.0415F);
float b = (x * 0.0557F) + (y * -0.2040F) + (z * 1.0570F);
return new Color(new Vector4(r, g, b, 1F).Compress());
}
/// <summary>
/// Gets the color component from the given values.
/// </summary>
/// <param name="first">The first value.</param>
/// <param name="second">The second value.</param>
/// <param name="third">The third value.</param>
/// <returns>
/// The <see cref="float"/>.
/// </returns>
private static float GetColorComponent(float first, float second, float third)
{
third = MoveIntoRange(third);
if (third < 0.1666667F)
{
return first + ((second - first) * 6.0f * third);
}
if (third < 0.5)
{
return second;
}
if (third < 0.6666667F)
{
return first + ((second - first) * (0.6666667F - third) * 6.0f);
}
return first;
}
/// <summary>
/// Moves the specific value within the acceptable range for
/// conversion.
/// <remarks>Used for converting <see cref="Hsl"/> colors to this type.</remarks>
/// </summary>
/// <param name="value">The value to shift.</param>
/// <returns>
/// The <see cref="float"/>.
/// </returns>
private static float MoveIntoRange(float value)
{
if (value < 0.0)
{
value += 1.0f;
}
else if (value > 1.0)
{
value -= 1.0f;
}
return value;
}
}
}

166
src/ImageSharp/Colors/Spaces/Bgra32.cs

@ -1,166 +0,0 @@
// <copyright file="Bgra32.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp.Colors.Spaces
{
using System;
using System.ComponentModel;
using System.Numerics;
/// <summary>
/// Represents an BGRA (blue, green, red, alpha) color.
/// </summary>
public struct Bgra32 : IEquatable<Bgra32>
{
/// <summary>
/// Represents a 32 bit <see cref="Bgra32"/> that has B, G, R, and A values set to zero.
/// </summary>
public static readonly Bgra32 Empty = default(Bgra32);
/// <summary>
/// Min range used for clamping
/// </summary>
private static readonly Vector4 VectorMin = Vector4.Zero;
/// <summary>
/// Max range used for clamping
/// </summary>
private static readonly Vector4 VectorMax = new Vector4(255);
/// <summary>
/// The backing vector for SIMD support.
/// </summary>
private readonly Vector4 backingVector;
/// <summary>
/// Initializes a new instance of the <see cref="Bgra32"/> struct.
/// </summary>
/// <param name="b">The blue component of this <see cref="Bgra32"/>.</param>
/// <param name="g">The green component of this <see cref="Bgra32"/>.</param>
/// <param name="r">The red component of this <see cref="Bgra32"/>.</param>
/// <param name="a">The alpha component of this <see cref="Bgra32"/>.</param>
public Bgra32(byte b, byte g, byte r, byte a = 255)
: this()
{
this.backingVector = Vector4.Clamp(new Vector4(b, g, r, a), VectorMin, VectorMax);
}
/// <summary>
/// Gets the blue component of the color
/// </summary>
public byte B => (byte)this.backingVector.X;
/// <summary>
/// Gets the green component of the color
/// </summary>
public byte G => (byte)this.backingVector.Y;
/// <summary>
/// Gets the red component of the color
/// </summary>
public byte R => (byte)this.backingVector.Z;
/// <summary>
/// Gets the alpha component of the color
/// </summary>
public byte A => (byte)this.backingVector.W;
/// <summary>
/// Gets the <see cref="Bgra32"/> integer representation of the color.
/// </summary>
public int Bgra => (this.R << 16) | (this.G << 8) | (this.B << 0) | (this.A << 24);
/// <summary>
/// Gets a value indicating whether this <see cref="Bgra32"/> is empty.
/// </summary>
[EditorBrowsable(EditorBrowsableState.Never)]
public bool IsEmpty => this.Equals(Empty);
/// <summary>
/// Allows the implicit conversion of an instance of <see cref="Color"/> to a
/// <see cref="Bgra32"/>.
/// </summary>
/// <param name="color">
/// The instance of <see cref="Color"/> to convert.
/// </param>
/// <returns>
/// An instance of <see cref="Bgra32"/>.
/// </returns>
public static implicit operator Bgra32(Color color)
{
return new Bgra32(color.B, color.G, color.R, color.A);
}
/// <summary>
/// Compares two <see cref="Bgra32"/> objects for equality.
/// </summary>
/// <param name="left">
/// The <see cref="Bgra32"/> on the left side of the operand.
/// </param>
/// <param name="right">
/// The <see cref="Bgra32"/> 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>
public static bool operator ==(Bgra32 left, Bgra32 right)
{
return left.Equals(right);
}
/// <summary>
/// Compares two <see cref="Bgra32"/> objects for inequality.
/// </summary>
/// <param name="left">
/// The <see cref="Bgra32"/> on the left side of the operand.
/// </param>
/// <param name="right">
/// The <see cref="Bgra32"/> 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>
public static bool operator !=(Bgra32 left, Bgra32 right)
{
return !left.Equals(right);
}
/// <inheritdoc/>
public override bool Equals(object obj)
{
if (obj is Bgra32)
{
Bgra32 color = (Bgra32)obj;
return this.backingVector == color.backingVector;
}
return false;
}
/// <inheritdoc/>
public override int GetHashCode()
{
return this.backingVector.GetHashCode();
}
/// <inheritdoc/>
public override string ToString()
{
if (this.IsEmpty)
{
return "Bgra32 [ Empty ]";
}
return $"Bgra32 [ B={this.B}, G={this.G}, R={this.R}, A={this.A} ]";
}
/// <inheritdoc/>
public bool Equals(Bgra32 other)
{
return this.backingVector.Equals(other.backingVector);
}
}
}

187
src/ImageSharp/Colors/Spaces/CieLab.cs

@ -1,187 +0,0 @@
// <copyright file="CieLab.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp.Colors.Spaces
{
using System;
using System.ComponentModel;
using System.Numerics;
/// <summary>
/// Represents an CIE LAB 1976 color.
/// <see href="https://en.wikipedia.org/wiki/Lab_color_space"/>
/// </summary>
public struct CieLab : IEquatable<CieLab>, IAlmostEquatable<CieLab, float>
{
/// <summary>
/// Represents a <see cref="CieLab"/> that has L, A, B values set to zero.
/// </summary>
public static readonly CieLab Empty = default(CieLab);
/// <summary>
/// Min range used for clamping
/// </summary>
private static readonly Vector3 VectorMin = new Vector3(0, -100, -100);
/// <summary>
/// Max range used for clamping
/// </summary>
private static readonly Vector3 VectorMax = new Vector3(100);
/// <summary>
/// The backing vector for SIMD support.
/// </summary>
private readonly Vector3 backingVector;
/// <summary>
/// Initializes a new instance of the <see cref="CieLab"/> struct.
/// </summary>
/// <param name="l">The lightness dimension.</param>
/// <param name="a">The a (green - magenta) component.</param>
/// <param name="b">The b (blue - yellow) component.</param>
public CieLab(float l, float a, float b)
: this()
{
this.backingVector = Vector3.Clamp(new Vector3(l, a, b), VectorMin, VectorMax);
}
/// <summary>
/// Gets the lightness dimension.
/// <remarks>A value ranging between 0 (black), 100 (diffuse white) or higher (specular white).</remarks>
/// </summary>
public float L => this.backingVector.X;
/// <summary>
/// Gets the a color component.
/// <remarks>Negative is green, positive magenta.</remarks>
/// </summary>
public float A => this.backingVector.Y;
/// <summary>
/// Gets the b color component.
/// <remarks>Negative is blue, positive is yellow</remarks>
/// </summary>
public float B => this.backingVector.Z;
/// <summary>
/// Gets a value indicating whether this <see cref="CieLab"/> is empty.
/// </summary>
[EditorBrowsable(EditorBrowsableState.Never)]
public bool IsEmpty => this.Equals(Empty);
/// <summary>
/// Allows the implicit conversion of an instance of <see cref="Color"/> to a
/// <see cref="CieLab"/>.
/// </summary>
/// <param name="color">
/// The instance of <see cref="Color"/> to convert.
/// </param>
/// <returns>
/// An instance of <see cref="CieLab"/>.
/// </returns>
public static implicit operator CieLab(Color color)
{
// First convert to CIE XYZ
Vector4 vector = color.ToVector4().Expand();
float x = (vector.X * 0.4124F) + (vector.Y * 0.3576F) + (vector.Z * 0.1805F);
float y = (vector.X * 0.2126F) + (vector.Y * 0.7152F) + (vector.Z * 0.0722F);
float z = (vector.X * 0.0193F) + (vector.Y * 0.1192F) + (vector.Z * 0.9505F);
// Now to LAB
x /= 0.95047F;
// y /= 1F;
z /= 1.08883F;
x = x > 0.008856F ? (float)Math.Pow(x, 0.3333333F) : ((903.3F * x) + 16F) / 116F;
y = y > 0.008856F ? (float)Math.Pow(y, 0.3333333F) : ((903.3F * y) + 16F) / 116F;
z = z > 0.008856F ? (float)Math.Pow(z, 0.3333333F) : ((903.3F * z) + 16F) / 116F;
float l = Math.Max(0, (116F * y) - 16F);
float a = 500F * (x - y);
float b = 200F * (y - z);
return new CieLab(l, a, b);
}
/// <summary>
/// Compares two <see cref="CieLab"/> objects for equality.
/// </summary>
/// <param name="left">
/// The <see cref="CieLab"/> on the left side of the operand.
/// </param>
/// <param name="right">
/// The <see cref="CieLab"/> 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>
public static bool operator ==(CieLab left, CieLab right)
{
return left.Equals(right);
}
/// <summary>
/// Compares two <see cref="CieLab"/> objects for inequality
/// </summary>
/// <param name="left">
/// The <see cref="CieLab"/> on the left side of the operand.
/// </param>
/// <param name="right">
/// The <see cref="CieLab"/> 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>
public static bool operator !=(CieLab left, CieLab right)
{
return !left.Equals(right);
}
/// <inheritdoc/>
public override int GetHashCode()
{
return this.backingVector.GetHashCode();
}
/// <inheritdoc/>
public override string ToString()
{
if (this.IsEmpty)
{
return "CieLab [Empty]";
}
return $"CieLab [ L={this.L:#0.##}, A={this.A:#0.##}, B={this.B:#0.##}]";
}
/// <inheritdoc/>
public override bool Equals(object obj)
{
if (obj is CieLab)
{
return this.Equals((CieLab)obj);
}
return false;
}
/// <inheritdoc/>
public bool Equals(CieLab other)
{
return this.backingVector.Equals(other.backingVector);
}
/// <inheritdoc/>
public bool AlmostEquals(CieLab other, float precision)
{
Vector3 result = Vector3.Abs(this.backingVector - other.backingVector);
return result.X <= precision
&& result.Y <= precision
&& result.Z <= precision;
}
}
}

168
src/ImageSharp/Colors/Spaces/CieXyz.cs

@ -1,168 +0,0 @@
// <copyright file="CieXyz.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp.Colors.Spaces
{
using System;
using System.ComponentModel;
using System.Numerics;
/// <summary>
/// Represents an CIE 1931 color
/// <see href="https://en.wikipedia.org/wiki/CIE_1931_color_space"/>
/// </summary>
public struct CieXyz : IEquatable<CieXyz>, IAlmostEquatable<CieXyz, float>
{
/// <summary>
/// Represents a <see cref="CieXyz"/> that has Y, Cb, and Cr values set to zero.
/// </summary>
public static readonly CieXyz Empty = default(CieXyz);
/// <summary>
/// The backing vector for SIMD support.
/// </summary>
private readonly Vector3 backingVector;
/// <summary>
/// Initializes a new instance of the <see cref="CieXyz"/> struct.
/// </summary>
/// <param name="x">X is a mix (a linear combination) of cone response curves chosen to be nonnegative</param>
/// <param name="y">The y luminance component.</param>
/// <param name="z">Z is quasi-equal to blue stimulation, or the S cone of the human eye.</param>
public CieXyz(float x, float y, float z)
: this()
{
// Not clamping as documentation about this space seems to indicate "usual" ranges
this.backingVector = new Vector3(x, y, z);
}
/// <summary>
/// Gets the Y luminance component.
/// <remarks>A value ranging between 380 and 780.</remarks>
/// </summary>
public float X => this.backingVector.X;
/// <summary>
/// Gets the Cb chroma component.
/// <remarks>A value ranging between 380 and 780.</remarks>
/// </summary>
public float Y => this.backingVector.Y;
/// <summary>
/// Gets the Cr chroma component.
/// <remarks>A value ranging between 380 and 780.</remarks>
/// </summary>
public float Z => this.backingVector.Z;
/// <summary>
/// Gets a value indicating whether this <see cref="CieXyz"/> is empty.
/// </summary>
[EditorBrowsable(EditorBrowsableState.Never)]
public bool IsEmpty => this.Equals(Empty);
/// <summary>
/// Allows the implicit conversion of an instance of <see cref="Color"/> to a
/// <see cref="CieXyz"/>.
/// </summary>
/// <param name="color">
/// The instance of <see cref="Color"/> to convert.
/// </param>
/// <returns>
/// An instance of <see cref="CieXyz"/>.
/// </returns>
public static implicit operator CieXyz(Color color)
{
Vector4 vector = color.ToVector4().Expand();
float x = (vector.X * 0.4124F) + (vector.Y * 0.3576F) + (vector.Z * 0.1805F);
float y = (vector.X * 0.2126F) + (vector.Y * 0.7152F) + (vector.Z * 0.0722F);
float z = (vector.X * 0.0193F) + (vector.Y * 0.1192F) + (vector.Z * 0.9505F);
x *= 100F;
y *= 100F;
z *= 100F;
return new CieXyz(x, y, z);
}
/// <summary>
/// Compares two <see cref="CieXyz"/> objects for equality.
/// </summary>
/// <param name="left">
/// The <see cref="CieXyz"/> on the left side of the operand.
/// </param>
/// <param name="right">
/// The <see cref="CieXyz"/> 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>
public static bool operator ==(CieXyz left, CieXyz right)
{
return left.Equals(right);
}
/// <summary>
/// Compares two <see cref="CieXyz"/> objects for inequality.
/// </summary>
/// <param name="left">
/// The <see cref="CieXyz"/> on the left side of the operand.
/// </param>
/// <param name="right">
/// The <see cref="CieXyz"/> 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>
public static bool operator !=(CieXyz left, CieXyz right)
{
return !left.Equals(right);
}
/// <inheritdoc/>
public override int GetHashCode()
{
return this.backingVector.GetHashCode();
}
/// <inheritdoc/>
public override string ToString()
{
if (this.IsEmpty)
{
return "CieXyz [ Empty ]";
}
return $"CieXyz [ X={this.X:#0.##}, Y={this.Y:#0.##}, Z={this.Z:#0.##} ]";
}
/// <inheritdoc/>
public override bool Equals(object obj)
{
if (obj is CieXyz)
{
return this.Equals((CieXyz)obj);
}
return false;
}
/// <inheritdoc/>
public bool Equals(CieXyz other)
{
return this.backingVector.Equals(other.backingVector);
}
/// <inheritdoc/>
public bool AlmostEquals(CieXyz other, float precision)
{
Vector3 result = Vector3.Abs(this.backingVector - other.backingVector);
return result.X <= precision
&& result.Y <= precision
&& result.Z <= precision;
}
}
}

189
src/ImageSharp/Colors/Spaces/Cmyk.cs

@ -1,189 +0,0 @@
// <copyright file="Cmyk.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp.Colors.Spaces
{
using System;
using System.ComponentModel;
using System.Numerics;
/// <summary>
/// Represents an CMYK (cyan, magenta, yellow, keyline) color.
/// </summary>
public struct Cmyk : IEquatable<Cmyk>, IAlmostEquatable<Cmyk, float>
{
/// <summary>
/// Represents a <see cref="Cmyk"/> that has C, M, Y, and K values set to zero.
/// </summary>
public static readonly Cmyk Empty = default(Cmyk);
/// <summary>
/// Min range used for clamping
/// </summary>
private static readonly Vector4 VectorMin = Vector4.Zero;
/// <summary>
/// Max range used for clamping
/// </summary>
private static readonly Vector4 VectorMax = Vector4.One;
/// <summary>
/// The backing vector for SIMD support.
/// </summary>
private readonly Vector4 backingVector;
/// <summary>
/// Initializes a new instance of the <see cref="Cmyk"/> struct.
/// </summary>
/// <param name="c">The cyan component.</param>
/// <param name="m">The magenta component.</param>
/// <param name="y">The yellow component.</param>
/// <param name="k">The keyline black component.</param>
public Cmyk(float c, float m, float y, float k)
: this()
{
this.backingVector = Vector4.Clamp(new Vector4(c, m, y, k), VectorMin, VectorMax);
}
/// <summary>
/// Gets the cyan color component.
/// <remarks>A value ranging between 0 and 1.</remarks>
/// </summary>
public float C => this.backingVector.X;
/// <summary>
/// Gets the magenta color component.
/// <remarks>A value ranging between 0 and 1.</remarks>
/// </summary>
public float M => this.backingVector.Y;
/// <summary>
/// Gets the yellow color component.
/// <remarks>A value ranging between 0 and 1.</remarks>
/// </summary>
public float Y => this.backingVector.Z;
/// <summary>
/// Gets the keyline black color component.
/// <remarks>A value ranging between 0 and 1.</remarks>
/// </summary>
public float K => this.backingVector.W;
/// <summary>
/// Gets a value indicating whether this <see cref="Cmyk"/> is empty.
/// </summary>
[EditorBrowsable(EditorBrowsableState.Never)]
public bool IsEmpty => this.Equals(Empty);
/// <summary>
/// Allows the implicit conversion of an instance of <see cref="Color"/> to a
/// <see cref="Cmyk"/>.
/// </summary>
/// <param name="color">
/// The instance of <see cref="Bgra32"/> to convert.
/// </param>
/// <returns>
/// An instance of <see cref="Cmyk"/>.
/// </returns>
public static implicit operator Cmyk(Color color)
{
float c = 1f - (color.R / 255F);
float m = 1f - (color.G / 255F);
float y = 1f - (color.B / 255F);
float k = Math.Min(c, Math.Min(m, y));
if (Math.Abs(k - 1.0f) <= Constants.Epsilon)
{
return new Cmyk(0, 0, 0, 1);
}
c = (c - k) / (1 - k);
m = (m - k) / (1 - k);
y = (y - k) / (1 - k);
return new Cmyk(c, m, y, k);
}
/// <summary>
/// Compares two <see cref="Cmyk"/> objects for equality.
/// </summary>
/// <param name="left">
/// The <see cref="Cmyk"/> on the left side of the operand.
/// </param>
/// <param name="right">
/// The <see cref="Cmyk"/> 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>
public static bool operator ==(Cmyk left, Cmyk right)
{
return left.Equals(right);
}
/// <summary>
/// Compares two <see cref="Cmyk"/> objects for inequality
/// </summary>
/// <param name="left">
/// The <see cref="Cmyk"/> on the left side of the operand.
/// </param>
/// <param name="right">
/// The <see cref="Cmyk"/> 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>
public static bool operator !=(Cmyk left, Cmyk right)
{
return !left.Equals(right);
}
/// <inheritdoc/>
public override int GetHashCode()
{
return this.backingVector.GetHashCode();
}
/// <inheritdoc/>
public override string ToString()
{
if (this.IsEmpty)
{
return "Cmyk [Empty]";
}
return $"Cmyk [ C={this.C:#0.##}, M={this.M:#0.##}, Y={this.Y:#0.##}, K={this.K:#0.##}]";
}
/// <inheritdoc/>
public override bool Equals(object obj)
{
if (obj is Cmyk)
{
return this.Equals((Cmyk)obj);
}
return false;
}
/// <inheritdoc/>
public bool Equals(Cmyk other)
{
return this.backingVector.Equals(other.backingVector);
}
/// <inheritdoc/>
public bool AlmostEquals(Cmyk other, float precision)
{
Vector4 result = Vector4.Abs(this.backingVector - other.backingVector);
return result.X <= precision
&& result.Y <= precision
&& result.Z <= precision
&& result.W <= precision;
}
}
}

207
src/ImageSharp/Colors/Spaces/Hsl.cs

@ -1,207 +0,0 @@
// <copyright file="Hsl.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp.Colors.Spaces
{
using System;
using System.ComponentModel;
using System.Numerics;
/// <summary>
/// Represents a Hsl (hue, saturation, lightness) color.
/// </summary>
public struct Hsl : IEquatable<Hsl>, IAlmostEquatable<Hsl, float>
{
/// <summary>
/// Represents a <see cref="Hsl"/> that has H, S, and L values set to zero.
/// </summary>
public static readonly Hsl Empty = default(Hsl);
/// <summary>
/// Min range used for clamping
/// </summary>
private static readonly Vector3 VectorMin = Vector3.Zero;
/// <summary>
/// Max range used for clamping
/// </summary>
private static readonly Vector3 VectorMax = new Vector3(360, 1, 1);
/// <summary>
/// The backing vector for SIMD support.
/// </summary>
private readonly Vector3 backingVector;
/// <summary>
/// Initializes a new instance of the <see cref="Hsl"/> struct.
/// </summary>
/// <param name="h">The h hue component.</param>
/// <param name="s">The s saturation component.</param>
/// <param name="l">The l value (lightness) component.</param>
public Hsl(float h, float s, float l)
{
this.backingVector = Vector3.Clamp(new Vector3(h, s, l), VectorMin, VectorMax);
}
/// <summary>
/// Gets the hue component.
/// <remarks>A value ranging between 0 and 360.</remarks>
/// </summary>
public float H => this.backingVector.X;
/// <summary>
/// Gets the saturation component.
/// <remarks>A value ranging between 0 and 1.</remarks>
/// </summary>
public float S => this.backingVector.Y;
/// <summary>
/// Gets the lightness component.
/// <remarks>A value ranging between 0 and 1.</remarks>
/// </summary>
public float L => this.backingVector.Z;
/// <summary>
/// Gets a value indicating whether this <see cref="Hsl"/> is empty.
/// </summary>
[EditorBrowsable(EditorBrowsableState.Never)]
public bool IsEmpty => this.Equals(Empty);
/// <summary>
/// Allows the implicit conversion of an instance of <see cref="Color"/> to a
/// <see cref="Hsl"/>.
/// </summary>
/// <param name="color">The instance of <see cref="Color"/> to convert.</param>
/// <returns>
/// An instance of <see cref="Hsl"/>.
/// </returns>
public static implicit operator Hsl(Color color)
{
float r = color.R / 255F;
float g = color.G / 255F;
float b = color.B / 255F;
float max = Math.Max(r, Math.Max(g, b));
float min = Math.Min(r, Math.Min(g, b));
float chroma = max - min;
float h = 0;
float s = 0;
float l = (max + min) / 2;
if (Math.Abs(chroma) < Constants.Epsilon)
{
return new Hsl(0, s, l);
}
if (Math.Abs(r - max) < Constants.Epsilon)
{
h = (g - b) / chroma;
}
else if (Math.Abs(g - max) < Constants.Epsilon)
{
h = 2 + ((b - r) / chroma);
}
else if (Math.Abs(b - max) < Constants.Epsilon)
{
h = 4 + ((r - g) / chroma);
}
h *= 60;
if (h < 0.0)
{
h += 360;
}
if (l <= .5f)
{
s = chroma / (max + min);
}
else
{
s = chroma / (2 - chroma);
}
return new Hsl(h, s, l);
}
/// <summary>
/// Compares two <see cref="Hsl"/> objects for equality.
/// </summary>
/// <param name="left">
/// The <see cref="Hsl"/> on the left side of the operand.
/// </param>
/// <param name="right">
/// The <see cref="Hsl"/> 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>
public static bool operator ==(Hsl left, Hsl right)
{
return left.Equals(right);
}
/// <summary>
/// Compares two <see cref="Hsl"/> objects for inequality.
/// </summary>
/// <param name="left">
/// The <see cref="Hsl"/> on the left side of the operand.
/// </param>
/// <param name="right">
/// The <see cref="Hsl"/> 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>
public static bool operator !=(Hsl left, Hsl right)
{
return !left.Equals(right);
}
/// <inheritdoc/>
public override int GetHashCode()
{
return this.backingVector.GetHashCode();
}
/// <inheritdoc/>
public override string ToString()
{
if (this.IsEmpty)
{
return "Hsl [ Empty ]";
}
return $"Hsl [ H={this.H:#0.##}, S={this.S:#0.##}, L={this.L:#0.##} ]";
}
/// <inheritdoc/>
public override bool Equals(object obj)
{
if (obj is Hsl)
{
return this.Equals((Hsl)obj);
}
return false;
}
/// <inheritdoc/>
public bool Equals(Hsl other)
{
return this.backingVector.Equals(other.backingVector);
}
/// <inheritdoc/>
public bool AlmostEquals(Hsl other, float precision)
{
Vector3 result = Vector3.Abs(this.backingVector - other.backingVector);
return result.X <= precision
&& result.Y <= precision
&& result.Z <= precision;
}
}
}

200
src/ImageSharp/Colors/Spaces/Hsv.cs

@ -1,200 +0,0 @@
// <copyright file="Hsv.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp.Colors.Spaces
{
using System;
using System.ComponentModel;
using System.Numerics;
/// <summary>
/// Represents a HSV (hue, saturation, value) color. Also known as HSB (hue, saturation, brightness).
/// </summary>
public struct Hsv : IEquatable<Hsv>, IAlmostEquatable<Hsv, float>
{
/// <summary>
/// Represents a <see cref="Hsv"/> that has H, S, and V values set to zero.
/// </summary>
public static readonly Hsv Empty = default(Hsv);
/// <summary>
/// Min range used for clamping
/// </summary>
private static readonly Vector3 VectorMin = Vector3.Zero;
/// <summary>
/// Max range used for clamping
/// </summary>
private static readonly Vector3 VectorMax = new Vector3(360, 1, 1);
/// <summary>
/// The backing vector for SIMD support.
/// </summary>
private readonly Vector3 backingVector;
/// <summary>
/// Initializes a new instance of the <see cref="Hsv"/> struct.
/// </summary>
/// <param name="h">The h hue component.</param>
/// <param name="s">The s saturation component.</param>
/// <param name="v">The v value (brightness) component.</param>
public Hsv(float h, float s, float v)
{
this.backingVector = Vector3.Clamp(new Vector3(h, s, v), VectorMin, VectorMax);
}
/// <summary>
/// Gets the hue component.
/// <remarks>A value ranging between 0 and 360.</remarks>
/// </summary>
public float H => this.backingVector.X;
/// <summary>
/// Gets the saturation component.
/// <remarks>A value ranging between 0 and 1.</remarks>
/// </summary>
public float S => this.backingVector.Y;
/// <summary>
/// Gets the value (brightness) component.
/// <remarks>A value ranging between 0 and 1.</remarks>
/// </summary>
public float V => this.backingVector.Z;
/// <summary>
/// Gets a value indicating whether this <see cref="Hsv"/> is empty.
/// </summary>
[EditorBrowsable(EditorBrowsableState.Never)]
public bool IsEmpty => this.Equals(Empty);
/// <summary>
/// Allows the implicit conversion of an instance of <see cref="Color"/> to a
/// <see cref="Hsv"/>.
/// </summary>
/// <param name="color">The instance of <see cref="Color"/> to convert.</param>
/// <returns>
/// An instance of <see cref="Hsv"/>.
/// </returns>
public static implicit operator Hsv(Color color)
{
float r = color.R / 255F;
float g = color.G / 255F;
float b = color.B / 255F;
float max = Math.Max(r, Math.Max(g, b));
float min = Math.Min(r, Math.Min(g, b));
float chroma = max - min;
float h = 0;
float s = 0;
float v = max;
if (Math.Abs(chroma) < Constants.Epsilon)
{
return new Hsv(0, s, v);
}
if (Math.Abs(r - max) < Constants.Epsilon)
{
h = (g - b) / chroma;
}
else if (Math.Abs(g - max) < Constants.Epsilon)
{
h = 2 + ((b - r) / chroma);
}
else if (Math.Abs(b - max) < Constants.Epsilon)
{
h = 4 + ((r - g) / chroma);
}
h *= 60;
if (h < 0.0)
{
h += 360;
}
s = chroma / v;
return new Hsv(h, s, v);
}
/// <summary>
/// Compares two <see cref="Hsv"/> objects for equality.
/// </summary>
/// <param name="left">
/// The <see cref="Hsv"/> on the left side of the operand.
/// </param>
/// <param name="right">
/// The <see cref="Hsv"/> 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>
public static bool operator ==(Hsv left, Hsv right)
{
return left.Equals(right);
}
/// <summary>
/// Compares two <see cref="Hsv"/> objects for inequality.
/// </summary>
/// <param name="left">
/// The <see cref="Hsv"/> on the left side of the operand.
/// </param>
/// <param name="right">
/// The <see cref="Hsv"/> 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>
public static bool operator !=(Hsv left, Hsv right)
{
return !left.Equals(right);
}
/// <inheritdoc/>
public override int GetHashCode()
{
return this.backingVector.GetHashCode();
}
/// <inheritdoc/>
public override string ToString()
{
if (this.IsEmpty)
{
return "Hsv [ Empty ]";
}
return $"Hsv [ H={this.H:#0.##}, S={this.S:#0.##}, V={this.V:#0.##} ]";
}
/// <inheritdoc/>
public override bool Equals(object obj)
{
if (obj is Hsv)
{
return this.Equals((Hsv)obj);
}
return false;
}
/// <inheritdoc/>
public bool Equals(Hsv other)
{
return this.backingVector.Equals(other.backingVector);
}
/// <inheritdoc/>
public bool AlmostEquals(Hsv other, float precision)
{
Vector3 result = Vector3.Abs(this.backingVector - other.backingVector);
return result.X <= precision
&& result.Y <= precision
&& result.Z <= precision;
}
}
}

30
src/ImageSharp/Colors/Spaces/IAlmostEquatable.cs

@ -1,30 +0,0 @@
// <copyright file="IAlmostEquatable.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp.Colors.Spaces
{
using System;
/// <summary>
/// Defines a generalized method that a value type or class implements to create
/// a type-specific method for determining approximate equality of instances.
/// </summary>
/// <typeparam name="TColor">The type of objects to compare.</typeparam>
/// <typeparam name="TPrecision">The object specifying the type to specify precision with.</typeparam>
public interface IAlmostEquatable<in TColor, in TPrecision>
where TPrecision : struct, IComparable<TPrecision>
{
/// <summary>
/// Indicates whether the current object is equal to another object of the same type
/// when compared to the specified precision level.
/// </summary>
/// <param name="other">An object to compare with this object.</param>
/// <param name="precision">The object specifying the level of precision.</param>
/// <returns>
/// true if the current object is equal to the other parameter; otherwise, false.
/// </returns>
bool AlmostEquals(TColor other, TPrecision precision);
}
}

165
src/ImageSharp/Colors/Spaces/YCbCr.cs

@ -1,165 +0,0 @@
// <copyright file="YCbCr.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp.Colors.Spaces
{
using System;
using System.ComponentModel;
using System.Numerics;
/// <summary>
/// Represents an YCbCr (luminance, blue chroma, red chroma) color conforming to the full range standard used in digital imaging systems.
/// <see href="http://en.wikipedia.org/wiki/YCbCr"/>
/// </summary>
public struct YCbCr : IEquatable<YCbCr>
{
/// <summary>
/// Represents a <see cref="YCbCr"/> that has Y, Cb, and Cr values set to zero.
/// </summary>
public static readonly YCbCr Empty = default(YCbCr);
/// <summary>
/// Min range used for clamping
/// </summary>
private static readonly Vector3 VectorMin = Vector3.Zero;
/// <summary>
/// Vector which is used in clamping to the max value
/// </summary>
private static readonly Vector3 VectorMax = new Vector3(255);
/// <summary>
/// The backing vector for SIMD support.
/// </summary>
private readonly Vector3 backingVector;
/// <summary>
/// Initializes a new instance of the <see cref="YCbCr"/> struct.
/// </summary>
/// <param name="y">The y luminance component.</param>
/// <param name="cb">The cb chroma component.</param>
/// <param name="cr">The cr chroma component.</param>
public YCbCr(byte y, byte cb, byte cr)
: this()
{
this.backingVector = Vector3.Clamp(new Vector3(y, cb, cr), VectorMin, VectorMax);
}
/// <summary>
/// Gets the Y luminance component.
/// <remarks>A value ranging between 0 and 255.</remarks>
/// </summary>
public byte Y => (byte)this.backingVector.X;
/// <summary>
/// Gets the Cb chroma component.
/// <remarks>A value ranging between 0 and 255.</remarks>
/// </summary>
public byte Cb => (byte)this.backingVector.Y;
/// <summary>
/// Gets the Cr chroma component.
/// <remarks>A value ranging between 0 and 255.</remarks>
/// </summary>
public byte Cr => (byte)this.backingVector.Z;
/// <summary>
/// Gets a value indicating whether this <see cref="YCbCr"/> is empty.
/// </summary>
[EditorBrowsable(EditorBrowsableState.Never)]
public bool IsEmpty => this.Equals(Empty);
/// <summary>
/// Allows the implicit conversion of an instance of <see cref="Color"/> to a
/// <see cref="YCbCr"/>.
/// </summary>
/// <param name="color">
/// The instance of <see cref="Color"/> to convert.
/// </param>
/// <returns>
/// An instance of <see cref="YCbCr"/>.
/// </returns>
public static implicit operator YCbCr(Color color)
{
byte r = color.R;
byte g = color.G;
byte b = color.B;
byte y = (byte)((0.299F * r) + (0.587F * g) + (0.114F * b));
byte cb = (byte)(128 + ((-0.168736F * r) - (0.331264F * g) + (0.5F * b)));
byte cr = (byte)(128 + ((0.5F * r) - (0.418688F * g) - (0.081312F * b)));
return new YCbCr(y, cb, cr);
}
/// <summary>
/// Compares two <see cref="YCbCr"/> objects for equality.
/// </summary>
/// <param name="left">
/// The <see cref="YCbCr"/> on the left side of the operand.
/// </param>
/// <param name="right">
/// The <see cref="YCbCr"/> 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>
public static bool operator ==(YCbCr left, YCbCr right)
{
return left.Equals(right);
}
/// <summary>
/// Compares two <see cref="YCbCr"/> objects for inequality.
/// </summary>
/// <param name="left">
/// The <see cref="YCbCr"/> on the left side of the operand.
/// </param>
/// <param name="right">
/// The <see cref="YCbCr"/> 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>
public static bool operator !=(YCbCr left, YCbCr right)
{
return !left.Equals(right);
}
/// <inheritdoc/>
public override int GetHashCode()
{
return this.backingVector.GetHashCode();
}
/// <inheritdoc/>
public override string ToString()
{
if (this.IsEmpty)
{
return "YCbCr [ Empty ]";
}
return $"YCbCr [ Y={this.Y}, Cb={this.Cb}, Cr={this.Cr} ]";
}
/// <inheritdoc/>
public override bool Equals(object obj)
{
if (obj is YCbCr)
{
return this.Equals((YCbCr)obj);
}
return false;
}
/// <inheritdoc/>
public bool Equals(YCbCr other)
{
return this.backingVector.Equals(other.backingVector);
}
}
}

493
tests/ImageSharp.Tests/Colors/ColorConversionTests.cs

@ -1,493 +0,0 @@
// <copyright file="ColorConversionTests.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp.Tests
{
using System;
using System.Diagnostics.CodeAnalysis;
using ImageSharp.Colors.Spaces;
using Xunit;
/// <summary>
/// Test conversion between the various color structs.
/// </summary>
/// <remarks>
/// Output values have been compared with <see cref="http://colormine.org/color-converter"/>
/// and <see cref="http://www.colorhexa.com/"/> for accuracy.
/// </remarks>
public class ColorConversionTests
{
/// <summary>
/// Tests the implicit conversion from <see cref="Color"/> to <see cref="YCbCr"/>.
/// </summary>
[Fact]
[SuppressMessage("StyleCop.CSharp.NamingRules", "SA1305:FieldNamesMustNotUseHungarianNotation",
Justification = "Reviewed. Suppression is OK here.")]
public void ColorToYCbCr()
{
// White
Color color = Color.White;
YCbCr yCbCr = color;
Assert.Equal(255, yCbCr.Y);
Assert.Equal(128, yCbCr.Cb);
Assert.Equal(128, yCbCr.Cr);
// Black
Color color2 = Color.Black;
YCbCr yCbCr2 = color2;
Assert.Equal(0, yCbCr2.Y);
Assert.Equal(128, yCbCr2.Cb);
Assert.Equal(128, yCbCr2.Cr);
// Gray
Color color3 = Color.Gray;
YCbCr yCbCr3 = color3;
Assert.Equal(128, yCbCr3.Y);
Assert.Equal(128, yCbCr3.Cb);
Assert.Equal(128, yCbCr3.Cr);
}
/// <summary>
/// Tests the implicit conversion from <see cref="YCbCr"/> to <see cref="Color"/>.
/// </summary>
[Fact]
[SuppressMessage("StyleCop.CSharp.NamingRules", "SA1305:FieldNamesMustNotUseHungarianNotation",
Justification = "Reviewed. Suppression is OK here.")]
public void YCbCrToColor()
{
// White
YCbCr yCbCr = new YCbCr(255, 128, 128);
Color color = yCbCr;
Assert.Equal(255, color.R);
Assert.Equal(255, color.G);
Assert.Equal(255, color.B);
Assert.Equal(255, color.A);
// Black
YCbCr yCbCr2 = new YCbCr(0, 128, 128);
Color color2 = yCbCr2;
Assert.Equal(0, color2.R);
Assert.Equal(0, color2.G);
Assert.Equal(0, color2.B);
Assert.Equal(255, color2.A);
// Gray
YCbCr yCbCr3 = new YCbCr(128, 128, 128);
Color color3 = yCbCr3;
Assert.Equal(128, color3.R);
Assert.Equal(128, color3.G);
Assert.Equal(128, color3.B);
Assert.Equal(255, color3.A);
}
/// <summary>
/// Tests the implicit conversion from <see cref="Color"/> to <see cref="CieXyz"/>.
/// Comparison values obtained from
/// http://colormine.org/convert/rgb-to-xyz
/// </summary>
[Fact]
public void ColorToCieXyz()
{
// White
Color color = Color.White;
CieXyz ciexyz = color;
Assert.Equal(95.05f, ciexyz.X, 3);
Assert.Equal(100.0f, ciexyz.Y, 3);
Assert.Equal(108.900f, ciexyz.Z, 3);
// Black
Color color2 = Color.Black;
CieXyz ciexyz2 = color2;
Assert.Equal(0, ciexyz2.X, 3);
Assert.Equal(0, ciexyz2.Y, 3);
Assert.Equal(0, ciexyz2.Z, 3);
// Gray
Color color3 = Color.Gray;
CieXyz ciexyz3 = color3;
Assert.Equal(20.518, ciexyz3.X, 3);
Assert.Equal(21.586, ciexyz3.Y, 3);
Assert.Equal(23.507, ciexyz3.Z, 3);
// Cyan
Color color4 = Color.Cyan;
CieXyz ciexyz4 = color4;
Assert.Equal(53.810f, ciexyz4.X, 3);
Assert.Equal(78.740f, ciexyz4.Y, 3);
Assert.Equal(106.970f, ciexyz4.Z, 3);
}
/// <summary>
/// Tests the implicit conversion from <see cref="CieXyz"/> to <see cref="Color"/>.
/// Comparison values obtained from
/// http://colormine.org/convert/rgb-to-xyz
/// </summary>
[Fact]
public void CieXyzToColor()
{
// Dark moderate pink.
CieXyz ciexyz = new CieXyz(13.337f, 9.297f, 14.727f);
Color color = ciexyz;
Assert.Equal(128, color.R);
Assert.Equal(64, color.G);
Assert.Equal(106, color.B);
// Ochre
CieXyz ciexyz2 = new CieXyz(31.787f, 26.147f, 4.885f);
Color color2 = ciexyz2;
Assert.Equal(204, color2.R);
Assert.Equal(119, color2.G);
Assert.Equal(34, color2.B);
// Black
CieXyz ciexyz3 = new CieXyz(0, 0, 0);
Color color3 = ciexyz3;
Assert.Equal(0, color3.R);
Assert.Equal(0, color3.G);
Assert.Equal(0, color3.B);
//// Check others.
//Random random = new Random(0);
//for (int i = 0; i < 1000; i++)
//{
// Color color4 = new Color((float)random.NextDouble(), (float)random.NextDouble(), (float)random.NextDouble());
// CieXyz ciexyz4 = color4;
// Assert.Equal(color4, (Color)ciexyz4);
//}
}
/// <summary>
/// Tests the implicit conversion from <see cref="Color"/> to <see cref="Hsv"/>.
/// </summary>
[Fact]
[SuppressMessage("StyleCop.CSharp.NamingRules", "SA1305:FieldNamesMustNotUseHungarianNotation",
Justification = "Reviewed. Suppression is OK here.")]
public void ColorToHsv()
{
// Black
Color b = Color.Black;
Hsv h = b;
Assert.Equal(0, h.H, 1);
Assert.Equal(0, h.S, 1);
Assert.Equal(0, h.V, 1);
// White
Color color = Color.White;
Hsv hsv = color;
Assert.Equal(0f, hsv.H, 1);
Assert.Equal(0f, hsv.S, 1);
Assert.Equal(1f, hsv.V, 1);
// Dark moderate pink.
Color color2 = new Color(128, 64, 106);
Hsv hsv2 = color2;
Assert.Equal(320.6f, hsv2.H, 1);
Assert.Equal(0.5f, hsv2.S, 1);
Assert.Equal(0.502f, hsv2.V, 2);
// Ochre.
Color color3 = new Color(204, 119, 34);
Hsv hsv3 = color3;
Assert.Equal(30f, hsv3.H, 1);
Assert.Equal(0.833f, hsv3.S, 3);
Assert.Equal(0.8f, hsv3.V, 1);
}
/// <summary>
/// Tests the implicit conversion from <see cref="Hsv"/> to <see cref="Color"/>.
/// </summary>
[Fact]
public void HsvToColor()
{
// Dark moderate pink.
Hsv hsv = new Hsv(320.6f, 0.5f, 0.502f);
Color color = hsv;
Assert.Equal(color.R, 128);
Assert.Equal(color.G, 64);
Assert.Equal(color.B, 106);
// Ochre
Hsv hsv2 = new Hsv(30, 0.833f, 0.8f);
Color color2 = hsv2;
Assert.Equal(color2.R, 204);
Assert.Equal(color2.G, 119);
Assert.Equal(color2.B, 34);
// White
Hsv hsv3 = new Hsv(0, 0, 1);
Color color3 = hsv3;
Assert.Equal(color3.B, 255);
Assert.Equal(color3.G, 255);
Assert.Equal(color3.R, 255);
// Check others.
//Random random = new Random(0);
//for (int i = 0; i < 1000; i++)
//{
// Color color4 = new Color((float)random.NextDouble(), (float)random.NextDouble(), (float)random.NextDouble());
// Hsv hsv4 = color4;
// Assert.Equal(color4, (Color)hsv4);
//}
}
/// <summary>
/// Tests the implicit conversion from <see cref="Color"/> to <see cref="Hsl"/>.
/// </summary>
[Fact]
[SuppressMessage("StyleCop.CSharp.NamingRules", "SA1305:FieldNamesMustNotUseHungarianNotation",
Justification = "Reviewed. Suppression is OK here.")]
public void ColorToHsl()
{
// Black
Color b = Color.Black;
Hsl h = b;
Assert.Equal(0, h.H, 1);
Assert.Equal(0, h.S, 1);
Assert.Equal(0, h.L, 1);
// White
Color color = Color.White;
Hsl hsl = color;
Assert.Equal(0f, hsl.H, 1);
Assert.Equal(0f, hsl.S, 1);
Assert.Equal(1f, hsl.L, 1);
// Dark moderate pink.
Color color2 = new Color(128, 64, 106);
Hsl hsl2 = color2;
Assert.Equal(320.6f, hsl2.H, 1);
Assert.Equal(0.33f, hsl2.S, 1);
Assert.Equal(0.376f, hsl2.L, 2);
// Ochre.
Color color3 = new Color(204, 119, 34);
Hsl hsl3 = color3;
Assert.Equal(30f, hsl3.H, 1);
Assert.Equal(0.714f, hsl3.S, 3);
Assert.Equal(0.467f, hsl3.L, 3);
}
/// <summary>
/// Tests the implicit conversion from <see cref="Hsl"/> to <see cref="Color"/>.
/// </summary>
[Fact]
public void HslToColor()
{
// Dark moderate pink.
Hsl hsl = new Hsl(320.6f, 0.33f, 0.376f);
Color color = hsl;
Assert.Equal(color.R, 128);
Assert.Equal(color.G, 64);
Assert.Equal(color.B, 106);
// Ochre
Hsl hsl2 = new Hsl(30, 0.714f, 0.467f);
Color color2 = hsl2;
Assert.Equal(color2.R, 204);
Assert.Equal(color2.G, 119);
Assert.Equal(color2.B, 34);
// White
Hsl hsl3 = new Hsl(0, 0, 1);
Color color3 = hsl3;
Assert.Equal(color3.R, 255);
Assert.Equal(color3.G, 255);
Assert.Equal(color3.B, 255);
// Check others.
//Random random = new Random(0);
//for (int i = 0; i < 1000; i++)
//{
// Color color4 = new Color((float)random.NextDouble(), (float)random.NextDouble(), (float)random.NextDouble());
// Hsl hsl4 = color4;
// Assert.Equal(color4, (Color)hsl4);
//}
}
/// <summary>
/// Tests the implicit conversion from <see cref="Color"/> to <see cref="Cmyk"/>.
/// </summary>
[Fact]
[SuppressMessage("StyleCop.CSharp.NamingRules", "SA1305:FieldNamesMustNotUseHungarianNotation",
Justification = "Reviewed. Suppression is OK here.")]
public void ColorToCmyk()
{
// White
Color color = Color.White;
Cmyk cmyk = color;
Assert.Equal(0, cmyk.C, 1);
Assert.Equal(0, cmyk.M, 1);
Assert.Equal(0, cmyk.Y, 1);
Assert.Equal(0, cmyk.K, 1);
// Black
Color color2 = Color.Black;
Cmyk cmyk2 = color2;
Assert.Equal(0, cmyk2.C, 1);
Assert.Equal(0, cmyk2.M, 1);
Assert.Equal(0, cmyk2.Y, 1);
Assert.Equal(1, cmyk2.K, 1);
// Gray
Color color3 = Color.Gray;
Cmyk cmyk3 = color3;
Assert.Equal(0f, cmyk3.C, 1);
Assert.Equal(0f, cmyk3.M, 1);
Assert.Equal(0f, cmyk3.Y, 1);
Assert.Equal(0.498, cmyk3.K, 2); // Checked with other online converters.
// Cyan
Color color4 = Color.Cyan;
Cmyk cmyk4 = color4;
Assert.Equal(1, cmyk4.C, 1);
Assert.Equal(0f, cmyk4.M, 1);
Assert.Equal(0f, cmyk4.Y, 1);
Assert.Equal(0f, cmyk4.K, 1);
}
/// <summary>
/// Tests the implicit conversion from <see cref="Cmyk"/> to <see cref="Color"/>.
/// </summary>
[Fact]
public void CmykToColor()
{
// Dark moderate pink.
Cmyk cmyk = new Cmyk(0f, .5f, .171f, .498f);
Color color = cmyk;
Assert.Equal(color.R, 128);
Assert.Equal(color.G, 64);
Assert.Equal(color.B, 106);
// Ochre
Cmyk cmyk2 = new Cmyk(0, .416f, .833f, .199f);
Color color2 = cmyk2;
Assert.Equal(color2.R, 204);
Assert.Equal(color2.G, 119);
Assert.Equal(color2.B, 34);
// White
Cmyk cmyk3 = new Cmyk(0, 0, 0, 0);
Color color3 = cmyk3;
Assert.Equal(color3.R, 255);
Assert.Equal(color3.G, 255);
Assert.Equal(color3.B, 255);
// Check others.
//Random random = new Random(0);
//for (int i = 0; i < 1000; i++)
//{
// Color color4 = new Color((float)random.NextDouble(), (float)random.NextDouble(), (float)random.NextDouble());
// Cmyk cmyk4 = color4;
// Assert.Equal(color4, (Color)cmyk4);
//}
}
/// <summary>
/// Tests the implicit conversion from <see cref="Color"/> to <see cref="CieLab"/>.
/// Comparison values obtained from
/// http://colormine.org/convert/rgb-to-lab
/// </summary>
[Fact]
public void ColorToCieLab()
{
// White
Color color = Color.White;
CieLab cielab = color;
Assert.Equal(100, cielab.L, 3);
Assert.Equal(0.005, cielab.A, 3);
Assert.Equal(-0.010, cielab.B, 3);
// Black
Color color2 = Color.Black;
CieLab cielab2 = color2;
Assert.Equal(0, cielab2.L, 3);
Assert.Equal(0, cielab2.A, 3);
Assert.Equal(0, cielab2.B, 3);
// Gray
Color color3 = Color.Gray;
CieLab cielab3 = color3;
Assert.Equal(53.585, cielab3.L, 3);
Assert.Equal(0.003, cielab3.A, 3);
Assert.Equal(-0.006, cielab3.B, 3);
// Cyan
Color color4 = Color.Cyan;
CieLab cielab4 = color4;
Assert.Equal(91.117, cielab4.L, 3);
Assert.Equal(-48.080, cielab4.A, 3);
Assert.Equal(-14.138, cielab4.B, 3);
}
/// <summary>
/// Tests the implicit conversion from <see cref="CieLab"/> to <see cref="Color"/>.
/// </summary>
/// Comparison values obtained from
/// http://colormine.org/convert/rgb-to-lab
[Fact]
public void CieLabToColor()
{
// Dark moderate pink.
CieLab cielab = new CieLab(36.5492f, 33.3173f, -12.0615f);
Color color = cielab;
Assert.Equal(color.R, 128);
Assert.Equal(color.G, 64);
Assert.Equal(color.B, 106);
// Ochre
CieLab cielab2 = new CieLab(58.1758f, 27.3399f, 56.8240f);
Color color2 = cielab2;
Assert.Equal(color2.R, 204);
Assert.Equal(color2.G, 119);
Assert.Equal(color2.B, 34);
// Black
CieLab cielab3 = new CieLab(0, 0, 0);
Color color3 = cielab3;
Assert.Equal(color3.R, 0);
Assert.Equal(color3.G, 0);
Assert.Equal(color3.B, 0);
// Check others.
//Random random = new Random(0);
//for (int i = 0; i < 1000; i++)
//{
// Color color4 = new Color((float)random.NextDouble(), (float)random.NextDouble(), (float)random.NextDouble());
// CieLab cielab4 = color4;
// Assert.Equal(color4, (Color)cielab4);
//}
}
}
}

3
tests/ImageSharp.Tests/Colors/ColorDefinitionTests.cs

@ -5,13 +5,10 @@
namespace ImageSharp.Tests
{
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Reflection;
using ImageSharp.Colors.Spaces;
using Xunit;
public class ColorDefinitionTests
{

216
tests/ImageSharp.Tests/Colors/ColorEqualityTests.cs

@ -7,7 +7,6 @@ namespace ImageSharp.Tests.Colors
{
using System;
using System.Numerics;
using ImageSharp.Colors.Spaces;
using Xunit;
/// <summary>
@ -38,38 +37,6 @@ namespace ImageSharp.Tests.Colors
{ new Short4(Vector4.One * 0x7FFF), new Short4(Vector4.One * 0x7FFF), typeof(Short4) },
};
public static readonly TheoryData<object, object, Type> EqualityDataColorSpaces =
new TheoryData<object, object, Type>()
{
{ new Bgra32(0, 0, 0), new Bgra32(0, 0, 0), typeof(Bgra32) },
{ new Bgra32(0, 0, 0, 0), new Bgra32(0, 0, 0, 0), typeof(Bgra32) },
{ new Bgra32(100, 100, 0, 0), new Bgra32(100, 100, 0, 0), typeof(Bgra32) },
{ new Bgra32(255, 255, 255), new Bgra32(255, 255, 255), typeof(Bgra32) },
{ new CieLab(0f, 0f, 0f), new CieLab(0f, 0f, 0f), typeof(CieLab) },
{ new CieLab(1f, 1f, 1f), new CieLab(1f, 1f, 1f), typeof(CieLab) },
{ new CieLab(0f, -100f, -100f), new CieLab(0f, -100f, -100f), typeof(CieLab) },
{ new CieLab(0f, 100f, -100f), new CieLab(0f, 100f, -100f), typeof(CieLab) },
{ new CieLab(0f, -100f, 100f), new CieLab(0f, -100f, 100f), typeof(CieLab) },
{ new CieLab(0f, -100f, 50f), new CieLab(0f, -100f, 50f), typeof(CieLab) },
{ new CieXyz(380f, 380f, 380f), new CieXyz(380f, 380f, 380f), typeof(CieXyz) },
{ new CieXyz(780f, 780f, 780f), new CieXyz(780f, 780f, 780f), typeof(CieXyz) },
{ new CieXyz(380f, 780f, 780f), new CieXyz(380f, 780f, 780f), typeof(CieXyz) },
{ new CieXyz(50f, 20f, 60f), new CieXyz(50f, 20f, 60f), typeof(CieXyz) },
{ new Cmyk(0f, 0f, 0f, 0f), new Cmyk(0f, 0f, 0f, 0f), typeof(Cmyk) },
{ new Cmyk(1f, 1f, 1f, 1f), new Cmyk(1f, 1f, 1f, 1f), typeof(Cmyk) },
{ new Cmyk(10f, 10f, 10f, 10f), new Cmyk(10f, 10f, 10f, 10f), typeof(Cmyk) },
{ new Cmyk(.4f, .5f, .1f, .2f), new Cmyk(.4f, .5f, .1f, .2f), typeof(Cmyk) },
{ new Hsl(0f, 0f, 0f), new Hsl(0f, 0f, 0f), typeof(Hsl) },
{ new Hsl(360f, 1f, 1f), new Hsl(360f, 1f, 1f), typeof(Hsl) },
{ new Hsl(100f, .5f, .1f), new Hsl(100f, .5f, .1f), typeof(Hsl) },
{ new Hsv(0f, 0f, 0f), new Hsv(0f, 0f, 0f), typeof(Hsv) },
{ new Hsv(360f, 1f, 1f), new Hsv(360f, 1f, 1f), typeof(Hsv) },
{ new Hsv(100f, .5f, .1f), new Hsv(100f, .5f, .1f), typeof(Hsv) },
{ new YCbCr(0, 0, 0), new YCbCr(0, 0, 0), typeof(YCbCr) },
{ new YCbCr(255, 255, 255), new YCbCr(255, 255, 255), typeof(YCbCr) },
{ new YCbCr(100, 100, 0), new YCbCr(100, 100, 0), typeof(YCbCr) },
};
public static readonly TheoryData<object, object, Type> NotEqualityDataNulls =
new TheoryData<object, object, Type>()
{
@ -94,18 +61,6 @@ namespace ImageSharp.Tests.Colors
{ new Short4(Vector4.One * 0x7FFF), null, typeof(Short4) },
};
public static readonly TheoryData<object, object, Type> NotEqualityDataNullsColorSpaces =
new TheoryData<object, object, Type>()
{
{ new Bgra32(0, 0, 0), null, typeof(Bgra32) },
{ new CieLab(0f, 0f, 0f), null, typeof(CieLab) },
{ new CieXyz(380f, 380f, 380f), null, typeof(CieXyz) },
{ new Cmyk(0f, 0f, 0f, 0f), null, typeof(Cmyk) },
{ new Hsl(0f, 0f, 0f), null, typeof(Hsl) },
{ new Hsv(360f, 1f, 1f), null, typeof(Hsv) },
{ new YCbCr(0, 0, 0), null, typeof(YCbCr) },
};
public static readonly TheoryData<object, object, Type> NotEqualityDataDifferentObjects =
new TheoryData<object, object, Type>()
{
@ -115,16 +70,6 @@ namespace ImageSharp.Tests.Colors
{ new Rgba1010102(Vector4.One), new Bgra5551(Vector4.Zero), null },
};
public static readonly TheoryData<object, object, Type> NotEqualityDataDifferentObjectsColorSpaces =
new TheoryData<object, object, Type>()
{
// Valid objects of different types but not equal
{ new Bgra32(0, 0, 0), new CieLab(0f, 0f, 0f), null },
{ new CieXyz(380f, 380f, 380f), new Cmyk(0f, 0f, 0f, 0f), null },
{ new Hsl(0f, 0f, 0f), new Hsv(360f, 1f, 1f), null },
{ new YCbCr(0, 0, 0), new Hsv(360f, 1f, 1f), null },
};
public static readonly TheoryData<object, object, Type> NotEqualityData =
new TheoryData<object, object, Type>()
{
@ -149,92 +94,8 @@ namespace ImageSharp.Tests.Colors
{ new Short4(Vector4.One * 0x7FFF), new Short4(Vector4.Zero), typeof(Short4) },
};
public static readonly TheoryData<object, object, Type> NotEqualityDataColorSpaces =
new TheoryData<object, object, Type>()
{
{ new Bgra32(0, 0, 0), new Bgra32(0, 1, 0), typeof(Bgra32) },
{ new Bgra32(0, 0, 0, 0), new Bgra32(0, 1, 0, 0), typeof(Bgra32) },
{ new Bgra32(100, 100, 0, 0), new Bgra32(100, 0, 0, 0), typeof(Bgra32) },
{ new Bgra32(255, 255, 255), new Bgra32(255, 0, 255), typeof(Bgra32) },
{ new CieLab(0f, 0f, 0f), new CieLab(0f, 1f, 0f), typeof(CieLab) },
{ new CieLab(1f, 1f, 1f), new CieLab(1f, 0f, 1f), typeof(CieLab) },
{ new CieLab(0f, -100f, -100f), new CieLab(0f, 100f, -100f), typeof(CieLab) },
{ new CieLab(0f, 100f, -100f), new CieLab(0f, -100f, -100f), typeof(CieLab) },
{ new CieLab(0f, -100f, 100f), new CieLab(0f, 100f, 100f), typeof(CieLab) },
{ new CieLab(0f, -100f, 50f), new CieLab(0f, 100f, 20f), typeof(CieLab) },
{ new CieXyz(380f, 380f, 380f), new CieXyz(380f, 0f, 380f), typeof(CieXyz) },
{ new CieXyz(780f, 780f, 780f), new CieXyz(780f, 0f, 780f), typeof(CieXyz) },
{ new CieXyz(380f, 780f, 780f), new CieXyz(380f, 0f, 780f), typeof(CieXyz) },
{ new CieXyz(50f, 20f, 60f), new CieXyz(50f, 0f, 60f), typeof(CieXyz) },
{ new Cmyk(0f, 0f, 0f, 0f), new Cmyk(0f, 1f, 0f, 0f), typeof(Cmyk) },
{ new Cmyk(1f, 1f, 1f, 1f), new Cmyk(1f, 1f, 0f, 1f), typeof(Cmyk) },
{ new Cmyk(10f, 10f, 10f, 10f), new Cmyk(10f, 10f, 0f, 10f), typeof(Cmyk) },
{ new Cmyk(.4f, .5f, .1f, .2f), new Cmyk(.4f, .5f, 5f, .2f), typeof(Cmyk) },
{ new Hsl(0f, 0f, 0f), new Hsl(0f, 5f, 0f), typeof(Hsl) },
{ new Hsl(360f, 1f, 1f), new Hsl(360f, .5f, 1f), typeof(Hsl) },
{ new Hsl(100f, .5f, .1f), new Hsl(100f, 9f, .1f), typeof(Hsl) },
{ new Hsv(0f, 0f, 0f), new Hsv(0f, 1f, 0f), typeof(Hsv) },
{ new Hsv(360f, 1f, 1f), new Hsv(0f, 1f, 1f), typeof(Hsv) },
{ new Hsv(100f, .5f, .1f), new Hsv(2f, .5f, .1f), typeof(Hsv) },
{ new YCbCr(0, 0, 0), new YCbCr(0, 1, 0), typeof(YCbCr) },
{ new YCbCr(255, 255, 255), new YCbCr(255, 0, 255), typeof(YCbCr) },
{ new YCbCr(100, 100, 0), new YCbCr(100, 20, 0), typeof(YCbCr) },
};
public static readonly TheoryData<object, object, Type, float> AlmostEqualsData =
new TheoryData<object, object, Type, float>()
{
{ new CieLab(0f, 0f, 0f), new CieLab(0f, 0f, 0f), typeof(CieLab), 0f },
{ new CieLab(0f, 0f, 0f), new CieLab(0f, 0f, 0f), typeof(CieLab), .001f },
{ new CieLab(0f, 0f, 0f), new CieLab(0f, 0f, 0f), typeof(CieLab), .0001f },
{ new CieLab(0f, 0f, 0f), new CieLab(0f, 0f, 0f), typeof(CieLab), .0005f },
{ 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 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 },
{ new CieXyz(380f, 380f, 380f), new CieXyz(380f, 380f, 380.001f), typeof(CieXyz), .01f },
{ new Cmyk(0f, 0f, 0f, 0f), new Cmyk(0f, 0f, 0f, 0f), typeof(Cmyk), 0f },
{ new Cmyk(0f, 0f, 0f, 0f), new Cmyk(0.001f, 0f, 0f, 0f), typeof(Cmyk), .01f },
{ new Cmyk(0f, 0f, 0f, 0f), new Cmyk(0f, 0.001f, 0f, 0f), typeof(Cmyk), .01f },
{ new Cmyk(0f, 0f, 0f, 0f), new Cmyk(0f, 0f, 0.001f, 0f), typeof(Cmyk), .01f },
{ new Cmyk(0f, 0f, 0f, 0f), new Cmyk(0f, 0f, 0f, 0.001f), typeof(Cmyk), .01f },
{ new Hsl(0f, 0f, 0f), new Hsl(0f, 0f, 0f), typeof(Hsl), 0f },
{ new Hsl(0f, 0f, 0f), new Hsl(0.001f, 0f, 0f), typeof(Hsl), .01f },
{ new Hsl(0f, 0f, 0f), new Hsl(0f, 0.001f, 0f), typeof(Hsl), .01f },
{ new Hsl(0f, 0f, 0f), new Hsl(0f, 0f, 0.001f), typeof(Hsl), .01f },
{ new Hsv(360f, 1f, 1f), new Hsv(360f, 1f, 1f), typeof(Hsv), 0f },
{ new Hsv(0f, 0f, 0f), new Hsv(0f, 0f, 0f), typeof(Hsv), 0f },
{ new Hsv(0f, 0f, 0f), new Hsv(0.001f, 0f, 0f), typeof(Hsv), .01f },
{ new Hsv(0f, 0f, 0f), new Hsv(0f, 0.001f, 0f), typeof(Hsv), .01f },
{ new Hsv(0f, 0f, 0f), new Hsv(0f, 0f, 0.001f), typeof(Hsv), .01f },
};
public static readonly TheoryData<object, object, Type, float> AlmostNotEqualsData =
new TheoryData<object, object, Type, float>()
{
{ new CieLab(0f, 0f, 0f), new CieLab(0.1f, 0f, 0f), typeof(CieLab), .001f },
{ new CieLab(0f, 0f, 0f), new CieLab(0f, 0.1f, 0f), typeof(CieLab), .001f },
{ new CieLab(0f, 0f, 0f), new CieLab(0f, 0f, 0.1f), typeof(CieLab), .001f },
{ new CieXyz(380f, 380f, 380f), new CieXyz(380.1f, 380f, 380f), typeof(CieXyz), .001f },
{ new CieXyz(380f, 380f, 380f), new CieXyz(380f, 380.1f, 380f), typeof(CieXyz), .001f },
{ new CieXyz(380f, 380f, 380f), new CieXyz(380f, 380f, 380.1f), typeof(CieXyz), .001f },
{ new Cmyk(0f, 0f, 0f, 0f), new Cmyk(0.1f, 0f, 0f, 0f), typeof(Cmyk), .001f },
{ new Cmyk(0f, 0f, 0f, 0f), new Cmyk(0f, 0.1f, 0f, 0f), typeof(Cmyk), .001f },
{ new Cmyk(0f, 0f, 0f, 0f), new Cmyk(0f, 0f, 0.1f, 0f), typeof(Cmyk), .001f },
{ new Cmyk(0f, 0f, 0f, 0f), new Cmyk(0f, 0f, 0f, 0.1f), typeof(Cmyk), .001f },
{ new Hsl(0f, 0f, 0f), new Hsl(0.1f, 0f, 0f), typeof(Hsl), .001f },
{ new Hsl(0f, 0f, 0f), new Hsl(0f, 0.1f, 0f), typeof(Hsl), .001f },
{ new Hsl(0f, 0f, 0f), new Hsl(0f, 0f, 0.1f), typeof(Hsl), .001f },
{ new Hsv(0f, 0f, 0f), new Hsv(0.1f, 0f, 0f), typeof(Hsv), .001f },
{ new Hsv(0f, 0f, 0f), new Hsv(0f, 0.1f, 0f), typeof(Hsv), .001f },
{ new Hsv(0f, 0f, 0f), new Hsv(0f, 0f, 0.1f), typeof(Hsv), .001f },
};
[Theory]
[MemberData(nameof(EqualityData))]
[MemberData(nameof(EqualityDataColorSpaces))]
public void Equality(object first, object second, Type type)
{
// Act
@ -246,11 +107,8 @@ namespace ImageSharp.Tests.Colors
[Theory]
[MemberData(nameof(NotEqualityDataNulls))]
[MemberData(nameof(NotEqualityDataNullsColorSpaces))]
[MemberData(nameof(NotEqualityDataDifferentObjects))]
[MemberData(nameof(NotEqualityDataDifferentObjectsColorSpaces))]
[MemberData(nameof(NotEqualityData))]
[MemberData(nameof(NotEqualityDataColorSpaces))]
public void NotEquality(object first, object second, Type type)
{
// Act
@ -262,7 +120,6 @@ namespace ImageSharp.Tests.Colors
[Theory]
[MemberData(nameof(EqualityData))]
[MemberData(nameof(EqualityDataColorSpaces))]
public void HashCodeEqual(object first, object second, Type type)
{
// Act
@ -274,7 +131,6 @@ namespace ImageSharp.Tests.Colors
[Theory]
[MemberData(nameof(NotEqualityDataDifferentObjects))]
[MemberData(nameof(NotEqualityDataDifferentObjectsColorSpaces))]
public void HashCodeNotEqual(object first, object second, Type type)
{
// Act
@ -286,13 +142,12 @@ namespace ImageSharp.Tests.Colors
[Theory]
[MemberData(nameof(EqualityData))]
[MemberData(nameof(EqualityDataColorSpaces))]
public void EqualityObject(object first, object second, Type type)
{
// Arrange
// Cast to the known object types, this is so that we can hit the
// equality operator on the concrete type, otherwise it goes to the
// default "object" one :)
// Arrange
// Cast to the known object types, this is so that we can hit the
// equality operator on the concrete type, otherwise it goes to the
// default "object" one :)
dynamic firstObject = Convert.ChangeType(first, type);
dynamic secondObject = Convert.ChangeType(second, type);
@ -305,13 +160,12 @@ namespace ImageSharp.Tests.Colors
[Theory]
[MemberData(nameof(NotEqualityData))]
[MemberData(nameof(NotEqualityDataColorSpaces))]
public void NotEqualityObject(object first, object second, Type type)
{
// Arrange
// Cast to the known object types, this is so that we can hit the
// equality operator on the concrete type, otherwise it goes to the
// default "object" one :)
// Arrange
// Cast to the known object types, this is so that we can hit the
// equality operator on the concrete type, otherwise it goes to the
// default "object" one :)
dynamic firstObject = Convert.ChangeType(first, type);
dynamic secondObject = Convert.ChangeType(second, type);
@ -324,13 +178,12 @@ namespace ImageSharp.Tests.Colors
[Theory]
[MemberData(nameof(EqualityData))]
[MemberData(nameof(EqualityDataColorSpaces))]
public void EqualityOperator(object first, object second, Type type)
{
// Arrange
// Cast to the known object types, this is so that we can hit the
// equality operator on the concrete type, otherwise it goes to the
// default "object" one :)
// Arrange
// Cast to the known object types, this is so that we can hit the
// equality operator on the concrete type, otherwise it goes to the
// default "object" one :)
dynamic firstObject = Convert.ChangeType(first, type);
dynamic secondObject = Convert.ChangeType(second, type);
@ -343,13 +196,12 @@ namespace ImageSharp.Tests.Colors
[Theory]
[MemberData(nameof(NotEqualityData))]
[MemberData(nameof(NotEqualityDataColorSpaces))]
public void NotEqualityOperator(object first, object second, Type type)
{
// Arrange
// Cast to the known object types, this is so that we can hit the
// equality operator on the concrete type, otherwise it goes to the
// default "object" one :)
// Arrange
// Cast to the known object types, this is so that we can hit the
// equality operator on the concrete type, otherwise it goes to the
// default "object" one :)
dynamic firstObject = Convert.ChangeType(first, type);
dynamic secondObject = Convert.ChangeType(second, type);
@ -359,41 +211,5 @@ namespace ImageSharp.Tests.Colors
// Assert
Assert.True(notEqual);
}
[Theory]
[MemberData(nameof(AlmostEqualsData))]
public void AlmostEquals(object first, object second, Type type, float precision)
{
// Arrange
// Cast to the known object types, this is so that we can hit the
// equality operator on the concrete type, otherwise it goes to the
// default "object" one :)
dynamic firstObject = Convert.ChangeType(first, type);
dynamic secondObject = Convert.ChangeType(second, type);
// Act
dynamic almostEqual = firstObject.AlmostEquals(secondObject, precision);
// Assert
Assert.True(almostEqual);
}
[Theory]
[MemberData(nameof(AlmostNotEqualsData))]
public void AlmostNotEquals(object first, object second, Type type, float precision)
{
// Arrange
// Cast to the known object types, this is so that we can hit the
// equality operator on the concrete type, otherwise it goes to the
// default "object" one :)
dynamic firstObject = Convert.ChangeType(first, type);
dynamic secondObject = Convert.ChangeType(second, type);
// Act
dynamic almostEqual = firstObject.AlmostEquals(secondObject, precision);
// Assert
Assert.False(almostEqual);
}
}
}

Loading…
Cancel
Save