From ff752a22b80638396287bb5c68637b72c5c73f61 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Wed, 22 May 2024 19:34:53 +1000 Subject: [PATCH] Sequential layout plus faster equality checks. --- src/ImageSharp/ColorProfiles/CieLab.cs | 32 ++++++++------- src/ImageSharp/ColorProfiles/CieLch.cs | 36 +++++++++-------- src/ImageSharp/ColorProfiles/CieLchuv.cs | 24 ++---------- src/ImageSharp/ColorProfiles/CieLuv.cs | 6 ++- .../CieXyChromaticityCoordinates.cs | 7 +++- src/ImageSharp/ColorProfiles/CieXyy.cs | 6 ++- src/ImageSharp/ColorProfiles/CieXyz.cs | 32 ++++++++------- src/ImageSharp/ColorProfiles/Cmyk.cs | 6 ++- src/ImageSharp/ColorProfiles/Hsl.cs | 6 ++- src/ImageSharp/ColorProfiles/Hsv.cs | 6 ++- src/ImageSharp/ColorProfiles/HunterLab.cs | 6 ++- src/ImageSharp/ColorProfiles/Lms.cs | 39 ++++++++++++------- src/ImageSharp/ColorProfiles/Rgb.cs | 32 ++++++++------- src/ImageSharp/ColorProfiles/YCbCr.cs | 6 ++- 14 files changed, 142 insertions(+), 102 deletions(-) diff --git a/src/ImageSharp/ColorProfiles/CieLab.cs b/src/ImageSharp/ColorProfiles/CieLab.cs index 82d60f4da..377cc20a9 100644 --- a/src/ImageSharp/ColorProfiles/CieLab.cs +++ b/src/ImageSharp/ColorProfiles/CieLab.cs @@ -3,6 +3,7 @@ using System.Numerics; using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; namespace SixLabors.ImageSharp.ColorProfiles; @@ -10,6 +11,7 @@ namespace SixLabors.ImageSharp.ColorProfiles; /// Represents a CIE L*a*b* 1976 color. /// /// +[StructLayout(LayoutKind.Sequential)] public readonly struct CieLab : IProfileConnectingSpace { /// @@ -80,20 +82,6 @@ public readonly struct CieLab : IProfileConnectingSpace [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(CieLab left, CieLab right) => !left.Equals(right); - /// - public override int GetHashCode() => HashCode.Combine(this.L, this.A, this.B); - - /// - public override string ToString() => FormattableString.Invariant($"CieLab({this.L:#0.##}, {this.A:#0.##}, {this.B:#0.##})"); - - /// - public override bool Equals(object? obj) => obj is CieLab other && this.Equals(other); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Equals(CieLab other) - => new Vector3(this.L, this.A, this.B) == new Vector3(other.L, other.A, other.B); - /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static CieLab FromProfileConnectingSpace(ColorConversionOptions options, in CieXyz source) @@ -171,4 +159,20 @@ public readonly struct CieLab : IProfileConnectingSpace /// public static ChromaticAdaptionWhitePointSource GetChromaticAdaptionWhitePointSource() => ChromaticAdaptionWhitePointSource.WhitePoint; + + /// + public override int GetHashCode() => HashCode.Combine(this.L, this.A, this.B); + + /// + public override string ToString() => FormattableString.Invariant($"CieLab({this.L:#0.##}, {this.A:#0.##}, {this.B:#0.##})"); + + /// + public override bool Equals(object? obj) => obj is CieLab other && this.Equals(other); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool Equals(CieLab other) + => this.AsVector3Unsafe() == other.AsVector3Unsafe(); + + private Vector3 AsVector3Unsafe() => Unsafe.As(ref Unsafe.AsRef(in this)); } diff --git a/src/ImageSharp/ColorProfiles/CieLch.cs b/src/ImageSharp/ColorProfiles/CieLch.cs index 8f6298a2d..131978340 100644 --- a/src/ImageSharp/ColorProfiles/CieLch.cs +++ b/src/ImageSharp/ColorProfiles/CieLch.cs @@ -3,6 +3,7 @@ using System.Numerics; using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; namespace SixLabors.ImageSharp.ColorProfiles; @@ -10,6 +11,7 @@ namespace SixLabors.ImageSharp.ColorProfiles; /// Represents the CIE L*C*h°, cylindrical form of the CIE L*a*b* 1976 color. /// /// +[StructLayout(LayoutKind.Sequential)] public readonly struct CieLch : IColorProfile { private static readonly Vector3 Min = new(0, -200, 0); @@ -80,22 +82,6 @@ public readonly struct CieLch : IColorProfile [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(CieLch left, CieLch right) => !left.Equals(right); - /// - public override int GetHashCode() - => HashCode.Combine(this.L, this.C, this.H); - - /// - public override string ToString() => FormattableString.Invariant($"CieLch({this.L:#0.##}, {this.C:#0.##}, {this.H:#0.##})"); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public override bool Equals(object? obj) => obj is CieLch other && this.Equals(other); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Equals(CieLch other) - => new Vector3(this.L, this.C, this.H) == new Vector3(other.L, other.C, other.H); - /// public static CieLch FromProfileConnectingSpace(ColorConversionOptions options, in CieLab source) { @@ -159,4 +145,22 @@ public readonly struct CieLch : IColorProfile /// public static ChromaticAdaptionWhitePointSource GetChromaticAdaptionWhitePointSource() => ChromaticAdaptionWhitePointSource.WhitePoint; + + /// + public override int GetHashCode() + => HashCode.Combine(this.L, this.C, this.H); + + /// + public override string ToString() => FormattableString.Invariant($"CieLch({this.L:#0.##}, {this.C:#0.##}, {this.H:#0.##})"); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public override bool Equals(object? obj) => obj is CieLch other && this.Equals(other); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool Equals(CieLch other) + => this.AsVector3Unsafe() == other.AsVector3Unsafe(); + + private Vector3 AsVector3Unsafe() => Unsafe.As(ref Unsafe.AsRef(in this)); } diff --git a/src/ImageSharp/ColorProfiles/CieLchuv.cs b/src/ImageSharp/ColorProfiles/CieLchuv.cs index e537259e4..7fd95feb1 100644 --- a/src/ImageSharp/ColorProfiles/CieLchuv.cs +++ b/src/ImageSharp/ColorProfiles/CieLchuv.cs @@ -3,6 +3,7 @@ using System.Numerics; using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; namespace SixLabors.ImageSharp.ColorProfiles; @@ -10,6 +11,7 @@ namespace SixLabors.ImageSharp.ColorProfiles; /// Represents the CIE L*C*h°, cylindrical form of the CIE L*u*v* 1976 color. /// /// +[StructLayout(LayoutKind.Sequential)] public readonly struct CieLchuv : IColorProfile { private static readonly Vector3 Min = new(0, -200, 0); @@ -159,25 +161,7 @@ public readonly struct CieLchuv : IColorProfile /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool Equals(CieLchuv other) - => new Vector3(this.L, this.C, this.H) == new Vector3(other.L, other.C, other.H); + => this.AsVector3Unsafe() == other.AsVector3Unsafe(); - /// - /// Computes the saturation of the color (chroma normalized by lightness) - /// - /// - /// A value ranging from 0 to 100. - /// - /// The - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public float Saturation() - { - float result = 100 * (this.C / this.L); - - if (float.IsNaN(result)) - { - return 0; - } - - return result; - } + private Vector3 AsVector3Unsafe() => Unsafe.As(ref Unsafe.AsRef(in this)); } diff --git a/src/ImageSharp/ColorProfiles/CieLuv.cs b/src/ImageSharp/ColorProfiles/CieLuv.cs index 118d32f04..97e2826f7 100644 --- a/src/ImageSharp/ColorProfiles/CieLuv.cs +++ b/src/ImageSharp/ColorProfiles/CieLuv.cs @@ -3,6 +3,7 @@ using System.Numerics; using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; namespace SixLabors.ImageSharp.ColorProfiles; @@ -12,6 +13,7 @@ namespace SixLabors.ImageSharp.ColorProfiles; /// attempted perceptual uniformity /// /// +[StructLayout(LayoutKind.Sequential)] public readonly struct CieLuv : IColorProfile { /// @@ -205,7 +207,9 @@ public readonly struct CieLuv : IColorProfile /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool Equals(CieLuv other) - => new Vector3(this.L, this.U, this.V) == new Vector3(other.L, other.U, other.V); + => this.AsVector3Unsafe() == other.AsVector3Unsafe(); + + private Vector3 AsVector3Unsafe() => Unsafe.As(ref Unsafe.AsRef(in this)); [MethodImpl(MethodImplOptions.AggressiveInlining)] private static double ComputeU(in CieXyz source) diff --git a/src/ImageSharp/ColorProfiles/CieXyChromaticityCoordinates.cs b/src/ImageSharp/ColorProfiles/CieXyChromaticityCoordinates.cs index aad7dbf95..fa12b81d2 100644 --- a/src/ImageSharp/ColorProfiles/CieXyChromaticityCoordinates.cs +++ b/src/ImageSharp/ColorProfiles/CieXyChromaticityCoordinates.cs @@ -3,13 +3,14 @@ using System.Numerics; using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; -// ReSharper disable CompareOfFloatsByEqualityOperator namespace SixLabors.ImageSharp.ColorProfiles; /// /// Represents the coordinates of CIEXY chromaticity space. /// +[StructLayout(LayoutKind.Sequential)] public readonly struct CieXyChromaticityCoordinates : IEquatable { /// @@ -80,5 +81,7 @@ public readonly struct CieXyChromaticityCoordinates : IEquatable [MethodImpl(InliningOptions.ShortMethod)] public bool Equals(CieXyChromaticityCoordinates other) - => new Vector2(this.X, this.Y) == new Vector2(other.X, other.Y); + => this.AsVector2Unsafe() == other.AsVector2Unsafe(); + + private Vector2 AsVector2Unsafe() => Unsafe.As(ref Unsafe.AsRef(in this)); } diff --git a/src/ImageSharp/ColorProfiles/CieXyy.cs b/src/ImageSharp/ColorProfiles/CieXyy.cs index ea19f5740..62873df14 100644 --- a/src/ImageSharp/ColorProfiles/CieXyy.cs +++ b/src/ImageSharp/ColorProfiles/CieXyy.cs @@ -3,6 +3,7 @@ using System.Numerics; using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; namespace SixLabors.ImageSharp.ColorProfiles; @@ -10,6 +11,7 @@ namespace SixLabors.ImageSharp.ColorProfiles; /// Represents an CIE xyY 1931 color /// /// +[StructLayout(LayoutKind.Sequential)] public readonly struct CieXyy : IColorProfile { /// @@ -150,5 +152,7 @@ public readonly struct CieXyy : IColorProfile /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool Equals(CieXyy other) - => new Vector3(this.X, this.Y, this.Yl) == new Vector3(other.X, other.Y, other.Yl); + => this.AsVector3Unsafe() == other.AsVector3Unsafe(); + + private Vector3 AsVector3Unsafe() => Unsafe.As(ref Unsafe.AsRef(in this)); } diff --git a/src/ImageSharp/ColorProfiles/CieXyz.cs b/src/ImageSharp/ColorProfiles/CieXyz.cs index fe8755454..07f9b47f9 100644 --- a/src/ImageSharp/ColorProfiles/CieXyz.cs +++ b/src/ImageSharp/ColorProfiles/CieXyz.cs @@ -3,6 +3,7 @@ using System.Numerics; using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; namespace SixLabors.ImageSharp.ColorProfiles; @@ -10,6 +11,7 @@ namespace SixLabors.ImageSharp.ColorProfiles; /// Represents an CIE XYZ 1931 color /// /// +[StructLayout(LayoutKind.Sequential)] public readonly struct CieXyz : IProfileConnectingSpace { /// @@ -86,20 +88,6 @@ public readonly struct CieXyz : IProfileConnectingSpace [MethodImpl(MethodImplOptions.AggressiveInlining)] public Vector3 ToVector3() => new(this.X, this.Y, this.Z); - /// - public override int GetHashCode() => HashCode.Combine(this.X, this.Y, this.Z); - - /// - public override string ToString() => FormattableString.Invariant($"CieXyz({this.X:#0.##}, {this.Y:#0.##}, {this.Z:#0.##})"); - - /// - public override bool Equals(object? obj) => obj is CieXyz other && this.Equals(other); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Equals(CieXyz other) - => new Vector3(this.X, this.Y, this.Z) == new Vector3(other.X, other.Y, other.Z); - /// public static CieXyz FromProfileConnectingSpace(ColorConversionOptions options, in CieXyz source) => new(source.X, source.Y, source.Z); @@ -124,4 +112,20 @@ public readonly struct CieXyz : IProfileConnectingSpace /// public static ChromaticAdaptionWhitePointSource GetChromaticAdaptionWhitePointSource() => ChromaticAdaptionWhitePointSource.WhitePoint; + + /// + public override int GetHashCode() => HashCode.Combine(this.X, this.Y, this.Z); + + /// + public override string ToString() => FormattableString.Invariant($"CieXyz({this.X:#0.##}, {this.Y:#0.##}, {this.Z:#0.##})"); + + /// + public override bool Equals(object? obj) => obj is CieXyz other && this.Equals(other); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool Equals(CieXyz other) + => this.AsVector3Unsafe() == other.AsVector3Unsafe(); + + private Vector3 AsVector3Unsafe() => Unsafe.As(ref Unsafe.AsRef(in this)); } diff --git a/src/ImageSharp/ColorProfiles/Cmyk.cs b/src/ImageSharp/ColorProfiles/Cmyk.cs index 88d3249b3..e92490449 100644 --- a/src/ImageSharp/ColorProfiles/Cmyk.cs +++ b/src/ImageSharp/ColorProfiles/Cmyk.cs @@ -3,12 +3,14 @@ using System.Numerics; using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; namespace SixLabors.ImageSharp.ColorProfiles; /// /// Represents an CMYK (cyan, magenta, yellow, keyline) color. /// +[StructLayout(LayoutKind.Sequential)] public readonly struct Cmyk : IColorProfile { private static readonly Vector4 Min = Vector4.Zero; @@ -157,5 +159,7 @@ public readonly struct Cmyk : IColorProfile /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool Equals(Cmyk other) - => new Vector4(this.C, this.M, this.Y, this.K) == new Vector4(other.C, other.M, other.Y, other.K); + => this.AsVector4Unsafe() == other.AsVector4Unsafe(); + + private Vector4 AsVector4Unsafe() => Unsafe.As(ref Unsafe.AsRef(in this)); } diff --git a/src/ImageSharp/ColorProfiles/Hsl.cs b/src/ImageSharp/ColorProfiles/Hsl.cs index c7ae97c79..2c98c7df9 100644 --- a/src/ImageSharp/ColorProfiles/Hsl.cs +++ b/src/ImageSharp/ColorProfiles/Hsl.cs @@ -3,12 +3,14 @@ using System.Numerics; using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; namespace SixLabors.ImageSharp.ColorProfiles; /// /// Represents a Hsl (hue, saturation, lightness) color. /// +[StructLayout(LayoutKind.Sequential)] public readonly struct Hsl : IColorProfile { private static readonly Vector3 Min = Vector3.Zero; @@ -200,7 +202,9 @@ public readonly struct Hsl : IColorProfile /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool Equals(Hsl other) - => new Vector3(this.H, this.S, this.L) == new Vector3(other.H, other.S, other.L); + => this.AsVector3Unsafe() == other.AsVector3Unsafe(); + + private Vector3 AsVector3Unsafe() => Unsafe.As(ref Unsafe.AsRef(in this)); [MethodImpl(MethodImplOptions.AggressiveInlining)] private static float GetColorComponent(float first, float second, float third) diff --git a/src/ImageSharp/ColorProfiles/Hsv.cs b/src/ImageSharp/ColorProfiles/Hsv.cs index 83445a40f..7535f2463 100644 --- a/src/ImageSharp/ColorProfiles/Hsv.cs +++ b/src/ImageSharp/ColorProfiles/Hsv.cs @@ -3,12 +3,14 @@ using System.Numerics; using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; namespace SixLabors.ImageSharp.ColorProfiles; /// /// Represents a HSV (hue, saturation, value) color. Also known as HSB (hue, saturation, brightness). /// +[StructLayout(LayoutKind.Sequential)] public readonly struct Hsv : IColorProfile { private static readonly Vector3 Min = Vector3.Zero; @@ -223,5 +225,7 @@ public readonly struct Hsv : IColorProfile /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool Equals(Hsv other) - => new Vector3(this.H, this.S, this.V) == new Vector3(other.H, other.S, other.V); + => this.AsVector3Unsafe() == other.AsVector3Unsafe(); + + private Vector3 AsVector3Unsafe() => Unsafe.As(ref Unsafe.AsRef(in this)); } diff --git a/src/ImageSharp/ColorProfiles/HunterLab.cs b/src/ImageSharp/ColorProfiles/HunterLab.cs index eb33e6a95..43ad2ac5c 100644 --- a/src/ImageSharp/ColorProfiles/HunterLab.cs +++ b/src/ImageSharp/ColorProfiles/HunterLab.cs @@ -3,6 +3,7 @@ using System.Numerics; using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; namespace SixLabors.ImageSharp.ColorProfiles; @@ -10,6 +11,7 @@ namespace SixLabors.ImageSharp.ColorProfiles; /// Represents an Hunter LAB color. /// . /// +[StructLayout(LayoutKind.Sequential)] public readonly struct HunterLab : IColorProfile { /// @@ -170,7 +172,9 @@ public readonly struct HunterLab : IColorProfile /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool Equals(HunterLab other) - => new Vector3(this.L, this.A, this.B) == new Vector3(other.L, other.A, other.B); + => this.AsVector3Unsafe() == other.AsVector3Unsafe(); + + private Vector3 AsVector3Unsafe() => Unsafe.As(ref Unsafe.AsRef(in this)); [MethodImpl(MethodImplOptions.AggressiveInlining)] private static float ComputeKa(in CieXyz whitePoint) diff --git a/src/ImageSharp/ColorProfiles/Lms.cs b/src/ImageSharp/ColorProfiles/Lms.cs index 03a1c5d66..5a6791b2d 100644 --- a/src/ImageSharp/ColorProfiles/Lms.cs +++ b/src/ImageSharp/ColorProfiles/Lms.cs @@ -3,10 +3,17 @@ using System.Numerics; using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; namespace SixLabors.ImageSharp.ColorProfiles; -internal readonly struct Lms : IColorProfile +/// +/// LMS is a color space represented by the response of the three types of cones of the human eye, +/// named after their responsivity (sensitivity) at long, medium and short wavelengths. +/// +/// +[StructLayout(LayoutKind.Sequential)] +public readonly struct Lms : IColorProfile { /// /// Initializes a new instance of the struct. @@ -82,20 +89,6 @@ internal readonly struct Lms : IColorProfile [MethodImpl(MethodImplOptions.AggressiveInlining)] public Vector3 ToVector3() => new(this.L, this.M, this.S); - /// - public override int GetHashCode() => HashCode.Combine(this.L, this.M, this.S); - - /// - public override string ToString() => FormattableString.Invariant($"Lms({this.L:#0.##}, {this.M:#0.##}, {this.S:#0.##})"); - - /// - public override bool Equals(object? obj) => obj is Lms other && this.Equals(other); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Equals(Lms other) - => new Vector3(this.L, this.M, this.S) == new Vector3(other.L, other.M, other.S); - /// public static Lms FromProfileConnectingSpace(ColorConversionOptions options, in CieXyz source) { @@ -136,4 +129,20 @@ internal readonly struct Lms : IColorProfile /// public static ChromaticAdaptionWhitePointSource GetChromaticAdaptionWhitePointSource() => ChromaticAdaptionWhitePointSource.WhitePoint; + + /// + public override int GetHashCode() => HashCode.Combine(this.L, this.M, this.S); + + /// + public override string ToString() => FormattableString.Invariant($"Lms({this.L:#0.##}, {this.M:#0.##}, {this.S:#0.##})"); + + /// + public override bool Equals(object? obj) => obj is Lms other && this.Equals(other); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool Equals(Lms other) + => this.AsVector3Unsafe() == other.AsVector3Unsafe(); + + private Vector3 AsVector3Unsafe() => Unsafe.As(ref Unsafe.AsRef(in this)); } diff --git a/src/ImageSharp/ColorProfiles/Rgb.cs b/src/ImageSharp/ColorProfiles/Rgb.cs index 8036d83e5..664f9d80f 100644 --- a/src/ImageSharp/ColorProfiles/Rgb.cs +++ b/src/ImageSharp/ColorProfiles/Rgb.cs @@ -3,6 +3,7 @@ using System.Numerics; using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; using SixLabors.ImageSharp.ColorProfiles.WorkingSpaces; namespace SixLabors.ImageSharp.ColorProfiles; @@ -10,6 +11,7 @@ namespace SixLabors.ImageSharp.ColorProfiles; /// /// Represents an RGB (red, green, blue) color profile. /// +[StructLayout(LayoutKind.Sequential)] public readonly struct Rgb : IProfileConnectingSpace { /// @@ -79,20 +81,6 @@ public readonly struct Rgb : IProfileConnectingSpace [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(Rgb left, Rgb right) => !left.Equals(right); - /// - public override int GetHashCode() => HashCode.Combine(this.R, this.G, this.B); - - /// - public override string ToString() => FormattableString.Invariant($"Rgb({this.R:#0.##}, {this.G:#0.##}, {this.B:#0.##})"); - - /// - public override bool Equals(object? obj) => obj is Rgb other && this.Equals(other); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Equals(Rgb other) - => new Vector3(this.R, this.G, this.B) == new Vector3(other.R, other.G, other.B); - /// public static Rgb FromProfileConnectingSpace(ColorConversionOptions options, in CieXyz source) { @@ -201,6 +189,22 @@ public readonly struct Rgb : IProfileConnectingSpace [MethodImpl(MethodImplOptions.AggressiveInlining)] public Vector4 ToScaledVector4() => new(this.ToScaledVector3(), 1f); + /// + public override int GetHashCode() => HashCode.Combine(this.R, this.G, this.B); + + /// + public override string ToString() => FormattableString.Invariant($"Rgb({this.R:#0.##}, {this.G:#0.##}, {this.B:#0.##})"); + + /// + public override bool Equals(object? obj) => obj is Rgb other && this.Equals(other); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool Equals(Rgb other) + => this.AsVector3Unsafe() == other.AsVector3Unsafe(); + + private Vector3 AsVector3Unsafe() => Unsafe.As(ref Unsafe.AsRef(in this)); + private static Matrix4x4 GetCieXyzToRgbMatrix(RgbWorkingSpace workingSpace) { Matrix4x4 matrix = GetRgbToCieXyzMatrix(workingSpace); diff --git a/src/ImageSharp/ColorProfiles/YCbCr.cs b/src/ImageSharp/ColorProfiles/YCbCr.cs index b9f5f65ee..03bd1d312 100644 --- a/src/ImageSharp/ColorProfiles/YCbCr.cs +++ b/src/ImageSharp/ColorProfiles/YCbCr.cs @@ -3,6 +3,7 @@ using System.Numerics; using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; namespace SixLabors.ImageSharp.ColorProfiles; @@ -11,6 +12,7 @@ namespace SixLabors.ImageSharp.ColorProfiles; /// /// /// +[StructLayout(LayoutKind.Sequential)] public readonly struct YCbCr : IColorProfile { private static readonly Vector3 Min = Vector3.Zero; @@ -152,5 +154,7 @@ public readonly struct YCbCr : IColorProfile /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool Equals(YCbCr other) - => new Vector3(this.Y, this.Cb, this.Cr) == new Vector3(other.Y, other.Cb, other.Cr); + => this.AsVector3Unsafe() == other.AsVector3Unsafe(); + + private Vector3 AsVector3Unsafe() => Unsafe.As(ref Unsafe.AsRef(in this)); }