From 96d27c46eae034f07babf637c45d283f783435dd Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Thu, 12 Jul 2018 19:44:18 +1000 Subject: [PATCH] Simplify structs, 5% perf increase. --- src/ImageSharp/ColorSpaces/CieLab.cs | 126 ++--- src/ImageSharp/ColorSpaces/CieLch.cs | 122 ++--- src/ImageSharp/ColorSpaces/CieLchuv.cs | 127 ++--- src/ImageSharp/ColorSpaces/CieLuv.cs | 129 ++--- .../CieXyChromaticityCoordinates.cs | 92 +--- src/ImageSharp/ColorSpaces/CieXyy.cs | 108 ++-- src/ImageSharp/ColorSpaces/CieXyz.cs | 108 ++-- src/ImageSharp/ColorSpaces/Cmyk.cs | 126 ++--- .../Implementation/CieXyzAndLmsConverter.cs | 4 +- .../CieXyzToLinearRgbConverter.cs | 2 +- .../Implementation/CmykAndRgbConverter.cs | 2 +- .../LinearRgbAndCieXyzConverterBase.cs | 26 +- .../LinearRgbToCieXyzConverter.cs | 2 +- .../Implementation/LinearRgbToRgbConverter.cs | 2 +- .../Implementation/RgbToLinearRgbConverter.cs | 2 +- .../Implementation/YCbCrAndRgbConverter.cs | 2 +- .../Conversion/VonKriesChromaticAdaptation.cs | 4 +- src/ImageSharp/ColorSpaces/Hsl.cs | 104 ++-- src/ImageSharp/ColorSpaces/Hsv.cs | 107 ++-- src/ImageSharp/ColorSpaces/HunterLab.cs | 120 ++--- src/ImageSharp/ColorSpaces/IColorVector.cs | 18 - .../ColorSpaces/IRgbWorkingSpace.cs | 31 -- src/ImageSharp/ColorSpaces/LinearRgb.cs | 125 ++--- src/ImageSharp/ColorSpaces/Lms.cs | 119 ++--- src/ImageSharp/ColorSpaces/Rgb.cs | 126 ++--- src/ImageSharp/ColorSpaces/YCbCr.cs | 108 ++-- .../Colorspaces/ColorSpaceEqualityTests.cs | 498 +++++++++--------- 27 files changed, 861 insertions(+), 1479 deletions(-) delete mode 100644 src/ImageSharp/ColorSpaces/IColorVector.cs delete mode 100644 src/ImageSharp/ColorSpaces/IRgbWorkingSpace.cs diff --git a/src/ImageSharp/ColorSpaces/CieLab.cs b/src/ImageSharp/ColorSpaces/CieLab.cs index 82975d933..3b2815dd7 100644 --- a/src/ImageSharp/ColorSpaces/CieLab.cs +++ b/src/ImageSharp/ColorSpaces/CieLab.cs @@ -2,7 +2,6 @@ // Licensed under the Apache License, Version 2.0. using System; -using System.ComponentModel; using System.Numerics; using System.Runtime.CompilerServices; @@ -12,7 +11,7 @@ namespace SixLabors.ImageSharp.ColorSpaces /// Represents a CIE L*a*b* 1976 color. /// /// - internal readonly struct CieLab : IColorVector, IEquatable, IAlmostEquatable + internal readonly struct CieLab : IEquatable { /// /// D50 standard illuminant. @@ -21,9 +20,27 @@ namespace SixLabors.ImageSharp.ColorSpaces public static readonly CieXyz DefaultWhitePoint = Illuminants.D50; /// - /// The backing vector for SIMD support. + /// Gets the lightness dimension. + /// A value ranging between 0 (black), 100 (diffuse white) or higher (specular white). + /// + public readonly float L; + + /// + /// Gets the a color component. + /// A value ranging from -100 to 100. Negative is green, positive magenta. + /// + public readonly float A; + + /// + /// Gets the b color component. + /// A value ranging from -100 to 100. Negative is blue, positive is yellow + /// + public readonly float B; + + /// + /// Gets the reference white point of this color /// - private readonly Vector3 backingVector; + public readonly CieXyz WhitePoint; /// /// Initializes a new instance of the struct. @@ -34,7 +51,7 @@ namespace SixLabors.ImageSharp.ColorSpaces /// Uses as white point. [MethodImpl(MethodImplOptions.AggressiveInlining)] public CieLab(float l, float a, float b) - : this(new Vector3(l, a, b), DefaultWhitePoint) + : this(l, a, b, DefaultWhitePoint) { } @@ -47,8 +64,11 @@ namespace SixLabors.ImageSharp.ColorSpaces /// The reference white point. [MethodImpl(MethodImplOptions.AggressiveInlining)] public CieLab(float l, float a, float b, CieXyz whitePoint) - : this(new Vector3(l, a, b), whitePoint) { + this.L = l; + this.A = a; + this.B = b; + this.WhitePoint = whitePoint; } /// @@ -71,88 +91,41 @@ namespace SixLabors.ImageSharp.ColorSpaces public CieLab(Vector3 vector, CieXyz whitePoint) : this() { - this.backingVector = vector; + this.L = vector.X; + this.A = vector.Y; + this.B = vector.Z; this.WhitePoint = whitePoint; } - /// - /// Gets the reference white point of this color - /// - public CieXyz WhitePoint { get; } - - /// - /// Gets the lightness dimension. - /// A value ranging between 0 (black), 100 (diffuse white) or higher (specular white). - /// - public float L - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => this.backingVector.X; - } - - /// - /// Gets the a color component. - /// A value ranging from -100 to 100. Negative is green, positive magenta. - /// - public float A - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => this.backingVector.Y; - } - - /// - /// Gets the b color component. - /// A value ranging from -100 to 100. Negative is blue, positive is yellow - /// - public float B - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => this.backingVector.Z; - } - - /// - public Vector3 Vector => this.backingVector; - /// /// Compares two objects for equality. /// - /// - /// The on the left side of the operand. - /// - /// - /// The on the right side of the operand. - /// + /// The on the left side of the operand. + /// The on the right side of the operand. /// /// True if the current left is equal to the parameter; otherwise, false. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator ==(CieLab left, CieLab right) - { - return left.Equals(right); - } + public static bool operator ==(CieLab left, CieLab right) => left.Equals(right); /// /// Compares two objects for inequality /// - /// - /// The on the left side of the operand. - /// - /// - /// The on the right side of the operand. - /// + /// The on the left side of the operand. + /// The on the right side of the operand. /// /// True if the current left is unequal to the parameter; otherwise, false. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator !=(CieLab left, CieLab right) - { - return !left.Equals(right); - } + public static bool operator !=(CieLab left, CieLab right) => !left.Equals(right); /// public override int GetHashCode() { - return HashHelpers.Combine(this.WhitePoint.GetHashCode(), this.backingVector.GetHashCode()); + int hash = this.L.GetHashCode(); + hash = HashHelpers.Combine(hash, this.A.GetHashCode()); + hash = HashHelpers.Combine(hash, this.B.GetHashCode()); + return HashHelpers.Combine(hash, this.WhitePoint.GetHashCode()); } /// @@ -164,29 +137,16 @@ namespace SixLabors.ImageSharp.ColorSpaces } /// - public override bool Equals(object obj) - { - return obj is CieLab other && this.Equals(other); - } + public override bool Equals(object obj) => obj is CieLab other && this.Equals(other); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool Equals(CieLab other) { - return this.backingVector.Equals(other.backingVector) + return this.L.Equals(other.L) + && this.A.Equals(other.A) + && this.B.Equals(other.B) && this.WhitePoint.Equals(other.WhitePoint); } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool AlmostEquals(CieLab other, float precision) - { - var result = Vector3.Abs(this.backingVector - other.backingVector); - - return this.WhitePoint.Equals(other.WhitePoint) - && result.X <= precision - && result.Y <= precision - && result.Z <= precision; - } } } \ No newline at end of file diff --git a/src/ImageSharp/ColorSpaces/CieLch.cs b/src/ImageSharp/ColorSpaces/CieLch.cs index 67a9956bd..eea9e24a3 100644 --- a/src/ImageSharp/ColorSpaces/CieLch.cs +++ b/src/ImageSharp/ColorSpaces/CieLch.cs @@ -2,7 +2,6 @@ // Licensed under the Apache License, Version 2.0. using System; -using System.ComponentModel; using System.Numerics; using System.Runtime.CompilerServices; @@ -12,7 +11,7 @@ namespace SixLabors.ImageSharp.ColorSpaces /// Represents the CIE L*C*h°, cylindrical form of the CIE L*a*b* 1976 color. /// /// - internal readonly struct CieLch : IColorVector, IEquatable, IAlmostEquatable + internal readonly struct CieLch : IEquatable { /// /// D50 standard illuminant. @@ -21,9 +20,27 @@ namespace SixLabors.ImageSharp.ColorSpaces public static readonly CieXyz DefaultWhitePoint = Illuminants.D50; /// - /// The backing vector for SIMD support. + /// Gets the lightness dimension. + /// A value ranging between 0 (black), 100 (diffuse white) or higher (specular white). + /// + public readonly float L; + + /// + /// Gets the a chroma component. + /// A value ranging from 0 to 100. /// - private readonly Vector3 backingVector; + public readonly float C; + + /// + /// Gets the h° hue component in degrees. + /// A value ranging from 0 to 360. + /// + public readonly float H; + + /// + /// Gets the reference white point of this color + /// + public readonly CieXyz WhitePoint; /// /// Initializes a new instance of the struct. @@ -34,7 +51,7 @@ namespace SixLabors.ImageSharp.ColorSpaces /// Uses as white point. [MethodImpl(MethodImplOptions.AggressiveInlining)] public CieLch(float l, float c, float h) - : this(new Vector3(l, c, h), DefaultWhitePoint) + : this(l, c, h, DefaultWhitePoint) { } @@ -47,8 +64,11 @@ namespace SixLabors.ImageSharp.ColorSpaces /// The reference white point. [MethodImpl(MethodImplOptions.AggressiveInlining)] public CieLch(float l, float c, float h, CieXyz whitePoint) - : this(new Vector3(l, c, h), whitePoint) { + this.L = l; + this.C = c; + this.H = h; + this.WhitePoint = whitePoint; } /// @@ -69,59 +89,18 @@ namespace SixLabors.ImageSharp.ColorSpaces /// The reference white point. [MethodImpl(MethodImplOptions.AggressiveInlining)] public CieLch(Vector3 vector, CieXyz whitePoint) - : this() { - this.backingVector = vector; + this.L = vector.X; + this.C = vector.Y; + this.H = vector.Z; this.WhitePoint = whitePoint; } - /// - /// Gets the reference white point of this color - /// - public CieXyz WhitePoint { get; } - - /// - /// Gets the lightness dimension. - /// A value ranging between 0 (black), 100 (diffuse white) or higher (specular white). - /// - public float L - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => this.backingVector.X; - } - - /// - /// Gets the a chroma component. - /// A value ranging from 0 to 100. - /// - public float C - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => this.backingVector.Y; - } - - /// - /// Gets the h° hue component in degrees. - /// A value ranging from 0 to 360. - /// - public float H - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => this.backingVector.Z; - } - - /// - public Vector3 Vector => this.backingVector; - /// /// Compares two objects for equality. /// - /// - /// The on the left side of the operand. - /// - /// - /// The on the right side of the operand. - /// + /// The on the left side of the operand. + /// The on the right side of the operand. /// /// True if the current left is equal to the parameter; otherwise, false. /// @@ -134,25 +113,21 @@ namespace SixLabors.ImageSharp.ColorSpaces /// /// Compares two objects for inequality /// - /// - /// The on the left side of the operand. - /// - /// - /// The on the right side of the operand. - /// + /// The on the left side of the operand. + /// The on the right side of the operand. /// /// True if the current left is unequal to the parameter; otherwise, false. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator !=(CieLch left, CieLch right) - { - return !left.Equals(right); - } + public static bool operator !=(CieLch left, CieLch right) => !left.Equals(right); /// public override int GetHashCode() { - return HashHelpers.Combine(this.WhitePoint.GetHashCode(), this.backingVector.GetHashCode()); + int hash = this.L.GetHashCode(); + hash = HashHelpers.Combine(hash, this.C.GetHashCode()); + hash = HashHelpers.Combine(hash, this.H.GetHashCode()); + return HashHelpers.Combine(hash, this.WhitePoint.GetHashCode()); } /// @@ -165,31 +140,18 @@ namespace SixLabors.ImageSharp.ColorSpaces /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public override bool Equals(object obj) - { - return obj is CieLch other && this.Equals(other); - } + public override bool Equals(object obj) => obj is CieLch other && this.Equals(other); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool Equals(CieLch other) { - return this.backingVector.Equals(other.backingVector) + return this.L.Equals(other.L) + && this.C.Equals(other.C) + && this.H.Equals(other.H) && this.WhitePoint.Equals(other.WhitePoint); } - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool AlmostEquals(CieLch other, float precision) - { - var result = Vector3.Abs(this.backingVector - other.backingVector); - - return this.WhitePoint.Equals(other.WhitePoint) - && result.X <= precision - && result.Y <= precision - && result.Z <= precision; - } - /// /// Computes the saturation of the color (chroma normalized by lightness) /// diff --git a/src/ImageSharp/ColorSpaces/CieLchuv.cs b/src/ImageSharp/ColorSpaces/CieLchuv.cs index 0b4c7a903..6538ccbbc 100644 --- a/src/ImageSharp/ColorSpaces/CieLchuv.cs +++ b/src/ImageSharp/ColorSpaces/CieLchuv.cs @@ -2,7 +2,6 @@ // Licensed under the Apache License, Version 2.0. using System; -using System.ComponentModel; using System.Numerics; using System.Runtime.CompilerServices; @@ -12,7 +11,7 @@ namespace SixLabors.ImageSharp.ColorSpaces /// Represents the CIE L*C*h°, cylindrical form of the CIE L*u*v* 1976 color. /// /// - internal readonly struct CieLchuv : IColorVector, IEquatable, IAlmostEquatable + internal readonly struct CieLchuv : IEquatable { /// /// D50 standard illuminant. @@ -21,9 +20,27 @@ namespace SixLabors.ImageSharp.ColorSpaces public static readonly CieXyz DefaultWhitePoint = Illuminants.D65; /// - /// The backing vector for SIMD support. + /// Gets the lightness dimension. + /// A value ranging between 0 (black), 100 (diffuse white) or higher (specular white). + /// + public readonly float L; + + /// + /// Gets the a chroma component. + /// A value ranging from 0 to 100. + /// + public readonly float C; + + /// + /// Gets the h° hue component in degrees. + /// A value ranging from 0 to 360. + /// + public readonly float H; + + /// + /// Gets the reference white point of this color /// - private readonly Vector3 backingVector; + public readonly CieXyz WhitePoint; /// /// Initializes a new instance of the struct. @@ -34,7 +51,7 @@ namespace SixLabors.ImageSharp.ColorSpaces /// Uses as white point. [MethodImpl(MethodImplOptions.AggressiveInlining)] public CieLchuv(float l, float c, float h) - : this(new Vector3(l, c, h), DefaultWhitePoint) + : this(l, c, h, DefaultWhitePoint) { } @@ -47,8 +64,11 @@ namespace SixLabors.ImageSharp.ColorSpaces /// The reference white point. [MethodImpl(MethodImplOptions.AggressiveInlining)] public CieLchuv(float l, float c, float h, CieXyz whitePoint) - : this(new Vector3(l, c, h), whitePoint) { + this.L = l; + this.C = c; + this.H = h; + this.WhitePoint = whitePoint; } /// @@ -71,87 +91,39 @@ namespace SixLabors.ImageSharp.ColorSpaces public CieLchuv(Vector3 vector, CieXyz whitePoint) : this() { - this.backingVector = vector; + this.L = vector.X; + this.C = vector.Y; + this.H = vector.Z; this.WhitePoint = whitePoint; } - /// - /// Gets the reference white point of this color - /// - public CieXyz WhitePoint { get; } - - /// - /// Gets the lightness dimension. - /// A value ranging between 0 (black), 100 (diffuse white) or higher (specular white). - /// - public float L - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => this.backingVector.X; - } - - /// - /// Gets the a chroma component. - /// A value ranging from 0 to 100. - /// - public float C - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => this.backingVector.Y; - } - - /// - /// Gets the h° hue component in degrees. - /// A value ranging from 0 to 360. - /// - public float H - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => this.backingVector.Z; - } - - /// - public Vector3 Vector => this.backingVector; - /// /// Compares two objects for equality. /// - /// - /// The on the left side of the operand. - /// - /// - /// The on the right side of the operand. - /// + /// The on the left side of the operand. + /// The on the right side of the operand. /// /// True if the current left is equal to the parameter; otherwise, false. /// - public static bool operator ==(CieLchuv left, CieLchuv right) - { - return left.Equals(right); - } + public static bool operator ==(CieLchuv left, CieLchuv right) => left.Equals(right); /// /// Compares two objects for inequality /// - /// - /// The on the left side of the operand. - /// - /// - /// The on the right side of the operand. - /// + /// The on the left side of the operand. + /// The on the right side of the operand. /// /// True if the current left is unequal to the parameter; otherwise, false. /// - public static bool operator !=(CieLchuv left, CieLchuv right) - { - return !left.Equals(right); - } + public static bool operator !=(CieLchuv left, CieLchuv right) => !left.Equals(right); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] public override int GetHashCode() { - return HashHelpers.Combine(this.WhitePoint.GetHashCode(), this.backingVector.GetHashCode()); + int hash = this.L.GetHashCode(); + hash = HashHelpers.Combine(hash, this.C.GetHashCode()); + hash = HashHelpers.Combine(hash, this.H.GetHashCode()); + return HashHelpers.Combine(hash, this.WhitePoint.GetHashCode()); } /// @@ -163,31 +135,18 @@ namespace SixLabors.ImageSharp.ColorSpaces } /// - public override bool Equals(object obj) - { - return obj is CieLchuv other && this.Equals(other); - } + public override bool Equals(object obj) => obj is CieLchuv other && this.Equals(other); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool Equals(CieLchuv other) { - return this.backingVector.Equals(other.backingVector) + return this.L.Equals(other.L) + && this.C.Equals(other.C) + && this.H.Equals(other.H) && this.WhitePoint.Equals(other.WhitePoint); } - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool AlmostEquals(CieLchuv other, float precision) - { - var result = Vector3.Abs(this.backingVector - other.backingVector); - - return this.WhitePoint.Equals(other.WhitePoint) - && result.X <= precision - && result.Y <= precision - && result.Z <= precision; - } - /// /// Computes the saturation of the color (chroma normalized by lightness) /// diff --git a/src/ImageSharp/ColorSpaces/CieLuv.cs b/src/ImageSharp/ColorSpaces/CieLuv.cs index dbc3b6dee..970362eae 100644 --- a/src/ImageSharp/ColorSpaces/CieLuv.cs +++ b/src/ImageSharp/ColorSpaces/CieLuv.cs @@ -2,7 +2,6 @@ // Licensed under the Apache License, Version 2.0. using System; -using System.ComponentModel; using System.Numerics; using System.Runtime.CompilerServices; @@ -14,7 +13,7 @@ namespace SixLabors.ImageSharp.ColorSpaces /// attempted perceptual uniformity /// /// - internal readonly struct CieLuv : IColorVector, IEquatable, IAlmostEquatable + internal readonly struct CieLuv : IEquatable { /// /// D65 standard illuminant. @@ -23,9 +22,27 @@ namespace SixLabors.ImageSharp.ColorSpaces public static readonly CieXyz DefaultWhitePoint = Illuminants.D65; /// - /// The backing vector for SIMD support. + /// Gets the lightness dimension + /// A value usually ranging between 0 and 100. + /// + public readonly float L; + + /// + /// Gets the blue-yellow chromaticity coordinate of the given whitepoint. + /// A value usually ranging between -100 and 100. + /// + public readonly float U; + + /// + /// Gets the red-green chromaticity coordinate of the given whitepoint. + /// A value usually ranging between -100 and 100. + /// + public readonly float V; + + /// + /// Gets the reference white point of this color /// - private readonly Vector3 backingVector; + public readonly CieXyz WhitePoint; /// /// Initializes a new instance of the struct. @@ -36,7 +53,7 @@ namespace SixLabors.ImageSharp.ColorSpaces /// Uses as white point. [MethodImpl(MethodImplOptions.AggressiveInlining)] public CieLuv(float l, float u, float v) - : this(new Vector3(l, u, v), DefaultWhitePoint) + : this(l, u, v, DefaultWhitePoint) { } @@ -49,8 +66,11 @@ namespace SixLabors.ImageSharp.ColorSpaces /// The reference white point. [MethodImpl(MethodImplOptions.AggressiveInlining)] public CieLuv(float l, float u, float v, CieXyz whitePoint) - : this(new Vector3(l, u, v), whitePoint) { + this.L = l; + this.U = u; + this.V = v; + this.WhitePoint = whitePoint; } /// @@ -71,90 +91,42 @@ namespace SixLabors.ImageSharp.ColorSpaces /// The reference white point. [MethodImpl(MethodImplOptions.AggressiveInlining)] public CieLuv(Vector3 vector, CieXyz whitePoint) - : this() { - this.backingVector = vector; + this.L = vector.X; + this.U = vector.Y; + this.V = vector.Z; this.WhitePoint = whitePoint; } - /// - /// Gets the reference white point of this color - /// - public CieXyz WhitePoint { get; } - - /// - /// Gets the lightness dimension - /// A value usually ranging between 0 and 100. - /// - public float L - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => this.backingVector.X; - } - - /// - /// Gets the blue-yellow chromaticity coordinate of the given whitepoint. - /// A value usually ranging between -100 and 100. - /// - public float U - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => this.backingVector.Y; - } - - /// - /// Gets the red-green chromaticity coordinate of the given whitepoint. - /// A value usually ranging between -100 and 100. - /// - public float V - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => this.backingVector.Z; - } - - /// - public Vector3 Vector => this.backingVector; - /// /// Compares two objects for equality. /// - /// - /// The on the left side of the operand. - /// - /// - /// The on the right side of the operand. - /// + /// The on the left side of the operand. + /// The on the right side of the operand. /// /// True if the current left is equal to the parameter; otherwise, false. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator ==(CieLuv left, CieLuv right) - { - return left.Equals(right); - } + public static bool operator ==(CieLuv left, CieLuv right) => left.Equals(right); /// /// Compares two objects for inequality. /// - /// - /// The on the left side of the operand. - /// - /// - /// The on the right side of the operand. - /// + /// The on the left side of the operand. + /// The on the right side of the operand. /// /// True if the current left is unequal to the parameter; otherwise, false. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator !=(CieLuv left, CieLuv right) - { - return !left.Equals(right); - } + public static bool operator !=(CieLuv left, CieLuv right) => !left.Equals(right); /// public override int GetHashCode() { - return HashHelpers.Combine(this.WhitePoint.GetHashCode(), this.backingVector.GetHashCode()); + int hash = this.L.GetHashCode(); + hash = HashHelpers.Combine(hash, this.U.GetHashCode()); + hash = HashHelpers.Combine(hash, this.V.GetHashCode()); + return HashHelpers.Combine(hash, this.WhitePoint.GetHashCode()); } /// @@ -166,29 +138,16 @@ namespace SixLabors.ImageSharp.ColorSpaces } /// - public override bool Equals(object obj) - { - return obj is CieLuv other && this.Equals(other); - } + public override bool Equals(object obj) => obj is CieLuv other && this.Equals(other); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool Equals(CieLuv other) { - return this.backingVector.Equals(other.backingVector) - && this.WhitePoint.Equals(other.WhitePoint); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool AlmostEquals(CieLuv other, float precision) - { - var result = Vector3.Abs(this.backingVector - other.backingVector); - - return this.WhitePoint.Equals(other.WhitePoint) - && result.X <= precision - && result.Y <= precision - && result.Z <= precision; + return this.L.Equals(other.L) + && this.U.Equals(other.U) + && this.V.Equals(other.V) + && this.WhitePoint.Equals(other.WhitePoint); } } } \ No newline at end of file diff --git a/src/ImageSharp/ColorSpaces/CieXyChromaticityCoordinates.cs b/src/ImageSharp/ColorSpaces/CieXyChromaticityCoordinates.cs index 4f4f95147..de6725f76 100644 --- a/src/ImageSharp/ColorSpaces/CieXyChromaticityCoordinates.cs +++ b/src/ImageSharp/ColorSpaces/CieXyChromaticityCoordinates.cs @@ -2,8 +2,6 @@ // Licensed under the Apache License, Version 2.0. using System; -using System.ComponentModel; -using System.Numerics; using System.Runtime.CompilerServices; // ReSharper disable CompareOfFloatsByEqualityOperator @@ -12,45 +10,15 @@ namespace SixLabors.ImageSharp.ColorSpaces /// /// Represents the coordinates of CIEXY chromaticity space /// - internal readonly struct CieXyChromaticityCoordinates : IEquatable, IAlmostEquatable + internal readonly struct CieXyChromaticityCoordinates : IEquatable { - /// - /// The backing vector for SIMD support. - /// - private readonly Vector2 backingVector; - - /// - /// Initializes a new instance of the struct. - /// - /// Chromaticity coordinate x (usually from 0 to 1) - /// Chromaticity coordinate y (usually from 0 to 1) - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public CieXyChromaticityCoordinates(float x, float y) - : this(new Vector2(x, y)) - { - } - - /// - /// Initializes a new instance of the struct. - /// - /// The vector containing the XY Chromaticity coordinates - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public CieXyChromaticityCoordinates(Vector2 vector) - { - this.backingVector = vector; - } - /// /// Gets the chromaticity X-coordinate. /// /// /// Ranges usually from 0 to 1. /// - public float X - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => this.backingVector.X; - } + public readonly float X; /// /// Gets the chromaticity Y-coordinate @@ -58,21 +26,25 @@ namespace SixLabors.ImageSharp.ColorSpaces /// /// Ranges usually from 0 to 1. /// - public float Y + public readonly float Y; + + /// + /// Initializes a new instance of the struct. + /// + /// Chromaticity coordinate x (usually from 0 to 1) + /// Chromaticity coordinate y (usually from 0 to 1) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public CieXyChromaticityCoordinates(float x, float y) { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => this.backingVector.Y; + this.X = x; + this.Y = y; } /// /// Compares two objects for equality. /// - /// - /// The on the left side of the operand. - /// - /// - /// The on the right side of the operand. - /// + /// The on the left side of the operand. + /// The on the right side of the operand. /// /// True if the current left is equal to the parameter; otherwise, false. /// @@ -85,12 +57,8 @@ namespace SixLabors.ImageSharp.ColorSpaces /// /// Compares two objects for inequality /// - /// - /// The on the left side of the operand. - /// - /// - /// The on the right side of the operand. - /// + /// The on the left side of the operand. + /// The on the right side of the operand. /// /// True if the current left is unequal to the parameter; otherwise, false. /// @@ -102,10 +70,7 @@ namespace SixLabors.ImageSharp.ColorSpaces /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public override int GetHashCode() - { - return this.backingVector.GetHashCode(); - } + public override int GetHashCode() => HashHelpers.Combine(this.X.GetHashCode(), this.Y.GetHashCode()); /// public override string ToString() @@ -116,27 +81,10 @@ namespace SixLabors.ImageSharp.ColorSpaces } /// - public override bool Equals(object obj) - { - return obj is CieXyChromaticityCoordinates other && this.Equals(other); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Equals(CieXyChromaticityCoordinates other) - { - // The memberwise comparison here is a workaround for https://github.com/dotnet/coreclr/issues/16443 - return this.X == other.X && this.Y == other.Y; - } + public override bool Equals(object obj) => obj is CieXyChromaticityCoordinates other && this.Equals(other); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool AlmostEquals(CieXyChromaticityCoordinates other, float precision) - { - var result = Vector2.Abs(this.backingVector - other.backingVector); - - return result.X <= precision - && result.Y <= precision; - } + public bool Equals(CieXyChromaticityCoordinates other) => this.X.Equals(other.X) && this.Y.Equals(other.Y); } } \ No newline at end of file diff --git a/src/ImageSharp/ColorSpaces/CieXyy.cs b/src/ImageSharp/ColorSpaces/CieXyy.cs index ac1a4532c..976454a31 100644 --- a/src/ImageSharp/ColorSpaces/CieXyy.cs +++ b/src/ImageSharp/ColorSpaces/CieXyy.cs @@ -2,7 +2,6 @@ // Licensed under the Apache License, Version 2.0. using System; -using System.ComponentModel; using System.Numerics; using System.Runtime.CompilerServices; @@ -12,12 +11,25 @@ namespace SixLabors.ImageSharp.ColorSpaces /// Represents an CIE xyY 1931 color /// /// - internal readonly struct CieXyy : IColorVector, IEquatable, IAlmostEquatable + internal readonly struct CieXyy : IEquatable { /// - /// The backing vector for SIMD support. + /// Gets the X chrominance component. + /// A value usually ranging between 0 and 1. + /// + public readonly float X; + + /// + /// Gets the Y chrominance component. + /// A value usually ranging between 0 and 1. + /// + public readonly float Y; + + /// + /// Gets the Y luminance component. + /// A value usually ranging between 0 and 1. /// - private readonly Vector3 backingVector; + public readonly float Yl; /// /// Initializes a new instance of the struct. @@ -27,8 +39,11 @@ namespace SixLabors.ImageSharp.ColorSpaces /// The y luminance component. [MethodImpl(MethodImplOptions.AggressiveInlining)] public CieXyy(float x, float y, float yl) - : this(new Vector3(x, y, yl)) { + // Not clamping as documentation about this space seems to indicate "usual" ranges + this.X = x; + this.Y = y; + this.Yl = yl; } /// @@ -40,83 +55,39 @@ namespace SixLabors.ImageSharp.ColorSpaces : this() { // Not clamping as documentation about this space seems to indicate "usual" ranges - this.backingVector = vector; - } - - /// - /// Gets the X chrominance component. - /// A value usually ranging between 0 and 1. - /// - public float X - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => this.backingVector.X; - } - - /// - /// Gets the Y chrominance component. - /// A value usually ranging between 0 and 1. - /// - public float Y - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => this.backingVector.Y; - } - - /// - /// Gets the Y luminance component. - /// A value usually ranging between 0 and 1. - /// - public float Yl - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => this.backingVector.Z; + this.X = vector.X; + this.Y = vector.Y; + this.Yl = vector.Z; } - /// - public Vector3 Vector => this.backingVector; - /// /// Compares two objects for equality. /// - /// - /// The on the left side of the operand. - /// - /// - /// The on the right side of the operand. - /// + /// The on the left side of the operand. + /// The on the right side of the operand. /// /// True if the current left is equal to the parameter; otherwise, false. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator ==(CieXyy left, CieXyy right) - { - return left.Equals(right); - } + public static bool operator ==(CieXyy left, CieXyy right) => left.Equals(right); /// /// Compares two objects for inequality. /// - /// - /// The on the left side of the operand. - /// - /// - /// The on the right side of the operand. - /// + /// The on the left side of the operand. + /// The on the right side of the operand. /// /// True if the current left is unequal to the parameter; otherwise, false. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator !=(CieXyy left, CieXyy right) - { - return !left.Equals(right); - } + public static bool operator !=(CieXyy left, CieXyy right) => !left.Equals(right); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] public override int GetHashCode() { - return this.backingVector.GetHashCode(); + int hash = this.X.GetHashCode(); + hash = HashHelpers.Combine(hash, this.Y.GetHashCode()); + return HashHelpers.Combine(hash, this.Yl.GetHashCode()); } /// @@ -137,18 +108,9 @@ namespace SixLabors.ImageSharp.ColorSpaces [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool Equals(CieXyy other) { - return this.backingVector.Equals(other.backingVector); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool AlmostEquals(CieXyy other, float precision) - { - var result = Vector3.Abs(this.backingVector - other.backingVector); - - return result.X <= precision - && result.Y <= precision - && result.Z <= precision; + return this.X.Equals(other.X) + && this.Y.Equals(other.Y) + && this.Yl.Equals(other.Yl); } } } \ No newline at end of file diff --git a/src/ImageSharp/ColorSpaces/CieXyz.cs b/src/ImageSharp/ColorSpaces/CieXyz.cs index fa4261b46..d23be9744 100644 --- a/src/ImageSharp/ColorSpaces/CieXyz.cs +++ b/src/ImageSharp/ColorSpaces/CieXyz.cs @@ -12,12 +12,25 @@ namespace SixLabors.ImageSharp.ColorSpaces /// Represents an CIE XYZ 1931 color /// /// - internal readonly struct CieXyz : IColorVector, IEquatable, IAlmostEquatable + internal readonly struct CieXyz : IEquatable { /// - /// The backing vector for SIMD support. + /// Gets the X component. A mix (a linear combination) of cone response curves chosen to be nonnegative. + /// A value usually ranging between 0 and 1. + /// + public readonly float X; + + /// + /// Gets the Y luminance component. + /// A value usually ranging between 0 and 1. + /// + public readonly float Y; + + /// + /// Gets the Z component. Quasi-equal to blue stimulation, or the S cone response + /// A value usually ranging between 0 and 1. /// - private readonly Vector3 backingVector; + public readonly float Z; /// /// Initializes a new instance of the struct. @@ -29,6 +42,10 @@ namespace SixLabors.ImageSharp.ColorSpaces public CieXyz(float x, float y, float z) : this(new Vector3(x, y, z)) { + // Not clamping as documentation about this space seems to indicate "usual" ranges + this.X = x; + this.Y = y; + this.Z = z; } /// @@ -39,51 +56,16 @@ namespace SixLabors.ImageSharp.ColorSpaces : this() { // Not clamping as documentation about this space seems to indicate "usual" ranges - this.backingVector = vector; - } - - /// - /// Gets the X component. A mix (a linear combination) of cone response curves chosen to be nonnegative. - /// A value usually ranging between 0 and 1. - /// - public float X - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => this.backingVector.X; - } - - /// - /// Gets the Y luminance component. - /// A value usually ranging between 0 and 1. - /// - public float Y - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => this.backingVector.Y; - } - - /// - /// Gets the Z component. Quasi-equal to blue stimulation, or the S cone response - /// A value usually ranging between 0 and 1. - /// - public float Z - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => this.backingVector.Z; + this.X = vector.X; + this.Y = vector.Y; + this.Z = vector.Z; } - /// - public Vector3 Vector => this.backingVector; - /// /// Compares two objects for equality. /// - /// - /// The on the left side of the operand. - /// - /// - /// The on the right side of the operand. - /// + /// The on the left side of the operand. + /// The on the right side of the operand. /// /// True if the current left is equal to the parameter; otherwise, false. /// @@ -96,12 +78,8 @@ namespace SixLabors.ImageSharp.ColorSpaces /// /// Compares two objects for inequality. /// - /// - /// The on the left side of the operand. - /// - /// - /// The on the right side of the operand. - /// + /// The on the left side of the operand. + /// The on the right side of the operand. /// /// True if the current left is unequal to the parameter; otherwise, false. /// @@ -111,11 +89,19 @@ namespace SixLabors.ImageSharp.ColorSpaces return !left.Equals(right); } - /// + /// + /// Returns a new representing this instance. + /// + /// The . [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Vector3 ToVector3() => new Vector3(this.X, this.Y, this.Z); + + /// public override int GetHashCode() { - return this.backingVector.GetHashCode(); + int hash = this.X.GetHashCode(); + hash = HashHelpers.Combine(hash, this.Y.GetHashCode()); + return HashHelpers.Combine(hash, this.Z.GetHashCode()); } /// @@ -127,27 +113,15 @@ namespace SixLabors.ImageSharp.ColorSpaces } /// - public override bool Equals(object obj) - { - return obj is CieXyz other && this.Equals(other); - } + public override bool Equals(object obj) => obj is CieXyz other && this.Equals(other); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool Equals(CieXyz other) { - return this.backingVector.Equals(other.backingVector); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool AlmostEquals(CieXyz other, float precision) - { - var result = Vector3.Abs(this.backingVector - other.backingVector); - - return result.X <= precision - && result.Y <= precision - && result.Z <= precision; + return this.X.Equals(other.X) + && this.Y.Equals(other.Y) + && this.Z.Equals(other.Z); } } } \ No newline at end of file diff --git a/src/ImageSharp/ColorSpaces/Cmyk.cs b/src/ImageSharp/ColorSpaces/Cmyk.cs index 2702d4ba3..711e9867f 100644 --- a/src/ImageSharp/ColorSpaces/Cmyk.cs +++ b/src/ImageSharp/ColorSpaces/Cmyk.cs @@ -2,7 +2,6 @@ // Licensed under the Apache License, Version 2.0. using System; -using System.ComponentModel; using System.Numerics; using System.Runtime.CompilerServices; @@ -11,12 +10,31 @@ namespace SixLabors.ImageSharp.ColorSpaces /// /// Represents an CMYK (cyan, magenta, yellow, keyline) color. /// - internal readonly struct Cmyk : IEquatable, IAlmostEquatable + internal readonly struct Cmyk : IEquatable { /// - /// The backing vector for SIMD support. + /// Gets the cyan color component. + /// A value ranging between 0 and 1. + /// + public readonly float C; + + /// + /// Gets the magenta color component. + /// A value ranging between 0 and 1. /// - private readonly Vector4 backingVector; + public readonly float M; + + /// + /// Gets the yellow color component. + /// A value ranging between 0 and 1. + /// + public readonly float Y; + + /// + /// Gets the keyline black color component. + /// A value ranging between 0 and 1. + /// + public readonly float K; /// /// Initializes a new instance of the struct. @@ -37,92 +55,44 @@ namespace SixLabors.ImageSharp.ColorSpaces /// The vector representing the c, m, y, k components. [MethodImpl(MethodImplOptions.AggressiveInlining)] public Cmyk(Vector4 vector) - : this() - { - this.backingVector = Vector4.Clamp(vector, Vector4.Zero, Vector4.One); - } - - /// - /// Gets the cyan color component. - /// A value ranging between 0 and 1. - /// - public float C { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => this.backingVector.X; - } - - /// - /// Gets the magenta color component. - /// A value ranging between 0 and 1. - /// - public float M - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => this.backingVector.Y; - } - - /// - /// Gets the yellow color component. - /// A value ranging between 0 and 1. - /// - public float Y - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => this.backingVector.Z; - } - - /// - /// Gets the keyline black color component. - /// A value ranging between 0 and 1. - /// - public float K - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => this.backingVector.W; + vector = Vector4.Clamp(vector, Vector4.Zero, Vector4.One); + this.C = vector.X; + this.Y = vector.Y; + this.M = vector.Z; + this.K = vector.W; } /// /// Compares two objects for equality. /// - /// - /// The on the left side of the operand. - /// - /// - /// The on the right side of the operand. - /// + /// The on the left side of the operand. + /// The on the right side of the operand. /// /// True if the current left is equal to the parameter; otherwise, false. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator ==(Cmyk left, Cmyk right) - { - return left.Equals(right); - } + public static bool operator ==(Cmyk left, Cmyk right) => left.Equals(right); /// /// Compares two objects for inequality /// - /// - /// The on the left side of the operand. - /// - /// - /// The on the right side of the operand. - /// + /// The on the left side of the operand. + /// The on the right side of the operand. /// /// True if the current left is unequal to the parameter; otherwise, false. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator !=(Cmyk left, Cmyk right) - { - return !left.Equals(right); - } + public static bool operator !=(Cmyk left, Cmyk right) => !left.Equals(right); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public override int GetHashCode() { - return this.backingVector.GetHashCode(); + int hash = this.C.GetHashCode(); + hash = HashHelpers.Combine(hash, this.M.GetHashCode()); + hash = HashHelpers.Combine(hash, this.Y.GetHashCode()); + return HashHelpers.Combine(hash, this.K.GetHashCode()); } /// @@ -134,28 +104,16 @@ namespace SixLabors.ImageSharp.ColorSpaces } /// - public override bool Equals(object obj) - { - return obj is Cmyk other && this.Equals(other); - } + public override bool Equals(object obj) => obj is Cmyk other && this.Equals(other); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool Equals(Cmyk other) { - return this.backingVector.Equals(other.backingVector); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool AlmostEquals(Cmyk other, float precision) - { - var result = Vector4.Abs(this.backingVector - other.backingVector); - - return result.X <= precision - && result.Y <= precision - && result.Z <= precision - && result.W <= precision; + return this.C.Equals(other.C) + && this.M.Equals(other.M) + && this.Y.Equals(other.Y) + && this.K.Equals(other.K); } } } \ No newline at end of file diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyzAndLmsConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyzAndLmsConverter.cs index 513a928c7..e3a031e82 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyzAndLmsConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyzAndLmsConverter.cs @@ -63,7 +63,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation [MethodImpl(MethodImplOptions.AggressiveInlining)] public Lms Convert(in CieXyz input) { - var vector = Vector3.Transform(input.Vector, this.transformationMatrix); + var vector = Vector3.Transform(input.ToVector3(), this.transformationMatrix); return new Lms(vector); } @@ -72,7 +72,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation [MethodImpl(MethodImplOptions.AggressiveInlining)] public CieXyz Convert(in Lms input) { - var vector = Vector3.Transform(input.Vector, this.inverseTransformationMatrix); + var vector = Vector3.Transform(input.ToVector3(), this.inverseTransformationMatrix); return new CieXyz(vector); } diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyzToLinearRgbConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyzToLinearRgbConverter.cs index 0ceb05fd9..a2786654f 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyzToLinearRgbConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyzToLinearRgbConverter.cs @@ -43,7 +43,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation public LinearRgb Convert(in CieXyz input) { Matrix4x4.Invert(this.conversionMatrix, out Matrix4x4 inverted); - var vector = Vector3.Transform(input.Vector, inverted); + var vector = Vector3.Transform(input.ToVector3(), inverted); return new LinearRgb(vector, this.TargetWorkingSpace); } } diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CmykAndRgbConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CmykAndRgbConverter.cs index 649e98400..26d15beb3 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CmykAndRgbConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CmykAndRgbConverter.cs @@ -25,7 +25,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation public Cmyk Convert(in Rgb input) { // To CMYK - Vector3 cmy = Vector3.One - input.Vector; + Vector3 cmy = Vector3.One - input.ToVector3(); // To CMYK var k = new Vector3(MathF.Min(cmy.X, MathF.Min(cmy.Y, cmy.Z))); diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/LinearRgbAndCieXyzConverterBase.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/LinearRgbAndCieXyzConverterBase.cs index 492d4a58f..a9d8e8398 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/LinearRgbAndCieXyzConverterBase.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/LinearRgbAndCieXyzConverterBase.cs @@ -42,23 +42,35 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation var xyzMatrix = new Matrix4x4 { - M11 = mXr, M21 = mXg, M31 = mXb, - M12 = Yr, M22 = Yg, M32 = Yb, - M13 = mZr, M23 = mZg, M33 = mZb, + M11 = mXr, + M21 = mXg, + M31 = mXb, + M12 = Yr, + M22 = Yg, + M32 = Yb, + M13 = mZr, + M23 = mZg, + M33 = mZb, M44 = 1F }; Matrix4x4.Invert(xyzMatrix, out Matrix4x4 inverseXyzMatrix); - var vector = Vector3.Transform(workingSpace.WhitePoint.Vector, inverseXyzMatrix); + var vector = Vector3.Transform(workingSpace.WhitePoint.ToVector3(), inverseXyzMatrix); // Use transposed Rows/Columns // TODO: Is there a built in method for this multiplication? return new Matrix4x4 { - M11 = vector.X * mXr, M21 = vector.Y * mXg, M31 = vector.Z * mXb, - M12 = vector.X * Yr, M22 = vector.Y * Yg, M32 = vector.Z * Yb, - M13 = vector.X * mZr, M23 = vector.Y * mZg, M33 = vector.Z * mZb, + M11 = vector.X * mXr, + M21 = vector.Y * mXg, + M31 = vector.Z * mXb, + M12 = vector.X * Yr, + M22 = vector.Y * Yg, + M32 = vector.Z * Yb, + M13 = vector.X * mZr, + M23 = vector.Y * mZg, + M33 = vector.Z * mZb, M44 = 1F }; } diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/LinearRgbToCieXyzConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/LinearRgbToCieXyzConverter.cs index 113ec0e7e..80849021f 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/LinearRgbToCieXyzConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/LinearRgbToCieXyzConverter.cs @@ -40,7 +40,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation { DebugGuard.IsTrue(input.WorkingSpace.Equals(this.SourceWorkingSpace), nameof(input.WorkingSpace), "Input and source working spaces must be equal."); - var vector = Vector3.Transform(input.Vector, this.conversionMatrix); + var vector = Vector3.Transform(input.ToVector3(), this.conversionMatrix); return new CieXyz(vector); } } diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/LinearRgbToRgbConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/LinearRgbToRgbConverter.cs index 6c43b00a3..a985f8ed5 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/LinearRgbToRgbConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/LinearRgbToRgbConverter.cs @@ -13,7 +13,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation /// public Rgb Convert(in LinearRgb input) { - Vector3 vector = input.Vector; + Vector3 vector = input.ToVector3(); vector.X = input.WorkingSpace.Companding.Compress(vector.X); vector.Y = input.WorkingSpace.Companding.Compress(vector.Y); vector.Z = input.WorkingSpace.Companding.Compress(vector.Z); diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/RgbToLinearRgbConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/RgbToLinearRgbConverter.cs index 2229c807e..c8d04c54a 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/RgbToLinearRgbConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/RgbToLinearRgbConverter.cs @@ -13,7 +13,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation /// public LinearRgb Convert(in Rgb input) { - Vector3 vector = input.Vector; + Vector3 vector = input.ToVector3(); vector.X = input.WorkingSpace.Companding.Expand(vector.X); vector.Y = input.WorkingSpace.Companding.Expand(vector.Y); vector.Z = input.WorkingSpace.Companding.Expand(vector.Z); diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/YCbCrAndRgbConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/YCbCrAndRgbConverter.cs index 99e2ca1bd..5d2cd85ba 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/YCbCrAndRgbConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/YCbCrAndRgbConverter.cs @@ -34,7 +34,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation [MethodImpl(MethodImplOptions.AggressiveInlining)] public YCbCr Convert(in Rgb input) { - Vector3 rgb = input.Vector * MaxBytes; + Vector3 rgb = input.ToVector3() * MaxBytes; float r = rgb.X; float g = rgb.Y; float b = rgb.Z; diff --git a/src/ImageSharp/ColorSpaces/Conversion/VonKriesChromaticAdaptation.cs b/src/ImageSharp/ColorSpaces/Conversion/VonKriesChromaticAdaptation.cs index 01aeb2556..f3d74b6f8 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/VonKriesChromaticAdaptation.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/VonKriesChromaticAdaptation.cs @@ -58,8 +58,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion Lms sourceWhitePointLms = this.converter.Convert(sourceWhitePoint); Lms targetWhitePointLms = this.converter.Convert(targetWhitePoint); - Vector3 vector = targetWhitePointLms.Vector / sourceWhitePointLms.Vector; - var targetColorLms = new Lms(Vector3.Multiply(vector, sourceColorLms.Vector)); + Vector3 vector = targetWhitePointLms.ToVector3() / sourceWhitePointLms.ToVector3(); + var targetColorLms = new Lms(Vector3.Multiply(vector, sourceColorLms.ToVector3())); return this.converter.Convert(targetColorLms); } diff --git a/src/ImageSharp/ColorSpaces/Hsl.cs b/src/ImageSharp/ColorSpaces/Hsl.cs index 8ed406753..14dfc5d1a 100644 --- a/src/ImageSharp/ColorSpaces/Hsl.cs +++ b/src/ImageSharp/ColorSpaces/Hsl.cs @@ -2,7 +2,6 @@ // Licensed under the Apache License, Version 2.0. using System; -using System.ComponentModel; using System.Numerics; using System.Runtime.CompilerServices; @@ -11,7 +10,7 @@ namespace SixLabors.ImageSharp.ColorSpaces /// /// Represents a Hsl (hue, saturation, lightness) color. /// - internal readonly struct Hsl : IColorVector, IEquatable, IAlmostEquatable + internal readonly struct Hsl : IEquatable { /// /// Max range used for clamping. @@ -19,9 +18,22 @@ namespace SixLabors.ImageSharp.ColorSpaces private static readonly Vector3 VectorMax = new Vector3(360, 1, 1); /// - /// The backing vector for SIMD support. + /// Gets the hue component. + /// A value ranging between 0 and 360. + /// + public readonly float H; + + /// + /// Gets the saturation component. + /// A value ranging between 0 and 1. /// - private readonly Vector3 backingVector; + public readonly float S; + + /// + /// Gets the lightness component. + /// A value ranging between 0 and 1. + /// + public readonly float L; /// /// Initializes a new instance of the struct. @@ -42,83 +54,43 @@ namespace SixLabors.ImageSharp.ColorSpaces [MethodImpl(MethodImplOptions.AggressiveInlining)] public Hsl(Vector3 vector) { - this.backingVector = Vector3.Clamp(vector, Vector3.Zero, VectorMax); - } - - /// - /// Gets the hue component. - /// A value ranging between 0 and 360. - /// - public float H - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => this.backingVector.X; - } - - /// - /// Gets the saturation component. - /// A value ranging between 0 and 1. - /// - public float S - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => this.backingVector.Y; + vector = Vector3.Clamp(vector, Vector3.Zero, VectorMax); + this.H = vector.X; + this.S = vector.Y; + this.L = vector.Z; } - /// - /// Gets the lightness component. - /// A value ranging between 0 and 1. - /// - public float L - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => this.backingVector.Z; - } - - /// - public Vector3 Vector => this.backingVector; - /// /// Compares two objects for equality. /// /// /// The on the left side of the operand. /// - /// - /// The on the right side of the operand. - /// + /// The on the right side of the operand. /// /// True if the current left is equal to the parameter; otherwise, false. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator ==(Hsl left, Hsl right) - { - return left.Equals(right); - } + public static bool operator ==(Hsl left, Hsl right) => left.Equals(right); /// /// Compares two objects for inequality. /// - /// - /// The on the left side of the operand. - /// - /// - /// The on the right side of the operand. - /// + /// The on the left side of the operand. + /// The on the right side of the operand. /// /// True if the current left is unequal to the parameter; otherwise, false. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator !=(Hsl left, Hsl right) - { - return !left.Equals(right); - } + public static bool operator !=(Hsl left, Hsl right) => !left.Equals(right); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public override int GetHashCode() { - return this.backingVector.GetHashCode(); + int hash = this.H.GetHashCode(); + hash = HashHelpers.Combine(hash, this.S.GetHashCode()); + return HashHelpers.Combine(hash, this.L.GetHashCode()); } /// @@ -130,27 +102,15 @@ namespace SixLabors.ImageSharp.ColorSpaces } /// - public override bool Equals(object obj) - { - return obj is Hsl other && this.Equals(other); - } + public override bool Equals(object obj) => obj is Hsl other && this.Equals(other); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool Equals(Hsl other) { - return this.backingVector.Equals(other.backingVector); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool AlmostEquals(Hsl other, float precision) - { - var result = Vector3.Abs(this.backingVector - other.backingVector); - - return result.X <= precision - && result.Y <= precision - && result.Z <= precision; + return this.H.Equals(other.H) + && this.S.Equals(other.S) + && this.L.Equals(other.L); } } } \ No newline at end of file diff --git a/src/ImageSharp/ColorSpaces/Hsv.cs b/src/ImageSharp/ColorSpaces/Hsv.cs index 78a49097e..1035f94bf 100644 --- a/src/ImageSharp/ColorSpaces/Hsv.cs +++ b/src/ImageSharp/ColorSpaces/Hsv.cs @@ -13,7 +13,7 @@ namespace SixLabors.ImageSharp.ColorSpaces /// /// Represents a HSV (hue, saturation, value) color. Also known as HSB (hue, saturation, brightness). /// - internal readonly struct Hsv : IColorVector, IEquatable, IAlmostEquatable + internal readonly struct Hsv : IEquatable { /// /// Max range used for clamping. @@ -21,9 +21,22 @@ namespace SixLabors.ImageSharp.ColorSpaces private static readonly Vector3 VectorMax = new Vector3(360, 1, 1); /// - /// The backing vector for SIMD support. + /// Gets the hue component. + /// A value ranging between 0 and 360. + /// + public readonly float H; + + /// + /// Gets the saturation component. + /// A value ranging between 0 and 1. + /// + public readonly float S; + + /// + /// Gets the value (brightness) component. + /// A value ranging between 0 and 1. /// - private readonly Vector3 backingVector; + public readonly float V; /// /// Initializes a new instance of the struct. @@ -44,42 +57,12 @@ namespace SixLabors.ImageSharp.ColorSpaces [MethodImpl(MethodImplOptions.AggressiveInlining)] public Hsv(Vector3 vector) { - this.backingVector = Vector3.Clamp(vector, Vector3.Zero, VectorMax); + vector = Vector3.Clamp(vector, Vector3.Zero, VectorMax); + this.H = vector.X; + this.S = vector.Y; + this.V = vector.Z; } - /// - /// Gets the hue component. - /// A value ranging between 0 and 360. - /// - public float H - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => this.backingVector.X; - } - - /// - /// Gets the saturation component. - /// A value ranging between 0 and 1. - /// - public float S - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => this.backingVector.Y; - } - - /// - /// Gets the value (brightness) component. - /// A value ranging between 0 and 1. - /// - public float V - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => this.backingVector.Z; - } - - /// - public Vector3 Vector => this.backingVector; - /// /// Allows the implicit conversion of an instance of to a /// . @@ -133,44 +116,32 @@ namespace SixLabors.ImageSharp.ColorSpaces /// /// Compares two objects for equality. /// - /// - /// The on the left side of the operand. - /// - /// - /// The on the right side of the operand. - /// + /// The on the left side of the operand. + /// The on the right side of the operand. /// /// True if the current left is equal to the parameter; otherwise, false. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator ==(Hsv left, Hsv right) - { - return left.Equals(right); - } + public static bool operator ==(Hsv left, Hsv right) => left.Equals(right); /// /// Compares two objects for inequality. /// - /// - /// The on the left side of the operand. - /// - /// - /// The on the right side of the operand. - /// + /// The on the left side of the operand. + /// The on the right side of the operand. /// /// True if the current left is unequal to the parameter; otherwise, false. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator !=(Hsv left, Hsv right) - { - return !left.Equals(right); - } + public static bool operator !=(Hsv left, Hsv right) => !left.Equals(right); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public override int GetHashCode() { - return this.backingVector.GetHashCode(); + int hash = this.H.GetHashCode(); + hash = HashHelpers.Combine(hash, this.S.GetHashCode()); + return HashHelpers.Combine(hash, this.V.GetHashCode()); } /// @@ -182,27 +153,15 @@ namespace SixLabors.ImageSharp.ColorSpaces } /// - public override bool Equals(object obj) - { - return obj is Hsv other && this.Equals(other); - } + public override bool Equals(object obj) => obj is Hsv other && this.Equals(other); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool Equals(Hsv other) { - return this.backingVector.Equals(other.backingVector); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool AlmostEquals(Hsv other, float precision) - { - var result = Vector3.Abs(this.backingVector - other.backingVector); - - return result.X <= precision - && result.Y <= precision - && result.Z <= precision; + return this.H.Equals(other.H) + && this.S.Equals(other.S) + && this.V.Equals(other.V); } } } \ No newline at end of file diff --git a/src/ImageSharp/ColorSpaces/HunterLab.cs b/src/ImageSharp/ColorSpaces/HunterLab.cs index 44f31bc29..2f8da5a9a 100644 --- a/src/ImageSharp/ColorSpaces/HunterLab.cs +++ b/src/ImageSharp/ColorSpaces/HunterLab.cs @@ -12,7 +12,7 @@ namespace SixLabors.ImageSharp.ColorSpaces /// Represents an Hunter LAB color. /// /// - internal readonly struct HunterLab : IColorVector, IEquatable, IAlmostEquatable + internal readonly struct HunterLab : IEquatable { /// /// D50 standard illuminant. @@ -21,9 +21,27 @@ namespace SixLabors.ImageSharp.ColorSpaces public static readonly CieXyz DefaultWhitePoint = Illuminants.C; /// - /// The backing vector for SIMD support. + /// Gets the lightness dimension. + /// A value ranging between 0 (black), 100 (diffuse white) or higher (specular white). + /// + public readonly float L; + + /// + /// Gets the a color component. + /// A value ranging from -100 to 100. Negative is green, positive magenta. /// - private readonly Vector3 backingVector; + public readonly float A; + + /// + /// Gets the b color component. + /// A value ranging from -100 to 100. Negative is blue, positive is yellow + /// + public readonly float B; + + /// + /// Gets the reference white point of this color + /// + public readonly CieXyz WhitePoint; /// /// Initializes a new instance of the struct. @@ -69,90 +87,43 @@ namespace SixLabors.ImageSharp.ColorSpaces /// The reference white point. [MethodImpl(MethodImplOptions.AggressiveInlining)] public HunterLab(Vector3 vector, CieXyz whitePoint) - : this() { - this.backingVector = vector; + // TODO: Clamp? + this.L = vector.X; + this.A = vector.Y; + this.B = vector.Z; this.WhitePoint = whitePoint; } - /// - /// Gets the reference white point of this color - /// - public CieXyz WhitePoint { get; } - - /// - /// Gets the lightness dimension. - /// A value ranging between 0 (black), 100 (diffuse white) or higher (specular white). - /// - public float L - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => this.backingVector.X; - } - - /// - /// Gets the a color component. - /// A value ranging from -100 to 100. Negative is green, positive magenta. - /// - public float A - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => this.backingVector.Y; - } - - /// - /// Gets the b color component. - /// A value ranging from -100 to 100. Negative is blue, positive is yellow - /// - public float B - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => this.backingVector.Z; - } - - /// - public Vector3 Vector => this.backingVector; - /// /// Compares two objects for equality. /// - /// - /// The on the left side of the operand. - /// - /// - /// The on the right side of the operand. - /// + /// The on the left side of the operand. + /// The on the right side of the operand. /// /// True if the current left is equal to the parameter; otherwise, false. /// - public static bool operator ==(HunterLab left, HunterLab right) - { - return left.Equals(right); - } + public static bool operator ==(HunterLab left, HunterLab right) => left.Equals(right); /// /// Compares two objects for inequality /// - /// - /// The on the left side of the operand. - /// - /// - /// The on the right side of the operand. - /// + /// The on the left side of the operand. + /// The on the right side of the operand. /// /// True if the current left is unequal to the parameter; otherwise, false. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator !=(HunterLab left, HunterLab right) - { - return !left.Equals(right); - } + public static bool operator !=(HunterLab left, HunterLab right) => !left.Equals(right); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public override int GetHashCode() { - return HashHelpers.Combine(this.WhitePoint.GetHashCode(), this.backingVector.GetHashCode()); + int hash = this.L.GetHashCode(); + hash = HashHelpers.Combine(hash, this.A.GetHashCode()); + hash = HashHelpers.Combine(hash, this.B.GetHashCode()); + return HashHelpers.Combine(hash, this.WhitePoint.GetHashCode()); } /// @@ -164,29 +135,16 @@ namespace SixLabors.ImageSharp.ColorSpaces } /// - public override bool Equals(object obj) - { - return obj is HunterLab other && this.Equals(other); - } + public override bool Equals(object obj) => obj is HunterLab other && this.Equals(other); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool Equals(HunterLab other) { - return this.backingVector.Equals(other.backingVector) + return this.L.Equals(other.L) + && this.A.Equals(other.A) + && this.B.Equals(other.B) && this.WhitePoint.Equals(other.WhitePoint); } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool AlmostEquals(HunterLab other, float precision) - { - var result = Vector3.Abs(this.backingVector - other.backingVector); - - return this.WhitePoint.Equals(other.WhitePoint) - && result.X <= precision - && result.Y <= precision - && result.Z <= precision; - } } } \ No newline at end of file diff --git a/src/ImageSharp/ColorSpaces/IColorVector.cs b/src/ImageSharp/ColorSpaces/IColorVector.cs deleted file mode 100644 index 85c040b86..000000000 --- a/src/ImageSharp/ColorSpaces/IColorVector.cs +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -using System.Numerics; - -namespace SixLabors.ImageSharp.ColorSpaces -{ - /// - /// Color represented as a vector in its color space - /// - internal interface IColorVector - { - /// - /// Gets the vector representation of the color - /// - Vector3 Vector { get; } - } -} \ No newline at end of file diff --git a/src/ImageSharp/ColorSpaces/IRgbWorkingSpace.cs b/src/ImageSharp/ColorSpaces/IRgbWorkingSpace.cs deleted file mode 100644 index 00a714c6f..000000000 --- a/src/ImageSharp/ColorSpaces/IRgbWorkingSpace.cs +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -using System; -using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation; - -namespace SixLabors.ImageSharp.ColorSpaces -{ - /// - /// Encasulates the RGB working color space - /// - internal interface IRgbWorkingSpace : IEquatable - { - /// - /// Gets the reference white of the color space. - /// - CieXyz WhitePoint { get; } - - /// - /// Gets the chromaticity coordinates of the primaries. - /// - RgbPrimariesChromaticityCoordinates ChromaticityCoordinates { get; } - - /// - /// Gets the companding function associated with the RGB color system. Used for conversion to XYZ and backwards. - /// - /// - /// - ICompanding Companding { get; } - } -} \ No newline at end of file diff --git a/src/ImageSharp/ColorSpaces/LinearRgb.cs b/src/ImageSharp/ColorSpaces/LinearRgb.cs index d0aeba75a..e9e06c0bb 100644 --- a/src/ImageSharp/ColorSpaces/LinearRgb.cs +++ b/src/ImageSharp/ColorSpaces/LinearRgb.cs @@ -11,7 +11,7 @@ namespace SixLabors.ImageSharp.ColorSpaces /// /// Represents an linear Rgb color with specified working space /// - internal readonly struct LinearRgb : IColorVector, IEquatable, IAlmostEquatable + internal readonly struct LinearRgb : IEquatable { /// /// The default LinearRgb working space. @@ -19,9 +19,27 @@ namespace SixLabors.ImageSharp.ColorSpaces public static readonly RgbWorkingSpace DefaultWorkingSpace = RgbWorkingSpaces.SRgb; /// - /// The backing vector for SIMD support. + /// Gets the red component. + /// A value usually ranging between 0 and 1. + /// + public readonly float R; + + /// + /// Gets the green component. + /// A value usually ranging between 0 and 1. /// - private readonly Vector3 backingVector; + public readonly float G; + + /// + /// Gets the blue component. + /// A value usually ranging between 0 and 1. + /// + public readonly float B; + + /// + /// Gets the LinearRgb color space + /// + public readonly RgbWorkingSpace WorkingSpace; /// /// Initializes a new instance of the struct. @@ -65,92 +83,51 @@ namespace SixLabors.ImageSharp.ColorSpaces /// The LinearRgb working space. [MethodImpl(MethodImplOptions.AggressiveInlining)] public LinearRgb(Vector3 vector, RgbWorkingSpace workingSpace) - : this() { // Clamp to 0-1 range. - this.backingVector = Vector3.Clamp(vector, Vector3.Zero, Vector3.One); + vector = Vector3.Clamp(vector, Vector3.Zero, Vector3.One); + this.R = vector.X; + this.G = vector.Y; + this.B = vector.Z; this.WorkingSpace = workingSpace; } - /// - /// Gets the red component. - /// A value usually ranging between 0 and 1. - /// - public float R - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => this.backingVector.X; - } - - /// - /// Gets the green component. - /// A value usually ranging between 0 and 1. - /// - public float G - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => this.backingVector.Y; - } - - /// - /// Gets the blue component. - /// A value usually ranging between 0 and 1. - /// - public float B - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => this.backingVector.Z; - } - - /// - /// Gets the LinearRgb color space - /// - public RgbWorkingSpace WorkingSpace { get; } - - /// - public Vector3 Vector => this.backingVector; - /// /// Compares two objects for equality. /// - /// - /// The on the left side of the operand. - /// - /// - /// The on the right side of the operand. - /// + /// The on the left side of the operand. + /// The on the right side of the operand. /// /// True if the current left is equal to the parameter; otherwise, false. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator ==(LinearRgb left, LinearRgb right) - { - return left.Equals(right); - } + public static bool operator ==(LinearRgb left, LinearRgb right) => left.Equals(right); /// /// Compares two objects for inequality. /// - /// - /// The on the left side of the operand. - /// - /// - /// The on the right side of the operand. - /// + /// The on the left side of the operand. + /// The on the right side of the operand. /// /// True if the current left is unequal to the parameter; otherwise, false. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator !=(LinearRgb left, LinearRgb right) - { - return !left.Equals(right); - } + public static bool operator !=(LinearRgb left, LinearRgb right) => !left.Equals(right); + + /// + /// Returns a new representing this instance. + /// + /// The . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Vector3 ToVector3() => new Vector3(this.R, this.G, this.B); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public override int GetHashCode() { - return this.backingVector.GetHashCode(); + int hash = this.R.GetHashCode(); + hash = HashHelpers.Combine(hash, this.G.GetHashCode()); + return HashHelpers.Combine(hash, this.B.GetHashCode()); } /// @@ -162,27 +139,15 @@ namespace SixLabors.ImageSharp.ColorSpaces } /// - public override bool Equals(object obj) - { - return obj is LinearRgb other && this.Equals(other); - } + public override bool Equals(object obj) => obj is LinearRgb other && this.Equals(other); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool Equals(LinearRgb other) { - return this.backingVector.Equals(other.backingVector); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool AlmostEquals(LinearRgb other, float precision) - { - var result = Vector3.Abs(this.backingVector - other.backingVector); - - return result.X <= precision - && result.Y <= precision - && result.Z <= precision; + return this.R.Equals(other.R) + && this.G.Equals(other.G) + && this.B.Equals(other.B); } } } \ No newline at end of file diff --git a/src/ImageSharp/ColorSpaces/Lms.cs b/src/ImageSharp/ColorSpaces/Lms.cs index 9b0331e0b..5c471649d 100644 --- a/src/ImageSharp/ColorSpaces/Lms.cs +++ b/src/ImageSharp/ColorSpaces/Lms.cs @@ -2,7 +2,6 @@ // Licensed under the Apache License, Version 2.0. using System; -using System.ComponentModel; using System.Numerics; using System.Runtime.CompilerServices; @@ -13,12 +12,25 @@ namespace SixLabors.ImageSharp.ColorSpaces /// named after their responsivity (sensitivity) at long, medium and short wavelengths. /// /// - internal readonly struct Lms : IColorVector, IEquatable, IAlmostEquatable + internal readonly struct Lms : IEquatable { /// - /// The backing vector for SIMD support. + /// Gets the L long component. + /// A value usually ranging between -1 and 1. + /// + public readonly float L; + + /// + /// Gets the M medium component. + /// A value usually ranging between -1 and 1. /// - private readonly Vector3 backingVector; + public readonly float M; + + /// + /// Gets the S short component. + /// A value usually ranging between -1 and 1. + /// + public readonly float S; /// /// Initializes a new instance of the struct. @@ -28,8 +40,10 @@ namespace SixLabors.ImageSharp.ColorSpaces /// S represents the responsivity at short wavelengths. [MethodImpl(MethodImplOptions.AggressiveInlining)] public Lms(float l, float m, float s) - : this(new Vector3(l, m, s)) { + this.L = l; + this.M = m; + this.S = s; } /// @@ -38,85 +52,48 @@ namespace SixLabors.ImageSharp.ColorSpaces /// The vector representing the l, m, s components. [MethodImpl(MethodImplOptions.AggressiveInlining)] public Lms(Vector3 vector) - : this() { // Not clamping as documentation about this space seems to indicate "usual" ranges - this.backingVector = vector; - } - - /// - /// Gets the L long component. - /// A value usually ranging between -1 and 1. - /// - public float L - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => this.backingVector.X; - } - - /// - /// Gets the M medium component. - /// A value usually ranging between -1 and 1. - /// - public float M - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => this.backingVector.Y; + this.L = vector.X; + this.M = vector.Y; + this.S = vector.Z; } - /// - /// Gets the S short component. - /// A value usually ranging between -1 and 1. - /// - public float S - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => this.backingVector.Z; - } - - /// - public Vector3 Vector => this.backingVector; - /// /// Compares two objects for equality. /// - /// - /// The on the left side of the operand. - /// - /// - /// The on the right side of the operand. - /// + /// The on the left side of the operand. + /// The on the right side of the operand. /// /// True if the current left is equal to the parameter; otherwise, false. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator ==(Lms left, Lms right) - { - return left.Equals(right); - } + public static bool operator ==(Lms left, Lms right) => left.Equals(right); /// /// Compares two objects for inequality. /// - /// - /// The on the left side of the operand. - /// - /// - /// The on the right side of the operand. - /// + /// The on the left side of the operand. + /// The on the right side of the operand. /// /// True if the current left is unequal to the parameter; otherwise, false. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator !=(Lms left, Lms right) - { - return !left.Equals(right); - } + public static bool operator !=(Lms left, Lms right) => !left.Equals(right); + + /// + /// Returns a new representing this instance. + /// + /// The . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Vector3 ToVector3() => new Vector3(this.L, this.M, this.S); /// public override int GetHashCode() { - return this.backingVector.GetHashCode(); + int hash = this.L.GetHashCode(); + hash = HashHelpers.Combine(hash, this.M.GetHashCode()); + return HashHelpers.Combine(hash, this.S.GetHashCode()); } /// @@ -128,27 +105,15 @@ namespace SixLabors.ImageSharp.ColorSpaces } /// - public override bool Equals(object obj) - { - return obj is Lms other && this.Equals(other); - } + public override bool Equals(object obj) => obj is Lms other && this.Equals(other); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool Equals(Lms other) { - return this.backingVector.Equals(other.backingVector); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool AlmostEquals(Lms other, float precision) - { - var result = Vector3.Abs(this.backingVector - other.backingVector); - - return result.X <= precision - && result.Y <= precision - && result.Z <= precision; + return this.L.Equals(other.L) + && this.M.Equals(other.M) + && this.S.Equals(other.S); } } } \ No newline at end of file diff --git a/src/ImageSharp/ColorSpaces/Rgb.cs b/src/ImageSharp/ColorSpaces/Rgb.cs index 74b0c5bc8..7c8437d6e 100644 --- a/src/ImageSharp/ColorSpaces/Rgb.cs +++ b/src/ImageSharp/ColorSpaces/Rgb.cs @@ -10,9 +10,9 @@ using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.ColorSpaces { /// - /// Represents an RGB color with specified working space + /// Represents an RGB color with specified working space. /// - internal readonly struct Rgb : IColorVector, IEquatable, IAlmostEquatable + internal readonly struct Rgb : IEquatable { /// /// The default rgb working space @@ -20,9 +20,27 @@ namespace SixLabors.ImageSharp.ColorSpaces public static readonly RgbWorkingSpace DefaultWorkingSpace = RgbWorkingSpaces.SRgb; /// - /// The backing vector for SIMD support. + /// Gets the red component. + /// A value usually ranging between 0 and 1. /// - private readonly Vector3 backingVector; + public readonly float R; + + /// + /// Gets the green component. + /// A value usually ranging between 0 and 1. + /// + public readonly float G; + + /// + /// Gets the blue component. + /// A value usually ranging between 0 and 1. + /// + public readonly float B; + + /// + /// Gets the Rgb color space + /// + public readonly RgbWorkingSpace WorkingSpace; /// /// Initializes a new instance of the struct. @@ -32,7 +50,7 @@ namespace SixLabors.ImageSharp.ColorSpaces /// The blue component ranging between 0 and 1. [MethodImpl(MethodImplOptions.AggressiveInlining)] public Rgb(float r, float g, float b) - : this(new Vector3(r, g, b)) + : this(r, g, b, DefaultWorkingSpace) { } @@ -45,8 +63,11 @@ namespace SixLabors.ImageSharp.ColorSpaces /// The rgb working space. [MethodImpl(MethodImplOptions.AggressiveInlining)] public Rgb(float r, float g, float b, RgbWorkingSpace workingSpace) - : this(new Vector3(r, g, b), workingSpace) { + this.R = r; + this.G = g; + this.B = b; + this.WorkingSpace = workingSpace; } /// @@ -66,51 +87,15 @@ namespace SixLabors.ImageSharp.ColorSpaces /// The rgb working space. [MethodImpl(MethodImplOptions.AggressiveInlining)] public Rgb(Vector3 vector, RgbWorkingSpace workingSpace) - : this() { // Clamp to 0-1 range. - this.backingVector = Vector3.Clamp(vector, Vector3.Zero, Vector3.One); + vector = Vector3.Clamp(vector, Vector3.Zero, Vector3.One); + this.R = vector.X; + this.G = vector.Y; + this.B = vector.Z; this.WorkingSpace = workingSpace; } - /// - /// Gets the red component. - /// A value usually ranging between 0 and 1. - /// - public float R - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => this.backingVector.X; - } - - /// - /// Gets the green component. - /// A value usually ranging between 0 and 1. - /// - public float G - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => this.backingVector.Y; - } - - /// - /// Gets the blue component. - /// A value usually ranging between 0 and 1. - /// - public float B - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => this.backingVector.Z; - } - - /// - /// Gets the Rgb color space - /// - public RgbWorkingSpace WorkingSpace { get; } - - /// - public Vector3 Vector => this.backingVector; - /// /// Allows the implicit conversion of an instance of to a /// . @@ -140,33 +125,32 @@ namespace SixLabors.ImageSharp.ColorSpaces /// True if the current left is equal to the parameter; otherwise, false. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator ==(Rgb left, Rgb right) - { - return left.Equals(right); - } + public static bool operator ==(Rgb left, Rgb right) => left.Equals(right); /// /// Compares two objects for inequality. /// - /// - /// The on the left side of the operand. - /// - /// - /// The on the right side of the operand. - /// + /// The on the left side of the operand. + /// The on the right side of the operand. /// /// True if the current left is unequal to the parameter; otherwise, false. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator !=(Rgb left, Rgb right) - { - return !left.Equals(right); - } + public static bool operator !=(Rgb left, Rgb right) => !left.Equals(right); + + /// + /// Returns a new representing this instance. + /// + /// The . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Vector3 ToVector3() => new Vector3(this.R, this.G, this.B); /// public override int GetHashCode() { - return this.backingVector.GetHashCode(); + int hash = this.R.GetHashCode(); + hash = HashHelpers.Combine(hash, this.G.GetHashCode()); + return HashHelpers.Combine(hash, this.B.GetHashCode()); } /// @@ -178,27 +162,15 @@ namespace SixLabors.ImageSharp.ColorSpaces } /// - public override bool Equals(object obj) - { - return obj is Rgb other && this.Equals(other); - } + public override bool Equals(object obj) => obj is Rgb other && this.Equals(other); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool Equals(Rgb other) { - return this.backingVector.Equals(other.backingVector); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool AlmostEquals(Rgb other, float precision) - { - var result = Vector3.Abs(this.backingVector - other.backingVector); - - return result.X <= precision - && result.Y <= precision - && result.Z <= precision; + return this.R.Equals(other.R) + && this.G.Equals(other.G) + && this.B.Equals(other.B); } } } \ No newline at end of file diff --git a/src/ImageSharp/ColorSpaces/YCbCr.cs b/src/ImageSharp/ColorSpaces/YCbCr.cs index 00533c699..f684f598b 100644 --- a/src/ImageSharp/ColorSpaces/YCbCr.cs +++ b/src/ImageSharp/ColorSpaces/YCbCr.cs @@ -2,7 +2,6 @@ // Licensed under the Apache License, Version 2.0. using System; -using System.ComponentModel; using System.Numerics; using System.Runtime.CompilerServices; @@ -13,7 +12,7 @@ namespace SixLabors.ImageSharp.ColorSpaces /// /// /// - internal readonly struct YCbCr : IColorVector, IEquatable, IAlmostEquatable + internal readonly struct YCbCr : IEquatable { /// /// Vector which is used in clamping to the max value. @@ -21,9 +20,22 @@ namespace SixLabors.ImageSharp.ColorSpaces private static readonly Vector3 VectorMax = new Vector3(255F); /// - /// The backing vector for SIMD support. + /// Gets the Y luminance component. + /// A value ranging between 0 and 255. + /// + public readonly float Y; + + /// + /// Gets the Cb chroma component. + /// A value ranging between 0 and 255. + /// + public readonly float Cb; + + /// + /// Gets the Cr chroma component. + /// A value ranging between 0 and 255. /// - private readonly Vector3 backingVector; + public readonly float Cr; /// /// Initializes a new instance of the struct. @@ -44,82 +56,40 @@ namespace SixLabors.ImageSharp.ColorSpaces [MethodImpl(MethodImplOptions.AggressiveInlining)] public YCbCr(Vector3 vector) { - this.backingVector = Vector3.Clamp(vector, Vector3.Zero, VectorMax); + vector = Vector3.Clamp(vector, Vector3.Zero, VectorMax); + this.Y = vector.X; + this.Cb = vector.Y; + this.Cr = vector.Z; } - /// - /// Gets the Y luminance component. - /// A value ranging between 0 and 255. - /// - public float Y - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => this.backingVector.X; - } - - /// - /// Gets the Cb chroma component. - /// A value ranging between 0 and 255. - /// - public float Cb - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => this.backingVector.Y; - } - - /// - /// Gets the Cr chroma component. - /// A value ranging between 0 and 255. - /// - public float Cr - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => this.backingVector.Z; - } - - /// - public Vector3 Vector => this.backingVector; - /// /// Compares two objects for equality. /// - /// - /// The on the left side of the operand. - /// - /// - /// The on the right side of the operand. - /// + /// The on the left side of the operand. + /// The on the right side of the operand. /// /// True if the current left is equal to the parameter; otherwise, false. /// - public static bool operator ==(YCbCr left, YCbCr right) - { - return left.Equals(right); - } + public static bool operator ==(YCbCr left, YCbCr right) => left.Equals(right); /// /// Compares two objects for inequality. /// - /// - /// The on the left side of the operand. - /// - /// - /// The on the right side of the operand. - /// + /// The on the left side of the operand. + /// The on the right side of the operand. /// /// True if the current left is unequal to the parameter; otherwise, false. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator !=(YCbCr left, YCbCr right) - { - return !left.Equals(right); - } + public static bool operator !=(YCbCr left, YCbCr right) => !left.Equals(right); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public override int GetHashCode() { - return this.backingVector.GetHashCode(); + int hash = this.Y.GetHashCode(); + hash = HashHelpers.Combine(hash, this.Cb.GetHashCode()); + return HashHelpers.Combine(hash, this.Cr.GetHashCode()); } /// @@ -131,27 +101,15 @@ namespace SixLabors.ImageSharp.ColorSpaces } /// - public override bool Equals(object obj) - { - return obj is YCbCr other && this.Equals(other); - } + public override bool Equals(object obj) => obj is YCbCr other && this.Equals(other); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool Equals(YCbCr other) { - return this.backingVector.Equals(other.backingVector); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool AlmostEquals(YCbCr other, float precision) - { - var result = Vector3.Abs(this.backingVector - other.backingVector); - - return result.X <= precision - && result.Y <= precision - && result.Z <= precision; + return this.Y.Equals(other.Y) + && this.Cb.Equals(other.Cb) + && this.Cr.Equals(other.Cr); } } } \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Colorspaces/ColorSpaceEqualityTests.cs b/tests/ImageSharp.Tests/Colorspaces/ColorSpaceEqualityTests.cs index 743653c41..b895ee9a4 100644 --- a/tests/ImageSharp.Tests/Colorspaces/ColorSpaceEqualityTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/ColorSpaceEqualityTests.cs @@ -17,228 +17,191 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces /// public class ColorSpaceEqualityTests { - internal static readonly Dictionary EmptyDataLookup = - new Dictionary - { - {nameof( CieLab), default(CieLab) }, - {nameof( CieLch), default(CieLch) }, - {nameof( CieLchuv), default(CieLchuv) }, - {nameof( CieLuv), default(CieLuv) }, - {nameof( CieXyz), default(CieXyz) }, - {nameof( CieXyy), default(CieXyy) }, - {nameof( Hsl), default(Hsl) }, - {nameof( HunterLab), default(HunterLab) }, - {nameof( Lms), default(Lms) }, - {nameof( LinearRgb), default(LinearRgb) }, - {nameof( Rgb), default(Rgb) }, - {nameof( YCbCr), default(YCbCr) } - }; - - public static readonly IEnumerable EmptyData = EmptyDataLookup.Select(x => new[] { x.Key }); - - public static readonly TheoryData EqualityData = - new TheoryData - { - { new CieLab(Vector3.One), new CieLab(Vector3.One), typeof(CieLab) }, - { new CieLch(Vector3.One), new CieLch(Vector3.One), typeof(CieLch) }, - { new CieLchuv(Vector3.One), new CieLchuv(Vector3.One), typeof(CieLchuv) }, - { 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) }, - { new Lms(Vector3.One), new Lms(Vector3.One), typeof(Lms) }, - { new LinearRgb(Vector3.One), new LinearRgb(Vector3.One), typeof(LinearRgb) }, - { new Rgb(Vector3.One), new Rgb(Vector3.One), typeof(Rgb) }, - { new Hsl(Vector3.One), new Hsl(Vector3.One), typeof(Hsl) }, - { new Hsv(Vector3.One), new Hsv(Vector3.One), typeof(Hsv) }, - { new YCbCr(Vector3.One), new YCbCr(Vector3.One), typeof(YCbCr) }, - }; - - public static readonly TheoryData NotEqualityDataNulls = - new TheoryData - { - // Valid object against null - { new CieLab(Vector3.One), null, typeof(CieLab) }, - { new CieLch(Vector3.One), null, typeof(CieLch) }, - { new CieLchuv(Vector3.One), null, typeof(CieLchuv) }, - { 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) }, - { new Lms(Vector3.One), null, typeof(Lms) }, - { new LinearRgb(Vector3.One), null, typeof(LinearRgb) }, - { new Rgb(Vector3.One), null, typeof(Rgb) }, - { new Hsl(Vector3.One), null, typeof(Hsl) }, - { new Hsv(Vector3.One), null, typeof(Hsv) }, - { new YCbCr(Vector3.One), null, typeof(YCbCr) }, - }; - - public static readonly TheoryData NotEqualityDataDifferentObjects = - new TheoryData - { - // Valid objects of different types but not equal - { new CieLab(Vector3.One), new CieLch(Vector3.Zero), null }, - { new CieLuv(Vector3.One), new CieLchuv(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 }, - { new Cmyk(Vector4.One), new Hsl(Vector3.Zero), null }, - { new YCbCr(Vector3.One), new CieXyy(Vector3.Zero), null }, - { new Hsv(Vector3.One), new Hsl(Vector3.Zero), null }, - }; - - public static readonly TheoryData NotEqualityData = - new TheoryData - { - // 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 CieLchuv(Vector3.One), new CieLchuv(Vector3.Zero), typeof(CieLchuv) }, - { 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) }, - { new Lms(Vector3.One), new Lms(Vector3.Zero), typeof(Lms) }, - { new LinearRgb(Vector3.One), new LinearRgb(Vector3.Zero), typeof(LinearRgb) }, - { new Rgb(Vector3.One), new Rgb(Vector3.Zero), typeof(Rgb) }, - { new Cmyk(Vector4.One), new Cmyk(Vector4.Zero), typeof(Cmyk) }, - { new Hsl(Vector3.One), new Hsl(Vector3.Zero), typeof(Hsl) }, - { new Hsv(Vector3.One), new Hsv(Vector3.Zero), typeof(Hsv) }, - { new YCbCr(Vector3.One), new YCbCr(Vector3.Zero), typeof(YCbCr) }, - }; - - public static readonly TheoryData AlmostEqualsData = - new TheoryData - { - { 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 CieLch(0F, 0F, 0F), new CieLch(0F, .001F, 0F), typeof(CieLch), .001F }, - { new CieLchuv(0F, 0F, 0F), new CieLchuv(0F, .001F, 0F), typeof(CieLchuv), .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 }, - { new CieXyz(380F, 380F, 380F), new CieXyz(380F, 380F, 380.001F), typeof(CieXyz), .01F }, - { new Cmyk(1, 1, 1, 1), new Cmyk(1, 1, 1, .99F), typeof(Cmyk), .01F }, - { new YCbCr(255F, 128F, 128F), new YCbCr(255F, 128F, 128.001F), typeof(YCbCr), .01F }, - { new Hsv(0F, 0F, 0F), new Hsv(0F, 0F, 0F), typeof(Hsv), 0F }, - { new Hsl(0F, 0F, 0F), new Hsl(0F, 0F, 0F), typeof(Hsl), 0F }, - }; - - public static readonly TheoryData AlmostNotEqualsData = - new TheoryData - { - { 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 }, - }; - - [Theory] - [MemberData(nameof(EmptyData))] - public void Vector_Equals_WhenTrue(string color) - { - IColorVector colorVector = EmptyDataLookup[color]; - // Act - bool equal = colorVector.Vector.Equals(Vector3.Zero); - - // Assert - Assert.True(equal); - } - - [Theory] - [MemberData(nameof(EqualityData))] - public void Equals_WhenTrue(object first, object second, Type type) - { - // Act - bool equal = first.Equals(second); - - // Assert - Assert.True(equal); - } - - [Theory] - [MemberData(nameof(NotEqualityDataNulls))] - [MemberData(nameof(NotEqualityDataDifferentObjects))] - [MemberData(nameof(NotEqualityData))] - public void Equals_WhenFalse(object first, object second, Type type) - { - // Act - bool equal = first.Equals(second); - - // Assert - Assert.False(equal); - } - - [Theory] - [MemberData(nameof(EqualityData))] - public void GetHashCode_WhenEqual(object first, object second, Type type) - { - // Act - bool equal = first.GetHashCode() == second.GetHashCode(); - - // Assert - Assert.True(equal); - } - - [Theory] - [MemberData(nameof(NotEqualityDataDifferentObjects))] - public void GetHashCode_WhenNotEqual(object first, object second, Type type) - { - // Act - bool equal = first.GetHashCode() == second.GetHashCode(); - - // Assert - Assert.False(equal); - } - - [Theory] - [MemberData(nameof(EqualityData))] - public void GenericEquals_WhenTrue(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 :) - dynamic firstObject = Convert.ChangeType(first, type); - dynamic secondObject = Convert.ChangeType(second, type); - - // Act - dynamic equal = firstObject.Equals(secondObject); - - // Assert - Assert.True(equal); - } - - [Theory] - [MemberData(nameof(NotEqualityData))] - public void GenericEquals_WhenFalse(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 :) - dynamic firstObject = Convert.ChangeType(first, type); - dynamic secondObject = Convert.ChangeType(second, type); - - // Act - dynamic equal = firstObject.Equals(secondObject); - - // Assert - Assert.False(equal); - } - - // TODO:Disabled due to RuntypeBinder errors while structs are internal + //internal static readonly Dictionary EmptyDataLookup = + // new Dictionary + // { + // {nameof( CieLab), default(CieLab) }, + // {nameof( CieLch), default(CieLch) }, + // {nameof( CieLchuv), default(CieLchuv) }, + // {nameof( CieLuv), default(CieLuv) }, + // {nameof( CieXyz), default(CieXyz) }, + // {nameof( CieXyy), default(CieXyy) }, + // {nameof( Hsl), default(Hsl) }, + // {nameof( HunterLab), default(HunterLab) }, + // {nameof( Lms), default(Lms) }, + // {nameof( LinearRgb), default(LinearRgb) }, + // {nameof( Rgb), default(Rgb) }, + // {nameof( YCbCr), default(YCbCr) } + // }; + + //public static readonly IEnumerable EmptyData = EmptyDataLookup.Select(x => new[] { x.Key }); + + //public static readonly TheoryData EqualityData = + // new TheoryData + // { + // { new CieLab(Vector3.One), new CieLab(Vector3.One), typeof(CieLab) }, + // { new CieLch(Vector3.One), new CieLch(Vector3.One), typeof(CieLch) }, + // { new CieLchuv(Vector3.One), new CieLchuv(Vector3.One), typeof(CieLchuv) }, + // { 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) }, + // { new Lms(Vector3.One), new Lms(Vector3.One), typeof(Lms) }, + // { new LinearRgb(Vector3.One), new LinearRgb(Vector3.One), typeof(LinearRgb) }, + // { new Rgb(Vector3.One), new Rgb(Vector3.One), typeof(Rgb) }, + // { new Hsl(Vector3.One), new Hsl(Vector3.One), typeof(Hsl) }, + // { new Hsv(Vector3.One), new Hsv(Vector3.One), typeof(Hsv) }, + // { new YCbCr(Vector3.One), new YCbCr(Vector3.One), typeof(YCbCr) }, + // }; + + //public static readonly TheoryData NotEqualityDataNulls = + // new TheoryData + // { + // // Valid object against null + // { new CieLab(Vector3.One), null, typeof(CieLab) }, + // { new CieLch(Vector3.One), null, typeof(CieLch) }, + // { new CieLchuv(Vector3.One), null, typeof(CieLchuv) }, + // { 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) }, + // { new Lms(Vector3.One), null, typeof(Lms) }, + // { new LinearRgb(Vector3.One), null, typeof(LinearRgb) }, + // { new Rgb(Vector3.One), null, typeof(Rgb) }, + // { new Hsl(Vector3.One), null, typeof(Hsl) }, + // { new Hsv(Vector3.One), null, typeof(Hsv) }, + // { new YCbCr(Vector3.One), null, typeof(YCbCr) }, + // }; + + //public static readonly TheoryData NotEqualityDataDifferentObjects = + // new TheoryData + // { + // // Valid objects of different types but not equal + // { new CieLab(Vector3.One), new CieLch(Vector3.Zero), null }, + // { new CieLuv(Vector3.One), new CieLchuv(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 }, + // { new Cmyk(Vector4.One), new Hsl(Vector3.Zero), null }, + // { new YCbCr(Vector3.One), new CieXyy(Vector3.Zero), null }, + // { new Hsv(Vector3.One), new Hsl(Vector3.Zero), null }, + // }; + + //public static readonly TheoryData NotEqualityData = + // new TheoryData + // { + // // 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 CieLchuv(Vector3.One), new CieLchuv(Vector3.Zero), typeof(CieLchuv) }, + // { 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) }, + // { new Lms(Vector3.One), new Lms(Vector3.Zero), typeof(Lms) }, + // { new LinearRgb(Vector3.One), new LinearRgb(Vector3.Zero), typeof(LinearRgb) }, + // { new Rgb(Vector3.One), new Rgb(Vector3.Zero), typeof(Rgb) }, + // { new Cmyk(Vector4.One), new Cmyk(Vector4.Zero), typeof(Cmyk) }, + // { new Hsl(Vector3.One), new Hsl(Vector3.Zero), typeof(Hsl) }, + // { new Hsv(Vector3.One), new Hsv(Vector3.Zero), typeof(Hsv) }, + // { new YCbCr(Vector3.One), new YCbCr(Vector3.Zero), typeof(YCbCr) }, + // }; + + //public static readonly TheoryData AlmostEqualsData = + // new TheoryData + // { + // { 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 CieLch(0F, 0F, 0F), new CieLch(0F, .001F, 0F), typeof(CieLch), .001F }, + // { new CieLchuv(0F, 0F, 0F), new CieLchuv(0F, .001F, 0F), typeof(CieLchuv), .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 }, + // { new CieXyz(380F, 380F, 380F), new CieXyz(380F, 380F, 380.001F), typeof(CieXyz), .01F }, + // { new Cmyk(1, 1, 1, 1), new Cmyk(1, 1, 1, .99F), typeof(Cmyk), .01F }, + // { new YCbCr(255F, 128F, 128F), new YCbCr(255F, 128F, 128.001F), typeof(YCbCr), .01F }, + // { new Hsv(0F, 0F, 0F), new Hsv(0F, 0F, 0F), typeof(Hsv), 0F }, + // { new Hsl(0F, 0F, 0F), new Hsl(0F, 0F, 0F), typeof(Hsl), 0F }, + // }; + + //public static readonly TheoryData AlmostNotEqualsData = + // new TheoryData + // { + // { 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 }, + // }; + + //[Theory] + //[MemberData(nameof(EmptyData))] + //public void Vector_Equals_WhenTrue(string color) + //{ + // IColorVector colorVector = EmptyDataLookup[color]; + // // Act + // bool equal = colorVector.Vector.Equals(Vector3.Zero); + + // // Assert + // Assert.True(equal); + //} + //[Theory] //[MemberData(nameof(EqualityData))] - //public void EqualityOperator(object first, object second, Type type) + //public void Equals_WhenTrue(object first, object second, Type type) + //{ + // // Act + // bool equal = first.Equals(second); + + // // Assert + // Assert.True(equal); + //} + + //[Theory] + //[MemberData(nameof(NotEqualityDataNulls))] + //[MemberData(nameof(NotEqualityDataDifferentObjects))] + //[MemberData(nameof(NotEqualityData))] + //public void Equals_WhenFalse(object first, object second, Type type) + //{ + // // Act + // bool equal = first.Equals(second); + + // // Assert + // Assert.False(equal); + //} + + //[Theory] + //[MemberData(nameof(EqualityData))] + //public void GetHashCode_WhenEqual(object first, object second, Type type) + //{ + // // Act + // bool equal = first.GetHashCode() == second.GetHashCode(); + + // // Assert + // Assert.True(equal); + //} + + //[Theory] + //[MemberData(nameof(NotEqualityDataDifferentObjects))] + //public void GetHashCode_WhenNotEqual(object first, object second, Type type) + //{ + // // Act + // bool equal = first.GetHashCode() == second.GetHashCode(); + + // // Assert + // Assert.False(equal); + //} + + //[Theory] + //[MemberData(nameof(EqualityData))] + //public void GenericEquals_WhenTrue(object first, object second, Type type) //{ // // Arrange // // Cast to the known object types, this is so that we can hit the @@ -248,34 +211,15 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces // dynamic secondObject = Convert.ChangeType(second, type); // // Act - // dynamic equal = firstObject == secondObject; + // dynamic equal = firstObject.Equals(secondObject); // // Assert // Assert.True(equal); //} - [Theory] - [MemberData(nameof(NotEqualityData))] - public void Operator_WhenTrue(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 :) - dynamic firstObject = Convert.ChangeType(first, type); - dynamic secondObject = Convert.ChangeType(second, type); - - // Act - dynamic notEqual = firstObject != secondObject; - - // Assert - Assert.True(notEqual); - } - - // TODO:Disabled due to RuntypeBinder errors while structs are internal //[Theory] - //[MemberData(nameof(AlmostEqualsData))] - //public void AlmostEquals(object first, object second, Type type, float precision) + //[MemberData(nameof(NotEqualityData))] + //public void GenericEquals_WhenFalse(object first, object second, Type type) //{ // // Arrange // // Cast to the known object types, this is so that we can hit the @@ -285,16 +229,34 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces // dynamic secondObject = Convert.ChangeType(second, type); // // Act - // dynamic almostEqual = firstObject.AlmostEquals(secondObject, precision); + // dynamic equal = firstObject.Equals(secondObject); // // Assert - // Assert.True(almostEqual); + // Assert.False(equal); //} - // TODO:Disabled due to RuntypeBinder errors while structs are internal + //// TODO:Disabled due to RuntypeBinder errors while structs are internal + ////[Theory] + ////[MemberData(nameof(EqualityData))] + ////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 :) + //// dynamic firstObject = Convert.ChangeType(first, type); + //// dynamic secondObject = Convert.ChangeType(second, type); + + //// // Act + //// dynamic equal = firstObject == secondObject; + + //// // Assert + //// Assert.True(equal); + ////} + //[Theory] - //[MemberData(nameof(AlmostNotEqualsData))] - //public void AlmostNotEquals(object first, object second, Type type, float precision) + //[MemberData(nameof(NotEqualityData))] + //public void Operator_WhenTrue(object first, object second, Type type) //{ // // Arrange // // Cast to the known object types, this is so that we can hit the @@ -304,10 +266,48 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces // dynamic secondObject = Convert.ChangeType(second, type); // // Act - // dynamic almostEqual = firstObject.AlmostEquals(secondObject, precision); + // dynamic notEqual = firstObject != secondObject; // // Assert - // Assert.False(almostEqual); + // Assert.True(notEqual); //} + + //// TODO:Disabled due to RuntypeBinder errors while structs are internal + ////[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); + ////} + + //// TODO:Disabled due to RuntypeBinder errors while structs are internal + ////[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); + ////} } }