diff --git a/src/ImageSharp/ColorProfiles/ChromaticAdaptionWhitePointSource.cs b/src/ImageSharp/ColorProfiles/ChromaticAdaptionWhitePointSource.cs new file mode 100644 index 0000000000..7e4a9c413b --- /dev/null +++ b/src/ImageSharp/ColorProfiles/ChromaticAdaptionWhitePointSource.cs @@ -0,0 +1,20 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +namespace SixLabors.ImageSharp.ColorProfiles; + +/// +/// Enumerate the possible sources of the white point used in chromatic adaptation. +/// +public enum ChromaticAdaptionWhitePointSource +{ + /// + /// The white point of the source color space. + /// + WhitePoint, + + /// + /// The white point of the source working space. + /// + RgbWorkingSpace +} diff --git a/src/ImageSharp/ColorSpaces/Conversion/CieConstants.cs b/src/ImageSharp/ColorProfiles/CieConstants.cs similarity index 67% rename from src/ImageSharp/ColorSpaces/Conversion/CieConstants.cs rename to src/ImageSharp/ColorProfiles/CieConstants.cs index 7c87944043..d13a84450f 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/CieConstants.cs +++ b/src/ImageSharp/ColorProfiles/CieConstants.cs @@ -1,7 +1,7 @@ -// Copyright (c) Six Labors. +// Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -namespace SixLabors.ImageSharp.ColorSpaces.Conversion; +namespace SixLabors.ImageSharp.ColorProfiles; /// /// Constants use for Cie conversion calculations @@ -12,10 +12,10 @@ internal static class CieConstants /// /// 216F / 24389F /// - public const float Epsilon = 0.008856452F; + public const float Epsilon = 216f / 24389f; /// /// 24389F / 27F /// - public const float Kappa = 903.2963F; + public const float Kappa = 24389f / 27f; } diff --git a/src/ImageSharp/ColorProfiles/CieLab.cs b/src/ImageSharp/ColorProfiles/CieLab.cs new file mode 100644 index 0000000000..377cc20a99 --- /dev/null +++ b/src/ImageSharp/ColorProfiles/CieLab.cs @@ -0,0 +1,178 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using System.Numerics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace SixLabors.ImageSharp.ColorProfiles; + +/// +/// Represents a CIE L*a*b* 1976 color. +/// +/// +[StructLayout(LayoutKind.Sequential)] +public readonly struct CieLab : IProfileConnectingSpace +{ + /// + /// Initializes a new instance of the struct. + /// + /// The lightness dimension. + /// The a (green - magenta) component. + /// The b (blue - yellow) component. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public CieLab(float l, float a, float b) + { + // Not clamping as documentation about this space only indicates "usual" ranges + this.L = l; + this.A = a; + this.B = b; + } + + /// + /// Initializes a new instance of the struct. + /// + /// The vector representing the l, a, b components. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public CieLab(Vector3 vector) + : this() + { + this.L = vector.X; + this.A = vector.Y; + this.B = vector.Z; + } + + /// + /// Gets the lightness dimension. + /// A value usually ranging between 0 (black), 100 (diffuse white) or higher (specular white). + /// + public float L { get; } + + /// + /// Gets the a color component. + /// A value usually ranging from -100 to 100. Negative is green, positive magenta. + /// + public float A { get; } + + /// + /// Gets the b color component. + /// A value usually ranging from -100 to 100. Negative is blue, positive is yellow + /// + public float B { get; } + + /// + /// Compares two objects for equality. + /// + /// 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) => left.Equals(right); + + /// + /// Compares two objects for inequality + /// + /// 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) => !left.Equals(right); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static CieLab FromProfileConnectingSpace(ColorConversionOptions options, in CieXyz source) + { + // Conversion algorithm described here: + // http://www.brucelindbloom.com/index.html?Eqn_XYZ_to_Lab.html + CieXyz whitePoint = options.TargetWhitePoint; + float wx = whitePoint.X, wy = whitePoint.Y, wz = whitePoint.Z; + + float xr = source.X / wx, yr = source.Y / wy, zr = source.Z / wz; + + const float inv116 = 1 / 116F; + + float fx = xr > CieConstants.Epsilon ? MathF.Pow(xr, 0.3333333F) : ((CieConstants.Kappa * xr) + 16F) * inv116; + float fy = yr > CieConstants.Epsilon ? MathF.Pow(yr, 0.3333333F) : ((CieConstants.Kappa * yr) + 16F) * inv116; + float fz = zr > CieConstants.Epsilon ? MathF.Pow(zr, 0.3333333F) : ((CieConstants.Kappa * zr) + 16F) * inv116; + + float l = (116F * fy) - 16F; + float a = 500F * (fx - fy); + float b = 200F * (fy - fz); + + return new CieLab(l, a, b); + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void FromProfileConnectionSpace(ColorConversionOptions options, ReadOnlySpan source, Span destination) + { + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + + for (int i = 0; i < source.Length; i++) + { + CieXyz xyz = source[i]; + destination[i] = FromProfileConnectingSpace(options, in xyz); + } + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public CieXyz ToProfileConnectingSpace(ColorConversionOptions options) + { + // Conversion algorithm described here: http://www.brucelindbloom.com/index.html?Eqn_Lab_to_XYZ.html + float l = this.L, a = this.A, b = this.B; + float fy = (l + 16) / 116F; + float fx = (a / 500F) + fy; + float fz = fy - (b / 200F); + + float fx3 = Numerics.Pow3(fx); + float fz3 = Numerics.Pow3(fz); + + float xr = fx3 > CieConstants.Epsilon ? fx3 : ((116F * fx) - 16F) / CieConstants.Kappa; + float yr = l > CieConstants.Kappa * CieConstants.Epsilon ? Numerics.Pow3((l + 16F) / 116F) : l / CieConstants.Kappa; + float zr = fz3 > CieConstants.Epsilon ? fz3 : ((116F * fz) - 16F) / CieConstants.Kappa; + + CieXyz whitePoint = options.WhitePoint; + Vector3 wxyz = new(whitePoint.X, whitePoint.Y, whitePoint.Z); + Vector3 xyzr = new(xr, yr, zr); + + return new(xyzr * wxyz); + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void ToProfileConnectionSpace(ColorConversionOptions options, ReadOnlySpan source, Span destination) + { + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + + for (int i = 0; i < source.Length; i++) + { + CieLab lab = source[i]; + destination[i] = lab.ToProfileConnectingSpace(options); + } + } + + /// + 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/ColorSpaces/CieLch.cs b/src/ImageSharp/ColorProfiles/CieLch.cs similarity index 50% rename from src/ImageSharp/ColorSpaces/CieLch.cs rename to src/ImageSharp/ColorProfiles/CieLch.cs index 48e8e2c6d9..1319783406 100644 --- a/src/ImageSharp/ColorSpaces/CieLch.cs +++ b/src/ImageSharp/ColorProfiles/CieLch.cs @@ -3,21 +3,17 @@ using System.Numerics; using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; -namespace SixLabors.ImageSharp.ColorSpaces; +namespace SixLabors.ImageSharp.ColorProfiles; /// /// Represents the CIE L*C*h°, cylindrical form of the CIE L*a*b* 1976 color. /// /// -public readonly struct CieLch : IEquatable +[StructLayout(LayoutKind.Sequential)] +public readonly struct CieLch : IColorProfile { - /// - /// D50 standard illuminant. - /// Used when reference white is not specified explicitly. - /// - public static readonly CieXyz DefaultWhitePoint = Illuminants.D50; - private static readonly Vector3 Min = new(0, -200, 0); private static readonly Vector3 Max = new(100, 200, 360); @@ -27,23 +23,9 @@ public readonly struct CieLch : IEquatable /// The lightness dimension. /// The chroma, relative saturation. /// The hue in degrees. - /// Uses as white point. - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public CieLch(float l, float c, float h) - : this(l, c, h, DefaultWhitePoint) - { - } - - /// - /// Initializes a new instance of the struct. - /// - /// The lightness dimension. - /// The chroma, relative saturation. - /// The hue in degrees. - /// The reference white point. - [MethodImpl(InliningOptions.ShortMethod)] - public CieLch(float l, float c, float h, CieXyz whitePoint) - : this(new Vector3(l, c, h), whitePoint) + : this(new Vector3(l, c, h)) { } @@ -51,50 +33,32 @@ public readonly struct CieLch : IEquatable /// Initializes a new instance of the struct. /// /// The vector representing the l, c, h components. - /// Uses as white point. - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public CieLch(Vector3 vector) - : this(vector, DefaultWhitePoint) - { - } - - /// - /// Initializes a new instance of the struct. - /// - /// The vector representing the l, c, h components. - /// The reference white point. - [MethodImpl(InliningOptions.ShortMethod)] - public CieLch(Vector3 vector, CieXyz whitePoint) { vector = Vector3.Clamp(vector, Min, Max); this.L = vector.X; this.C = vector.Y; this.H = vector.Z; - this.WhitePoint = whitePoint; } /// /// Gets the lightness dimension. /// A value ranging between 0 (black), 100 (diffuse white) or higher (specular white). /// - public readonly float L { get; } + public float L { get; } /// /// Gets the a chroma component. /// A value ranging from 0 to 200. /// - public readonly float C { get; } + public float C { get; } /// /// Gets the h° hue component in degrees. /// A value ranging from 0 to 360. /// - public readonly float H { get; } - - /// - /// Gets the reference white point of this color - /// - public readonly CieXyz WhitePoint { get; } + public float H { get; } /// /// Compares two objects for equality. @@ -104,7 +68,7 @@ public readonly struct CieLch : IEquatable /// /// True if the current left is equal to the parameter; otherwise, false. /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(CieLch left, CieLch right) => left.Equals(right); /// @@ -115,45 +79,88 @@ public readonly struct CieLch : IEquatable /// /// True if the current left is unequal to the parameter; otherwise, false. /// - [MethodImpl(InliningOptions.ShortMethod)] + [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, this.WhitePoint); + public static CieLch FromProfileConnectingSpace(ColorConversionOptions options, in CieLab source) + { + // Conversion algorithm described here: + // https://en.wikipedia.org/wiki/Lab_color_space#Cylindrical_representation:_CIELCh_or_CIEHLC + float l = source.L, a = source.A, b = source.B; + float c = MathF.Sqrt((a * a) + (b * b)); + float hRadians = MathF.Atan2(b, a); + float hDegrees = GeometryUtilities.RadianToDegree(hRadians); + + // Wrap the angle round at 360. + hDegrees %= 360; + + // Make sure it's not negative. + while (hDegrees < 0) + { + hDegrees += 360; + } - /// - public override string ToString() => FormattableString.Invariant($"CieLch({this.L:#0.##}, {this.C:#0.##}, {this.H:#0.##})"); + return new CieLch(l, c, hDegrees); + } /// - [MethodImpl(InliningOptions.ShortMethod)] - public override bool Equals(object? obj) => obj is CieLch other && this.Equals(other); + public static void FromProfileConnectionSpace(ColorConversionOptions options, ReadOnlySpan source, Span destination) + { + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + + for (int i = 0; i < source.Length; i++) + { + CieLab lab = source[i]; + destination[i] = FromProfileConnectingSpace(options, in lab); + } + } /// - [MethodImpl(InliningOptions.ShortMethod)] - public bool Equals(CieLch other) - => this.L.Equals(other.L) - && this.C.Equals(other.C) - && this.H.Equals(other.H) - && this.WhitePoint.Equals(other.WhitePoint); + public CieLab ToProfileConnectingSpace(ColorConversionOptions options) + { + // Conversion algorithm described here: + // https://en.wikipedia.org/wiki/Lab_color_space#Cylindrical_representation:_CIELCh_or_CIEHLC + float l = this.L, c = this.C, hDegrees = this.H; + float hRadians = GeometryUtilities.DegreeToRadian(hDegrees); - /// - /// Computes the saturation of the color (chroma normalized by lightness) - /// - /// - /// A value ranging from 0 to 100. - /// - /// The - [MethodImpl(InliningOptions.ShortMethod)] - public float Saturation() + float a = c * MathF.Cos(hRadians); + float b = c * MathF.Sin(hRadians); + + return new CieLab(l, a, b); + } + + /// + public static void ToProfileConnectionSpace(ColorConversionOptions options, ReadOnlySpan source, Span destination) { - float result = 100 * (this.C / this.L); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - if (float.IsNaN(result)) + for (int i = 0; i < source.Length; i++) { - return 0; + CieLch lch = source[i]; + destination[i] = lch.ToProfileConnectingSpace(options); } - - return result; } + + /// + 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 new file mode 100644 index 0000000000..7fd95feb19 --- /dev/null +++ b/src/ImageSharp/ColorProfiles/CieLchuv.cs @@ -0,0 +1,167 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using System.Numerics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +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); + private static readonly Vector3 Max = new(100, 200, 360); + + /// + /// Initializes a new instance of the struct. + /// + /// The lightness dimension. + /// The chroma, relative saturation. + /// The hue in degrees. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public CieLchuv(float l, float c, float h) + : this(new Vector3(l, c, h)) + { + } + + /// + /// Initializes a new instance of the struct. + /// + /// The vector representing the l, c, h components. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public CieLchuv(Vector3 vector) + : this() + { + vector = Vector3.Clamp(vector, Min, Max); + this.L = vector.X; + this.C = vector.Y; + this.H = vector.Z; + } + + /// + /// Gets the lightness dimension. + /// A value ranging between 0 (black), 100 (diffuse white) or higher (specular white). + /// + public float L { get; } + + /// + /// Gets the a chroma component. + /// A value ranging from 0 to 200. + /// + public float C { get; } + + /// + /// Gets the h° hue component in degrees. + /// A value ranging from 0 to 360. + /// + public float H { get; } + + /// + /// Compares two objects for equality. + /// + /// 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) => left.Equals(right); + + /// + /// Compares two objects for inequality + /// + /// 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) => !left.Equals(right); + + /// + public static CieLchuv FromProfileConnectingSpace(ColorConversionOptions options, in CieXyz source) + { + CieLuv luv = CieLuv.FromProfileConnectingSpace(options, source); + + // Conversion algorithm described here: + // https://en.wikipedia.org/wiki/CIELUV#Cylindrical_representation_.28CIELCH.29 + float l = luv.L, u = luv.U, v = luv.V; + float c = MathF.Sqrt((u * u) + (v * v)); + float hRadians = MathF.Atan2(v, u); + float hDegrees = GeometryUtilities.RadianToDegree(hRadians); + + // Wrap the angle round at 360. + hDegrees %= 360; + + // Make sure it's not negative. + while (hDegrees < 0) + { + hDegrees += 360; + } + + return new CieLchuv(l, c, hDegrees); + } + + /// + public static void FromProfileConnectionSpace(ColorConversionOptions options, ReadOnlySpan source, Span destination) + { + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + for (int i = 0; i < source.Length; i++) + { + CieXyz xyz = source[i]; + destination[i] = FromProfileConnectingSpace(options, in xyz); + } + } + + /// + public CieXyz ToProfileConnectingSpace(ColorConversionOptions options) + { + // Conversion algorithm described here: + // https://en.wikipedia.org/wiki/CIELUV#Cylindrical_representation_.28CIELCH.29 + float l = this.L, c = this.C, hDegrees = this.H; + float hRadians = GeometryUtilities.DegreeToRadian(hDegrees); + + float u = c * MathF.Cos(hRadians); + float v = c * MathF.Sin(hRadians); + + CieLuv luv = new(l, u, v); + return luv.ToProfileConnectingSpace(options); + } + + /// + public static void ToProfileConnectionSpace(ColorConversionOptions options, ReadOnlySpan source, Span destination) + { + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + for (int i = 0; i < source.Length; i++) + { + CieLchuv lch = source[i]; + destination[i] = lch.ToProfileConnectingSpace(options); + } + } + + /// + public static ChromaticAdaptionWhitePointSource GetChromaticAdaptionWhitePointSource() + => ChromaticAdaptionWhitePointSource.WhitePoint; + + /// + public override int GetHashCode() + => HashCode.Combine(this.L, this.C, this.H); + + /// + public override string ToString() + => FormattableString.Invariant($"CieLchuv({this.L:#0.##}, {this.C:#0.##}, {this.H:#0.##})"); + + /// + public override bool Equals(object? obj) + => obj is CieLchuv other && this.Equals(other); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool Equals(CieLchuv other) + => this.AsVector3Unsafe() == other.AsVector3Unsafe(); + + private Vector3 AsVector3Unsafe() => Unsafe.As(ref Unsafe.AsRef(in this)); +} diff --git a/src/ImageSharp/ColorProfiles/CieLuv.cs b/src/ImageSharp/ColorProfiles/CieLuv.cs new file mode 100644 index 0000000000..97e2826f74 --- /dev/null +++ b/src/ImageSharp/ColorProfiles/CieLuv.cs @@ -0,0 +1,221 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using System.Numerics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace SixLabors.ImageSharp.ColorProfiles; + +/// +/// The CIE 1976 (L*, u*, v*) color space, commonly known by its abbreviation CIELUV, is a color space adopted by the International +/// Commission on Illumination (CIE) in 1976, as a simple-to-compute transformation of the 1931 CIE XYZ color space, but which +/// attempted perceptual uniformity +/// +/// +[StructLayout(LayoutKind.Sequential)] +public readonly struct CieLuv : IColorProfile +{ + /// + /// Initializes a new instance of the struct. + /// + /// The lightness dimension. + /// The blue-yellow chromaticity coordinate of the given white point. + /// The red-green chromaticity coordinate of the given white point. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public CieLuv(float l, float u, float v) + { + // Not clamping as documentation about this space only indicates "usual" ranges + this.L = l; + this.U = u; + this.V = v; + } + + /// + /// Initializes a new instance of the struct. + /// + /// The vector representing the l, u, v components. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public CieLuv(Vector3 vector) + : this() + { + this.L = vector.X; + this.U = vector.Y; + this.V = vector.Z; + } + + /// + /// Gets the lightness dimension + /// A value usually ranging between 0 and 100. + /// + public float L { get; } + + /// + /// Gets the blue-yellow chromaticity coordinate of the given white point. + /// A value usually ranging between -100 and 100. + /// + public float U { get; } + + /// + /// Gets the red-green chromaticity coordinate of the given white point. + /// A value usually ranging between -100 and 100. + /// + public float V { get; } + + /// + /// Compares two objects for equality. + /// + /// 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) => left.Equals(right); + + /// + /// Compares two objects for inequality. + /// + /// 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) => !left.Equals(right); + + /// + public static CieLuv FromProfileConnectingSpace(ColorConversionOptions options, in CieXyz source) + { + // Use doubles here for accuracy. + // Conversion algorithm described here: + // http://www.brucelindbloom.com/index.html?Eqn_XYZ_to_Luv.html + CieXyz whitePoint = options.TargetWhitePoint; + + double yr = source.Y / whitePoint.Y; + + double den = source.X + (15 * source.Y) + (3 * source.Z); + double up = den > 0 ? ComputeU(in source) : 0; + double vp = den > 0 ? ComputeV(in source) : 0; + double upr = ComputeU(in whitePoint); + double vpr = ComputeV(in whitePoint); + + const double e = 1 / 3d; + double l = yr > CieConstants.Epsilon + ? ((116 * Math.Pow(yr, e)) - 16d) + : (CieConstants.Kappa * yr); + + if (double.IsNaN(l) || l == -0d) + { + l = 0; + } + + double u = 13 * l * (up - upr); + double v = 13 * l * (vp - vpr); + + if (double.IsNaN(u) || u == -0d) + { + u = 0; + } + + if (double.IsNaN(v) || v == -0d) + { + v = 0; + } + + return new CieLuv((float)l, (float)u, (float)v); + } + + /// + public static void FromProfileConnectionSpace(ColorConversionOptions options, ReadOnlySpan source, Span destination) + { + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + for (int i = 0; i < source.Length; i++) + { + CieXyz xyz = source[i]; + destination[i] = FromProfileConnectingSpace(options, in xyz); + } + } + + /// + public CieXyz ToProfileConnectingSpace(ColorConversionOptions options) + { + // Use doubles here for accuracy. + // Conversion algorithm described here: + // http://www.brucelindbloom.com/index.html?Eqn_Luv_to_XYZ.html + CieXyz whitePoint = options.WhitePoint; + + double l = this.L, u = this.U, v = this.V; + + double u0 = ComputeU(in whitePoint); + double v0 = ComputeV(in whitePoint); + + double y = l > CieConstants.Kappa * CieConstants.Epsilon + ? Numerics.Pow3((l + 16) / 116d) + : l / CieConstants.Kappa; + + double a = ((52 * l / (u + (13 * l * u0))) - 1) / 3; + double b = -5 * y; + const double c = -1 / 3d; + double d = y * ((39 * l / (v + (13 * l * v0))) - 5); + + double x = (d - b) / (a - c); + double z = (x * a) + b; + + if (double.IsNaN(x) || x == -0d) + { + x = 0; + } + + if (double.IsNaN(y) || y == -0d) + { + y = 0; + } + + if (double.IsNaN(z) || z == -0d) + { + z = 0; + } + + return new CieXyz((float)x, (float)y, (float)z); + } + + /// + public static void ToProfileConnectionSpace(ColorConversionOptions options, ReadOnlySpan source, Span destination) + { + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + for (int i = 0; i < source.Length; i++) + { + CieLuv luv = source[i]; + destination[i] = luv.ToProfileConnectingSpace(options); + } + } + + /// + public static ChromaticAdaptionWhitePointSource GetChromaticAdaptionWhitePointSource() + => ChromaticAdaptionWhitePointSource.WhitePoint; + + /// + public override int GetHashCode() => HashCode.Combine(this.L, this.U, this.V); + + /// + public override string ToString() => FormattableString.Invariant($"CieLuv({this.L:#0.##}, {this.U:#0.##}, {this.V:#0.##})"); + + /// + public override bool Equals(object? obj) => obj is CieLuv other && this.Equals(other); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool Equals(CieLuv other) + => this.AsVector3Unsafe() == other.AsVector3Unsafe(); + + private Vector3 AsVector3Unsafe() => Unsafe.As(ref Unsafe.AsRef(in this)); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static double ComputeU(in CieXyz source) + => (4 * source.X) / (source.X + (15 * source.Y) + (3 * source.Z)); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static double ComputeV(in CieXyz source) + => (9 * source.Y) / (source.X + (15 * source.Y) + (3 * source.Z)); +} diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyChromaticityCoordinates.cs b/src/ImageSharp/ColorProfiles/CieXyChromaticityCoordinates.cs similarity index 88% rename from src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyChromaticityCoordinates.cs rename to src/ImageSharp/ColorProfiles/CieXyChromaticityCoordinates.cs index 2cc785d53b..fa12b81d22 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyChromaticityCoordinates.cs +++ b/src/ImageSharp/ColorProfiles/CieXyChromaticityCoordinates.cs @@ -1,14 +1,16 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. +using System.Numerics; using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; -// ReSharper disable CompareOfFloatsByEqualityOperator -namespace SixLabors.ImageSharp.ColorSpaces.Conversion; +namespace SixLabors.ImageSharp.ColorProfiles; /// /// Represents the coordinates of CIEXY chromaticity space. /// +[StructLayout(LayoutKind.Sequential)] public readonly struct CieXyChromaticityCoordinates : IEquatable { /// @@ -29,7 +31,7 @@ public readonly struct CieXyChromaticityCoordinates : IEquatable /// Ranges usually from 0 to 1. /// - public readonly float X { get; } + public float X { get; } /// /// Gets the chromaticity Y-coordinate @@ -37,7 +39,7 @@ public readonly struct CieXyChromaticityCoordinates : IEquatable /// Ranges usually from 0 to 1. /// - public readonly float Y { get; } + public float Y { get; } /// /// Compares two objects for equality. @@ -79,5 +81,7 @@ public readonly struct CieXyChromaticityCoordinates : IEquatable [MethodImpl(InliningOptions.ShortMethod)] public bool Equals(CieXyChromaticityCoordinates other) - => this.X.Equals(other.X) && this.Y.Equals(other.Y); + => this.AsVector2Unsafe() == other.AsVector2Unsafe(); + + private Vector2 AsVector2Unsafe() => Unsafe.As(ref Unsafe.AsRef(in this)); } diff --git a/src/ImageSharp/ColorSpaces/CieXyy.cs b/src/ImageSharp/ColorProfiles/CieXyy.cs similarity index 51% rename from src/ImageSharp/ColorSpaces/CieXyy.cs rename to src/ImageSharp/ColorProfiles/CieXyy.cs index 6b7d2e6cbd..62873df147 100644 --- a/src/ImageSharp/ColorSpaces/CieXyy.cs +++ b/src/ImageSharp/ColorProfiles/CieXyy.cs @@ -3,14 +3,16 @@ using System.Numerics; using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; -namespace SixLabors.ImageSharp.ColorSpaces; +namespace SixLabors.ImageSharp.ColorProfiles; /// /// Represents an CIE xyY 1931 color /// /// -public readonly struct CieXyy : IEquatable +[StructLayout(LayoutKind.Sequential)] +public readonly struct CieXyy : IColorProfile { /// /// Initializes a new instance of the struct. @@ -18,7 +20,7 @@ public readonly struct CieXyy : IEquatable /// The x chroma component. /// The y chroma component. /// The y luminance component. - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public CieXyy(float x, float y, float yl) { // Not clamping as documentation about this space only indicates "usual" ranges @@ -31,7 +33,7 @@ public readonly struct CieXyy : IEquatable /// Initializes a new instance of the struct. /// /// The vector representing the x, y, Y components. - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public CieXyy(Vector3 vector) : this() { @@ -45,19 +47,19 @@ public readonly struct CieXyy : IEquatable /// Gets the X chrominance component. /// A value usually ranging between 0 and 1. /// - public readonly float X { get; } + public float X { get; } /// /// Gets the Y chrominance component. /// A value usually ranging between 0 and 1. /// - public readonly float Y { get; } + public float Y { get; } /// /// Gets the Y luminance component. /// A value usually ranging between 0 and 1. /// - public readonly float Yl { get; } + public float Yl { get; } /// /// Compares two objects for equality. @@ -67,7 +69,7 @@ public readonly struct CieXyy : IEquatable /// /// True if the current left is equal to the parameter; otherwise, false. /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(CieXyy left, CieXyy right) => left.Equals(right); /// @@ -78,22 +80,79 @@ public readonly struct CieXyy : IEquatable /// /// True if the current left is unequal to the parameter; otherwise, false. /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(CieXyy left, CieXyy right) => !left.Equals(right); /// - public override int GetHashCode() => HashCode.Combine(this.X, this.Y, this.Yl); + public static CieXyy FromProfileConnectingSpace(ColorConversionOptions options, in CieXyz source) + { + float x = source.X / (source.X + source.Y + source.Z); + float y = source.Y / (source.X + source.Y + source.Z); + + if (float.IsNaN(x) || float.IsNaN(y)) + { + return new CieXyy(0, 0, source.Y); + } + + return new CieXyy(x, y, source.Y); + } + + /// + public static void FromProfileConnectionSpace(ColorConversionOptions options, ReadOnlySpan source, Span destination) + { + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + for (int i = 0; i < source.Length; i++) + { + CieXyz xyz = source[i]; + destination[i] = FromProfileConnectingSpace(options, in xyz); + } + } /// - public override string ToString() => FormattableString.Invariant($"CieXyy({this.X:#0.##}, {this.Y:#0.##}, {this.Yl:#0.##})"); + public CieXyz ToProfileConnectingSpace(ColorConversionOptions options) + { + if (MathF.Abs(this.Y) < Constants.Epsilon) + { + return new CieXyz(0, 0, this.Yl); + } + + float x = (this.X * this.Yl) / this.Y; + float y = this.Yl; + float z = ((1 - this.X - this.Y) * y) / this.Y; + + return new CieXyz(x, y, z); + } + + /// + public static void ToProfileConnectionSpace(ColorConversionOptions options, ReadOnlySpan source, Span destination) + { + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + for (int i = 0; i < source.Length; i++) + { + CieXyy xyz = source[i]; + destination[i] = xyz.ToProfileConnectingSpace(options); + } + } + + /// + public static ChromaticAdaptionWhitePointSource GetChromaticAdaptionWhitePointSource() + => ChromaticAdaptionWhitePointSource.WhitePoint; + + /// + public override int GetHashCode() + => HashCode.Combine(this.X, this.Y, this.Yl); + + /// + public override string ToString() + => FormattableString.Invariant($"CieXyy({this.X:#0.##}, {this.Y:#0.##}, {this.Yl:#0.##})"); /// public override bool Equals(object? obj) => obj is CieXyy other && this.Equals(other); /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool Equals(CieXyy other) - => this.X.Equals(other.X) - && this.Y.Equals(other.Y) - && this.Yl.Equals(other.Yl); + => this.AsVector3Unsafe() == other.AsVector3Unsafe(); + + private Vector3 AsVector3Unsafe() => Unsafe.As(ref Unsafe.AsRef(in this)); } diff --git a/src/ImageSharp/ColorSpaces/CieXyz.cs b/src/ImageSharp/ColorProfiles/CieXyz.cs similarity index 64% rename from src/ImageSharp/ColorSpaces/CieXyz.cs rename to src/ImageSharp/ColorProfiles/CieXyz.cs index 2ac9c9f286..07f9b47f9b 100644 --- a/src/ImageSharp/ColorSpaces/CieXyz.cs +++ b/src/ImageSharp/ColorProfiles/CieXyz.cs @@ -3,14 +3,16 @@ using System.Numerics; using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; -namespace SixLabors.ImageSharp.ColorSpaces; +namespace SixLabors.ImageSharp.ColorProfiles; /// /// Represents an CIE XYZ 1931 color /// /// -public readonly struct CieXyz : IEquatable +[StructLayout(LayoutKind.Sequential)] +public readonly struct CieXyz : IProfileConnectingSpace { /// /// Initializes a new instance of the struct. @@ -18,10 +20,13 @@ public readonly struct CieXyz : IEquatable /// X is a mix (a linear combination) of cone response curves chosen to be nonnegative /// The y luminance component. /// Z is quasi-equal to blue stimulation, or the S cone of the human eye. - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public CieXyz(float x, float y, float z) - : this(new Vector3(x, y, z)) { + // Not clamping as documentation about this space only indicates "usual" ranges + this.X = x; + this.Y = y; + this.Z = z; } /// @@ -31,7 +36,6 @@ public readonly struct CieXyz : IEquatable public CieXyz(Vector3 vector) : this() { - // Not clamping as documentation about this space only indicates "usual" ranges this.X = vector.X; this.Y = vector.Y; this.Z = vector.Z; @@ -41,19 +45,19 @@ public readonly struct CieXyz : IEquatable /// 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 { get; } + public float X { get; } /// /// Gets the Y luminance component. /// A value usually ranging between 0 and 1. /// - public readonly float Y { get; } + public float Y { get; } /// /// Gets the Z component. Quasi-equal to blue stimulation, or the S cone response. /// A value usually ranging between 0 and 1. /// - public readonly float Z { get; } + public float Z { get; } /// /// Compares two objects for equality. @@ -63,7 +67,7 @@ public readonly struct CieXyz : IEquatable /// /// True if the current left is equal to the parameter; otherwise, false. /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(CieXyz left, CieXyz right) => left.Equals(right); /// @@ -74,16 +78,41 @@ public readonly struct CieXyz : IEquatable /// /// True if the current left is unequal to the parameter; otherwise, false. /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(CieXyz left, CieXyz right) => !left.Equals(right); /// /// Returns a new representing this instance. /// /// The . - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public Vector3 ToVector3() => new(this.X, this.Y, this.Z); + /// + public static CieXyz FromProfileConnectingSpace(ColorConversionOptions options, in CieXyz source) + => new(source.X, source.Y, source.Z); + + /// + public static void FromProfileConnectionSpace(ColorConversionOptions options, ReadOnlySpan source, Span destination) + { + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + source.CopyTo(destination[..source.Length]); + } + + /// + public CieXyz ToProfileConnectingSpace(ColorConversionOptions options) + => new(this.X, this.Y, this.Z); + + /// + public static void ToProfileConnectionSpace(ColorConversionOptions options, ReadOnlySpan source, Span destination) + { + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + source.CopyTo(destination[..source.Length]); + } + + /// + public static ChromaticAdaptionWhitePointSource GetChromaticAdaptionWhitePointSource() => ChromaticAdaptionWhitePointSource.WhitePoint; + /// public override int GetHashCode() => HashCode.Combine(this.X, this.Y, this.Z); @@ -94,9 +123,9 @@ public readonly struct CieXyz : IEquatable public override bool Equals(object? obj) => obj is CieXyz other && this.Equals(other); /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool Equals(CieXyz other) - => this.X.Equals(other.X) - && this.Y.Equals(other.Y) - && this.Z.Equals(other.Z); + => 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 new file mode 100644 index 0000000000..e924904497 --- /dev/null +++ b/src/ImageSharp/ColorProfiles/Cmyk.cs @@ -0,0 +1,165 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +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; + private static readonly Vector4 Max = Vector4.One; + + /// + /// Initializes a new instance of the struct. + /// + /// The cyan component. + /// The magenta component. + /// The yellow component. + /// The keyline black component. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Cmyk(float c, float m, float y, float k) + : this(new Vector4(c, m, y, k)) + { + } + + /// + /// Initializes a new instance of the struct. + /// + /// The vector representing the c, m, y, k components. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Cmyk(Vector4 vector) + { + vector = Numerics.Clamp(vector, Min, Max); + this.C = vector.X; + this.M = vector.Y; + this.Y = vector.Z; + this.K = vector.W; + } + + /// + /// Gets the cyan color component. + /// A value ranging between 0 and 1. + /// + public float C { get; } + + /// + /// Gets the magenta color component. + /// A value ranging between 0 and 1. + /// + public float M { get; } + + /// + /// Gets the yellow color component. + /// A value ranging between 0 and 1. + /// + public float Y { get; } + + /// + /// Gets the keyline black color component. + /// A value ranging between 0 and 1. + /// + public float K { get; } + + /// + /// Compares two objects for equality. + /// + /// 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) => left.Equals(right); + + /// + /// Compares two objects for inequality. + /// + /// 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) => !left.Equals(right); + + /// + public static Cmyk FromProfileConnectingSpace(ColorConversionOptions options, in Rgb source) + { + // To CMY + Vector3 cmy = Vector3.One - source.ToScaledVector3(); + + // To CMYK + Vector3 k = new(MathF.Min(cmy.X, MathF.Min(cmy.Y, cmy.Z))); + + if (MathF.Abs(k.X - 1F) < Constants.Epsilon) + { + return new Cmyk(0, 0, 0, 1F); + } + + cmy = (cmy - k) / (Vector3.One - k); + + return new Cmyk(cmy.X, cmy.Y, cmy.Z, k.X); + } + + /// + public static void FromProfileConnectionSpace(ColorConversionOptions options, ReadOnlySpan source, Span destination) + { + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + + // TODO: We can optimize this by using SIMD + for (int i = 0; i < source.Length; i++) + { + Rgb rgb = source[i]; + destination[i] = FromProfileConnectingSpace(options, in rgb); + } + } + + /// + public Rgb ToProfileConnectingSpace(ColorConversionOptions options) + { + Vector3 rgb = (Vector3.One - new Vector3(this.C, this.M, this.Y)) * (Vector3.One - new Vector3(this.K)); + return Rgb.FromScaledVector3(rgb); + } + + /// + public static void ToProfileConnectionSpace(ColorConversionOptions options, ReadOnlySpan source, Span destination) + { + // TODO: We can possibly optimize this by using SIMD + for (int i = 0; i < source.Length; i++) + { + Cmyk cmyk = source[i]; + destination[i] = cmyk.ToProfileConnectingSpace(options); + } + } + + /// + public static ChromaticAdaptionWhitePointSource GetChromaticAdaptionWhitePointSource() + => ChromaticAdaptionWhitePointSource.RgbWorkingSpace; + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public override int GetHashCode() + => HashCode.Combine(this.C, this.M, this.Y, this.K); + + /// + public override string ToString() + => FormattableString.Invariant($"Cmyk({this.C:#0.##}, {this.M:#0.##}, {this.Y:#0.##}, {this.K:#0.##})"); + + /// + public override bool Equals(object? obj) + => obj is Cmyk other && this.Equals(other); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool Equals(Cmyk other) + => this.AsVector4Unsafe() == other.AsVector4Unsafe(); + + private Vector4 AsVector4Unsafe() => Unsafe.As(ref Unsafe.AsRef(in this)); +} diff --git a/src/ImageSharp/ColorProfiles/ColorConversionOptions.cs b/src/ImageSharp/ColorProfiles/ColorConversionOptions.cs new file mode 100644 index 0000000000..1eb118834a --- /dev/null +++ b/src/ImageSharp/ColorProfiles/ColorConversionOptions.cs @@ -0,0 +1,63 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using System.Numerics; +using SixLabors.ImageSharp.ColorProfiles.WorkingSpaces; +using SixLabors.ImageSharp.Memory; + +namespace SixLabors.ImageSharp.ColorProfiles; + +/// +/// Provides options for color profile conversion. +/// +public class ColorConversionOptions +{ + private Matrix4x4 adaptationMatrix; + + /// + /// Initializes a new instance of the class. + /// + public ColorConversionOptions() => this.AdaptationMatrix = KnownChromaticAdaptationMatrices.Bradford; + + /// + /// Gets the memory allocator. + /// + public MemoryAllocator MemoryAllocator { get; init; } = MemoryAllocator.Default; + + /// + /// Gets the source white point used for chromatic adaptation in conversions from/to XYZ color space. + /// + public CieXyz WhitePoint { get; init; } = KnownIlluminants.D50; + + /// + /// Gets the destination white point used for chromatic adaptation in conversions from/to XYZ color space. + /// + public CieXyz TargetWhitePoint { get; init; } = KnownIlluminants.D50; + + /// + /// Gets the source working space used for companding in conversions from/to XYZ color space. + /// + public RgbWorkingSpace RgbWorkingSpace { get; init; } = KnownRgbWorkingSpaces.SRgb; + + /// + /// Gets the destination working space used for companding in conversions from/to XYZ color space. + /// + public RgbWorkingSpace TargetRgbWorkingSpace { get; init; } = KnownRgbWorkingSpaces.SRgb; + + /// + /// Gets the transformation matrix used in conversion to perform chromatic adaptation. + /// for further information. Default is Bradford. + /// + public Matrix4x4 AdaptationMatrix + { + get => this.adaptationMatrix; + init + { + this.adaptationMatrix = value; + Matrix4x4.Invert(value, out Matrix4x4 inverted); + this.InverseAdaptationMatrix = inverted; + } + } + + internal Matrix4x4 InverseAdaptationMatrix { get; private set; } +} diff --git a/src/ImageSharp/ColorProfiles/ColorProfileConverter.cs b/src/ImageSharp/ColorProfiles/ColorProfileConverter.cs new file mode 100644 index 0000000000..18b90a622a --- /dev/null +++ b/src/ImageSharp/ColorProfiles/ColorProfileConverter.cs @@ -0,0 +1,45 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +namespace SixLabors.ImageSharp.ColorProfiles; + +/// +/// Allows the conversion of color profiles. +/// +public class ColorProfileConverter +{ + /// + /// Initializes a new instance of the class. + /// + public ColorProfileConverter() + : this(new()) + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The color profile conversion options. + public ColorProfileConverter(ColorConversionOptions options) + => this.Options = options; + + /// + /// Gets the color profile conversion options. + /// + public ColorConversionOptions Options { get; } + + internal (CieXyz From, CieXyz To) GetChromaticAdaptionWhitePoints() + where TFrom : struct, IColorProfile + where TTo : struct, IColorProfile + { + CieXyz sourceWhitePoint = TFrom.GetChromaticAdaptionWhitePointSource() == ChromaticAdaptionWhitePointSource.WhitePoint + ? this.Options.WhitePoint + : this.Options.RgbWorkingSpace.WhitePoint; + + CieXyz targetWhitePoint = TTo.GetChromaticAdaptionWhitePointSource() == ChromaticAdaptionWhitePointSource.WhitePoint + ? this.Options.TargetWhitePoint + : this.Options.TargetRgbWorkingSpace.WhitePoint; + + return (sourceWhitePoint, targetWhitePoint); + } +} diff --git a/src/ImageSharp/ColorProfiles/ColorProfileConverterExtensionsCieLabCieLab.cs b/src/ImageSharp/ColorProfiles/ColorProfileConverterExtensionsCieLabCieLab.cs new file mode 100644 index 0000000000..41ae4b08fa --- /dev/null +++ b/src/ImageSharp/ColorProfiles/ColorProfileConverterExtensionsCieLabCieLab.cs @@ -0,0 +1,57 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using System.Buffers; +using SixLabors.ImageSharp.Memory; + +namespace SixLabors.ImageSharp.ColorProfiles; + +internal static class ColorProfileConverterExtensionsCieLabCieLab +{ + public static TTo Convert(this ColorProfileConverter converter, in TFrom source) + where TFrom : struct, IColorProfile + where TTo : struct, IColorProfile + { + ColorConversionOptions options = converter.Options; + + // Convert to input PCS + CieLab pcsFromA = source.ToProfileConnectingSpace(options); + CieXyz pcsFromB = pcsFromA.ToProfileConnectingSpace(options); + + // Adapt to target white point + (CieXyz From, CieXyz To) whitePoints = converter.GetChromaticAdaptionWhitePoints(); + pcsFromB = VonKriesChromaticAdaptation.Transform(in pcsFromB, whitePoints, options.AdaptationMatrix); + + // Convert between PCS + CieLab pcsTo = CieLab.FromProfileConnectingSpace(options, in pcsFromB); + + // Convert to output from PCS + return TTo.FromProfileConnectingSpace(options, in pcsTo); + } + + public static void Convert(this ColorProfileConverter converter, ReadOnlySpan source, Span destination) + where TFrom : struct, IColorProfile + where TTo : struct, IColorProfile + { + ColorConversionOptions options = converter.Options; + + // Convert to input PCS. + using IMemoryOwner pcsFromToOwner = options.MemoryAllocator.Allocate(source.Length); + Span pcsFromTo = pcsFromToOwner.GetSpan(); + TFrom.ToProfileConnectionSpace(options, source, pcsFromTo); + + using IMemoryOwner pcsFromOwner = options.MemoryAllocator.Allocate(source.Length); + Span pcsFrom = pcsFromOwner.GetSpan(); + CieLab.ToProfileConnectionSpace(options, pcsFromTo, pcsFrom); + + // Adapt to target white point + (CieXyz From, CieXyz To) whitePoints = converter.GetChromaticAdaptionWhitePoints(); + VonKriesChromaticAdaptation.Transform(pcsFrom, pcsFrom, whitePoints, options.AdaptationMatrix); + + // Convert between PCS. + CieLab.FromProfileConnectionSpace(options, pcsFrom, pcsFromTo); + + // Convert to output from PCS + TTo.FromProfileConnectionSpace(options, pcsFromTo, destination); + } +} diff --git a/src/ImageSharp/ColorProfiles/ColorProfileConverterExtensionsCieLabCieXyz.cs b/src/ImageSharp/ColorProfiles/ColorProfileConverterExtensionsCieLabCieXyz.cs new file mode 100644 index 0000000000..04937e927e --- /dev/null +++ b/src/ImageSharp/ColorProfiles/ColorProfileConverterExtensionsCieLabCieXyz.cs @@ -0,0 +1,54 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using System.Buffers; +using SixLabors.ImageSharp.Memory; + +namespace SixLabors.ImageSharp.ColorProfiles; + +internal static class ColorProfileConverterExtensionsCieLabCieXyz +{ + public static TTo Convert(this ColorProfileConverter converter, in TFrom source) + where TFrom : struct, IColorProfile + where TTo : struct, IColorProfile + { + ColorConversionOptions options = converter.Options; + + // Convert to input PCS + CieLab pcsFrom = source.ToProfileConnectingSpace(options); + + // Convert between PCS + CieXyz pcsTo = pcsFrom.ToProfileConnectingSpace(options); + + // Adapt to target white point + (CieXyz From, CieXyz To) whitePoints = converter.GetChromaticAdaptionWhitePoints(); + pcsTo = VonKriesChromaticAdaptation.Transform(in pcsTo, whitePoints, options.AdaptationMatrix); + + // Convert to output from PCS + return TTo.FromProfileConnectingSpace(options, in pcsTo); + } + + public static void Convert(this ColorProfileConverter converter, ReadOnlySpan source, Span destination) + where TFrom : struct, IColorProfile + where TTo : struct, IColorProfile + { + ColorConversionOptions options = converter.Options; + + // Convert to input PCS. + using IMemoryOwner pcsFromOwner = options.MemoryAllocator.Allocate(source.Length); + Span pcsFrom = pcsFromOwner.GetSpan(); + TFrom.ToProfileConnectionSpace(options, source, pcsFrom); + + // Convert between PCS. + using IMemoryOwner pcsToOwner = options.MemoryAllocator.Allocate(source.Length); + Span pcsTo = pcsToOwner.GetSpan(); + CieLab.ToProfileConnectionSpace(options, pcsFrom, pcsTo); + + // Adapt to target white point + (CieXyz From, CieXyz To) whitePoints = converter.GetChromaticAdaptionWhitePoints(); + VonKriesChromaticAdaptation.Transform(pcsTo, pcsTo, whitePoints, options.AdaptationMatrix); + + // Convert to output from PCS + TTo.FromProfileConnectionSpace(options, pcsTo, destination); + } +} diff --git a/src/ImageSharp/ColorProfiles/ColorProfileConverterExtensionsCieLabRgb.cs b/src/ImageSharp/ColorProfiles/ColorProfileConverterExtensionsCieLabRgb.cs new file mode 100644 index 0000000000..47e4d2a80a --- /dev/null +++ b/src/ImageSharp/ColorProfiles/ColorProfileConverterExtensionsCieLabRgb.cs @@ -0,0 +1,59 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using System.Buffers; +using SixLabors.ImageSharp.Memory; + +namespace SixLabors.ImageSharp.ColorProfiles; + +internal static class ColorProfileConverterExtensionsCieLabRgb +{ + public static TTo Convert(this ColorProfileConverter converter, in TFrom source) + where TFrom : struct, IColorProfile + where TTo : struct, IColorProfile + { + ColorConversionOptions options = converter.Options; + + // Convert to input PCS + CieLab pcsFromA = source.ToProfileConnectingSpace(options); + CieXyz pcsFromB = pcsFromA.ToProfileConnectingSpace(options); + + // Adapt to target white point + (CieXyz From, CieXyz To) whitePoints = converter.GetChromaticAdaptionWhitePoints(); + pcsFromB = VonKriesChromaticAdaptation.Transform(in pcsFromB, whitePoints, options.AdaptationMatrix); + + // Convert between PCS + Rgb pcsTo = Rgb.FromProfileConnectingSpace(options, in pcsFromB); + + // Convert to output from PCS + return TTo.FromProfileConnectingSpace(options, in pcsTo); + } + + public static void Convert(this ColorProfileConverter converter, ReadOnlySpan source, Span destination) + where TFrom : struct, IColorProfile + where TTo : struct, IColorProfile + { + ColorConversionOptions options = converter.Options; + + // Convert to input PCS. + using IMemoryOwner pcsFromAOwner = options.MemoryAllocator.Allocate(source.Length); + Span pcsFromA = pcsFromAOwner.GetSpan(); + TFrom.ToProfileConnectionSpace(options, source, pcsFromA); + + using IMemoryOwner pcsFromBOwner = options.MemoryAllocator.Allocate(source.Length); + Span pcsFromB = pcsFromBOwner.GetSpan(); + CieLab.ToProfileConnectionSpace(options, pcsFromA, pcsFromB); + + // Adapt to target white point + (CieXyz From, CieXyz To) whitePoints = converter.GetChromaticAdaptionWhitePoints(); + VonKriesChromaticAdaptation.Transform(pcsFromB, pcsFromB, whitePoints, options.AdaptationMatrix); + + // Convert between PCS. + using IMemoryOwner pcsToOwner = options.MemoryAllocator.Allocate(source.Length); + Span pcsTo = pcsToOwner.GetSpan(); + Rgb.FromProfileConnectionSpace(options, pcsFromB, pcsTo); + + // Convert to output from PCS + TTo.FromProfileConnectionSpace(options, pcsTo, destination); + } +} diff --git a/src/ImageSharp/ColorProfiles/ColorProfileConverterExtensionsCieXyzCieLab.cs b/src/ImageSharp/ColorProfiles/ColorProfileConverterExtensionsCieXyzCieLab.cs new file mode 100644 index 0000000000..6b1575d04c --- /dev/null +++ b/src/ImageSharp/ColorProfiles/ColorProfileConverterExtensionsCieXyzCieLab.cs @@ -0,0 +1,54 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using System.Buffers; +using SixLabors.ImageSharp.Memory; + +namespace SixLabors.ImageSharp.ColorProfiles; + +internal static class ColorProfileConverterExtensionsCieXyzCieLab +{ + public static TTo Convert(this ColorProfileConverter converter, in TFrom source) + where TFrom : struct, IColorProfile + where TTo : struct, IColorProfile + { + ColorConversionOptions options = converter.Options; + + // Convert to input PCS + CieXyz pcsFrom = source.ToProfileConnectingSpace(options); + + // Adapt to target white point + (CieXyz From, CieXyz To) whitePoints = converter.GetChromaticAdaptionWhitePoints(); + pcsFrom = VonKriesChromaticAdaptation.Transform(in pcsFrom, whitePoints, options.AdaptationMatrix); + + // Convert between PCS + CieLab pcsTo = CieLab.FromProfileConnectingSpace(options, in pcsFrom); + + // Convert to output from PCS + return TTo.FromProfileConnectingSpace(options, in pcsTo); + } + + public static void Convert(this ColorProfileConverter converter, ReadOnlySpan source, Span destination) + where TFrom : struct, IColorProfile + where TTo : struct, IColorProfile + { + ColorConversionOptions options = converter.Options; + + // Convert to input PCS. + using IMemoryOwner pcsFromOwner = options.MemoryAllocator.Allocate(source.Length); + Span pcsFrom = pcsFromOwner.GetSpan(); + TFrom.ToProfileConnectionSpace(options, source, pcsFrom); + + // Adapt to target white point + (CieXyz From, CieXyz To) whitePoints = converter.GetChromaticAdaptionWhitePoints(); + VonKriesChromaticAdaptation.Transform(pcsFrom, pcsFrom, whitePoints, options.AdaptationMatrix); + + // Convert between PCS. + using IMemoryOwner pcsToOwner = options.MemoryAllocator.Allocate(source.Length); + Span pcsTo = pcsToOwner.GetSpan(); + CieLab.FromProfileConnectionSpace(options, pcsFrom, pcsTo); + + // Convert to output from PCS + TTo.FromProfileConnectionSpace(options, pcsTo, destination); + } +} diff --git a/src/ImageSharp/ColorProfiles/ColorProfileConverterExtensionsCieXyzCieXyz.cs b/src/ImageSharp/ColorProfiles/ColorProfileConverterExtensionsCieXyzCieXyz.cs new file mode 100644 index 0000000000..8f56a5a663 --- /dev/null +++ b/src/ImageSharp/ColorProfiles/ColorProfileConverterExtensionsCieXyzCieXyz.cs @@ -0,0 +1,46 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using System.Buffers; +using SixLabors.ImageSharp.Memory; + +namespace SixLabors.ImageSharp.ColorProfiles; + +internal static class ColorProfileConverterExtensionsCieXyzCieXyz +{ + public static TTo Convert(this ColorProfileConverter converter, in TFrom source) + where TFrom : struct, IColorProfile + where TTo : struct, IColorProfile + { + ColorConversionOptions options = converter.Options; + + // Convert to input PCS + CieXyz pcsFrom = source.ToProfileConnectingSpace(options); + + // Adapt to target white point + (CieXyz From, CieXyz To) whitePoints = converter.GetChromaticAdaptionWhitePoints(); + pcsFrom = VonKriesChromaticAdaptation.Transform(in pcsFrom, whitePoints, options.AdaptationMatrix); + + // Convert to output from PCS + return TTo.FromProfileConnectingSpace(options, in pcsFrom); + } + + public static void Convert(this ColorProfileConverter converter, ReadOnlySpan source, Span destination) + where TFrom : struct, IColorProfile + where TTo : struct, IColorProfile + { + ColorConversionOptions options = converter.Options; + + // Convert to input PCS. + using IMemoryOwner pcsFromOwner = options.MemoryAllocator.Allocate(source.Length); + Span pcsFrom = pcsFromOwner.GetSpan(); + TFrom.ToProfileConnectionSpace(options, source, pcsFrom); + + // Adapt to target white point + (CieXyz From, CieXyz To) whitePoints = converter.GetChromaticAdaptionWhitePoints(); + VonKriesChromaticAdaptation.Transform(pcsFrom, pcsFrom, whitePoints, options.AdaptationMatrix); + + // Convert to output from PCS + TTo.FromProfileConnectionSpace(options, pcsFrom, destination); + } +} diff --git a/src/ImageSharp/ColorProfiles/ColorProfileConverterExtensionsCieXyzRgb.cs b/src/ImageSharp/ColorProfiles/ColorProfileConverterExtensionsCieXyzRgb.cs new file mode 100644 index 0000000000..9cc0bd9436 --- /dev/null +++ b/src/ImageSharp/ColorProfiles/ColorProfileConverterExtensionsCieXyzRgb.cs @@ -0,0 +1,54 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using System.Buffers; +using SixLabors.ImageSharp.Memory; + +namespace SixLabors.ImageSharp.ColorProfiles; + +internal static class ColorProfileConverterExtensionsCieXyzRgb +{ + public static TTo Convert(this ColorProfileConverter converter, in TFrom source) + where TFrom : struct, IColorProfile + where TTo : struct, IColorProfile + { + ColorConversionOptions options = converter.Options; + + // Convert to input PCS + CieXyz pcsFrom = source.ToProfileConnectingSpace(options); + + // Adapt to target white point + (CieXyz From, CieXyz To) whitePoints = converter.GetChromaticAdaptionWhitePoints(); + pcsFrom = VonKriesChromaticAdaptation.Transform(in pcsFrom, whitePoints, options.AdaptationMatrix); + + // Convert between PCS + Rgb pcsTo = Rgb.FromProfileConnectingSpace(options, in pcsFrom); + + // Convert to output from PCS + return TTo.FromProfileConnectingSpace(options, in pcsTo); + } + + public static void Convert(this ColorProfileConverter converter, ReadOnlySpan source, Span destination) + where TFrom : struct, IColorProfile + where TTo : struct, IColorProfile + { + ColorConversionOptions options = converter.Options; + + // Convert to input PCS. + using IMemoryOwner pcsFromOwner = options.MemoryAllocator.Allocate(source.Length); + Span pcsFrom = pcsFromOwner.GetSpan(); + TFrom.ToProfileConnectionSpace(options, source, pcsFrom); + + // Adapt to target white point + (CieXyz From, CieXyz To) whitePoints = converter.GetChromaticAdaptionWhitePoints(); + VonKriesChromaticAdaptation.Transform(pcsFrom, pcsFrom, whitePoints, options.AdaptationMatrix); + + // Convert between PCS. + using IMemoryOwner pcsToOwner = options.MemoryAllocator.Allocate(source.Length); + Span pcsTo = pcsToOwner.GetSpan(); + Rgb.FromProfileConnectionSpace(options, pcsFrom, pcsTo); + + // Convert to output from PCS + TTo.FromProfileConnectionSpace(options, pcsTo, destination); + } +} diff --git a/src/ImageSharp/ColorProfiles/ColorProfileConverterExtensionsRgbCieLab.cs b/src/ImageSharp/ColorProfiles/ColorProfileConverterExtensionsRgbCieLab.cs new file mode 100644 index 0000000000..415dd94c3f --- /dev/null +++ b/src/ImageSharp/ColorProfiles/ColorProfileConverterExtensionsRgbCieLab.cs @@ -0,0 +1,59 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using System.Buffers; +using SixLabors.ImageSharp.Memory; + +namespace SixLabors.ImageSharp.ColorProfiles; + +internal static class ColorProfileConverterExtensionsRgbCieLab +{ + public static TTo Convert(this ColorProfileConverter converter, in TFrom source) + where TFrom : struct, IColorProfile + where TTo : struct, IColorProfile + { + ColorConversionOptions options = converter.Options; + + // Convert to input PCS + Rgb pcsFromA = source.ToProfileConnectingSpace(options); + CieXyz pcsFromB = pcsFromA.ToProfileConnectingSpace(options); + + // Adapt to target white point + (CieXyz From, CieXyz To) whitePoints = converter.GetChromaticAdaptionWhitePoints(); + pcsFromB = VonKriesChromaticAdaptation.Transform(in pcsFromB, whitePoints, options.AdaptationMatrix); + + // Convert between PCS + CieLab pcsTo = CieLab.FromProfileConnectingSpace(options, in pcsFromB); + + // Convert to output from PCS + return TTo.FromProfileConnectingSpace(options, in pcsTo); + } + + public static void Convert(this ColorProfileConverter converter, ReadOnlySpan source, Span destination) + where TFrom : struct, IColorProfile + where TTo : struct, IColorProfile + { + ColorConversionOptions options = converter.Options; + + // Convert to input PCS. + using IMemoryOwner pcsFromAOwner = options.MemoryAllocator.Allocate(source.Length); + Span pcsFromA = pcsFromAOwner.GetSpan(); + TFrom.ToProfileConnectionSpace(options, source, pcsFromA); + + using IMemoryOwner pcsFromBOwner = options.MemoryAllocator.Allocate(source.Length); + Span pcsFromB = pcsFromBOwner.GetSpan(); + Rgb.ToProfileConnectionSpace(options, pcsFromA, pcsFromB); + + // Adapt to target white point + (CieXyz From, CieXyz To) whitePoints = converter.GetChromaticAdaptionWhitePoints(); + VonKriesChromaticAdaptation.Transform(pcsFromB, pcsFromB, whitePoints, options.AdaptationMatrix); + + // Convert between PCS. + using IMemoryOwner pcsToOwner = options.MemoryAllocator.Allocate(source.Length); + Span pcsTo = pcsToOwner.GetSpan(); + CieLab.FromProfileConnectionSpace(options, pcsFromB, pcsTo); + + // Convert to output from PCS + TTo.FromProfileConnectionSpace(options, pcsTo, destination); + } +} diff --git a/src/ImageSharp/ColorProfiles/ColorProfileConverterExtensionsRgbCieXyz.cs b/src/ImageSharp/ColorProfiles/ColorProfileConverterExtensionsRgbCieXyz.cs new file mode 100644 index 0000000000..a13f645778 --- /dev/null +++ b/src/ImageSharp/ColorProfiles/ColorProfileConverterExtensionsRgbCieXyz.cs @@ -0,0 +1,54 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using System.Buffers; +using SixLabors.ImageSharp.Memory; + +namespace SixLabors.ImageSharp.ColorProfiles; + +internal static class ColorProfileConverterExtensionsRgbCieXyz +{ + public static TTo Convert(this ColorProfileConverter converter, in TFrom source) + where TFrom : struct, IColorProfile + where TTo : struct, IColorProfile + { + ColorConversionOptions options = converter.Options; + + // Convert to input PCS + Rgb pcsFrom = source.ToProfileConnectingSpace(options); + + // Convert between PCS + CieXyz pcsTo = pcsFrom.ToProfileConnectingSpace(options); + + // Adapt to target white point + (CieXyz From, CieXyz To) whitePoints = converter.GetChromaticAdaptionWhitePoints(); + pcsTo = VonKriesChromaticAdaptation.Transform(in pcsTo, whitePoints, options.AdaptationMatrix); + + // Convert to output from PCS + return TTo.FromProfileConnectingSpace(options, in pcsTo); + } + + public static void Convert(this ColorProfileConverter converter, ReadOnlySpan source, Span destination) + where TFrom : struct, IColorProfile + where TTo : struct, IColorProfile + { + ColorConversionOptions options = converter.Options; + + // Convert to input PCS. + using IMemoryOwner pcsFromOwner = options.MemoryAllocator.Allocate(source.Length); + Span pcsFrom = pcsFromOwner.GetSpan(); + TFrom.ToProfileConnectionSpace(options, source, pcsFrom); + + // Convert between PCS. + using IMemoryOwner pcsToOwner = options.MemoryAllocator.Allocate(source.Length); + Span pcsTo = pcsToOwner.GetSpan(); + Rgb.ToProfileConnectionSpace(options, pcsFrom, pcsTo); + + // Adapt to target white point + (CieXyz From, CieXyz To) whitePoints = converter.GetChromaticAdaptionWhitePoints(); + VonKriesChromaticAdaptation.Transform(pcsTo, pcsTo, whitePoints, options.AdaptationMatrix); + + // Convert to output from PCS + TTo.FromProfileConnectionSpace(options, pcsTo, destination); + } +} diff --git a/src/ImageSharp/ColorProfiles/ColorProfileConverterExtensionsRgbRgb.cs b/src/ImageSharp/ColorProfiles/ColorProfileConverterExtensionsRgbRgb.cs new file mode 100644 index 0000000000..c1c75dea1b --- /dev/null +++ b/src/ImageSharp/ColorProfiles/ColorProfileConverterExtensionsRgbRgb.cs @@ -0,0 +1,57 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using System.Buffers; +using SixLabors.ImageSharp.Memory; + +namespace SixLabors.ImageSharp.ColorProfiles; + +internal static class ColorProfileConverterExtensionsRgbRgb +{ + public static TTo Convert(this ColorProfileConverter converter, in TFrom source) + where TFrom : struct, IColorProfile + where TTo : struct, IColorProfile + { + ColorConversionOptions options = converter.Options; + + // Convert to input PCS + Rgb pcsFromA = source.ToProfileConnectingSpace(options); + CieXyz pcsFromB = pcsFromA.ToProfileConnectingSpace(options); + + // Adapt to target white point + (CieXyz From, CieXyz To) whitePoints = converter.GetChromaticAdaptionWhitePoints(); + pcsFromB = VonKriesChromaticAdaptation.Transform(in pcsFromB, whitePoints, options.AdaptationMatrix); + + // Convert between PCS + Rgb pcsTo = Rgb.FromProfileConnectingSpace(options, in pcsFromB); + + // Convert to output from PCS + return TTo.FromProfileConnectingSpace(options, in pcsTo); + } + + public static void Convert(this ColorProfileConverter converter, ReadOnlySpan source, Span destination) + where TFrom : struct, IColorProfile + where TTo : struct, IColorProfile + { + ColorConversionOptions options = converter.Options; + + // Convert to input PCS. + using IMemoryOwner pcsFromToOwner = options.MemoryAllocator.Allocate(source.Length); + Span pcsFromTo = pcsFromToOwner.GetSpan(); + TFrom.ToProfileConnectionSpace(options, source, pcsFromTo); + + using IMemoryOwner pcsFromOwner = options.MemoryAllocator.Allocate(source.Length); + Span pcsFrom = pcsFromOwner.GetSpan(); + Rgb.ToProfileConnectionSpace(options, pcsFromTo, pcsFrom); + + // Adapt to target white point + (CieXyz From, CieXyz To) whitePoints = converter.GetChromaticAdaptionWhitePoints(); + VonKriesChromaticAdaptation.Transform(pcsFrom, pcsFrom, whitePoints, options.AdaptationMatrix); + + // Convert between PCS. + Rgb.FromProfileConnectionSpace(options, pcsFrom, pcsFromTo); + + // Convert to output from PCS + TTo.FromProfileConnectionSpace(options, pcsFromTo, destination); + } +} diff --git a/src/ImageSharp/ColorProfiles/Companding/CompandingUtilities.cs b/src/ImageSharp/ColorProfiles/Companding/CompandingUtilities.cs new file mode 100644 index 0000000000..1970e2d949 --- /dev/null +++ b/src/ImageSharp/ColorProfiles/Companding/CompandingUtilities.cs @@ -0,0 +1,182 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using System.Collections.Concurrent; +using System.Numerics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.X86; + +namespace SixLabors.ImageSharp.ColorProfiles.Companding; + +/// +/// Companding utilities that allow the accelerated compression-expansion of color channels. +/// +public static class CompandingUtilities +{ + private const int Length = Scale + 2; // 256kb @ 16bit precision. + private const int Scale = (1 << 16) - 1; + private static readonly ConcurrentDictionary<(Type, double), float[]> CompressLookupTables = new(); + private static readonly ConcurrentDictionary<(Type, double), float[]> ExpandLookupTables = new(); + + /// + /// Lazily creates and stores a companding compression lookup table using the given function and modifier. + /// + /// The type of companding function. + /// The companding function. + /// A modifier to pass to the function. + /// The array. + public static float[] GetCompressLookupTable(Func compandingFunction, double modifier = 0) + => CompressLookupTables.GetOrAdd((typeof(T), modifier), args => CreateLookupTableImpl(compandingFunction, args.Item2)); + + /// + /// Lazily creates and stores a companding expanding lookup table using the given function and modifier. + /// + /// The type of companding function. + /// The companding function. + /// A modifier to pass to the function. + /// The array. + public static float[] GetExpandLookupTable(Func compandingFunction, double modifier = 0) + => ExpandLookupTables.GetOrAdd((typeof(T), modifier), args => CreateLookupTableImpl(compandingFunction, args.Item2)); + + /// + /// Creates a companding lookup table using the given function. + /// + /// The companding function. + /// A modifier to pass to the function. + /// The array. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static float[] CreateLookupTableImpl(Func compandingFunction, double modifier = 0) + { + float[] result = new float[Length]; + + for (int i = 0; i < result.Length; i++) + { + double d = (double)i / Scale; + d = compandingFunction(d, modifier); + result[i] = (float)d; + } + + return result; + } + + /// + /// Performs the companding operation on the given vectors using the given table. + /// + /// The span of vectors. + /// The lookup table. + public static void Compand(Span vectors, float[] table) + { + DebugGuard.MustBeGreaterThanOrEqualTo(table.Length, Length, nameof(table)); + + if (Avx2.IsSupported && vectors.Length >= 2) + { + CompandAvx2(vectors, table); + + if (Numerics.Modulo2(vectors.Length) != 0) + { + // Vector4 fits neatly in pairs. Any overlap has to be equal to 1. + ref Vector4 last = ref MemoryMarshal.GetReference(vectors[^1..]); + last = Compand(last, table); + } + } + else + { + CompandScalar(vectors, table); + } + } + + /// + /// Performs the companding operation on the given vector using the given table. + /// + /// The vector. + /// The lookup table. + /// The + public static Vector4 Compand(Vector4 vector, float[] table) + { + DebugGuard.MustBeGreaterThanOrEqualTo(table.Length, Length, nameof(table)); + + Vector4 zero = Vector4.Zero; + Vector4 scale = new(Scale); + + Vector4 multiplied = Numerics.Clamp(vector * Scale, zero, scale); + + float f0 = multiplied.X; + float f1 = multiplied.Y; + float f2 = multiplied.Z; + + uint i0 = (uint)f0; + uint i1 = (uint)f1; + uint i2 = (uint)f2; + + // Alpha is already a linear representation of opacity so we do not want to convert it. + vector.X = Numerics.Lerp(table[i0], table[i0 + 1], f0 - (int)i0); + vector.Y = Numerics.Lerp(table[i1], table[i1 + 1], f1 - (int)i1); + vector.Z = Numerics.Lerp(table[i2], table[i2 + 1], f2 - (int)i2); + + return vector; + } + + private static unsafe void CompandAvx2(Span vectors, float[] table) + { + fixed (float* tablePointer = &MemoryMarshal.GetArrayDataReference(table)) + { + Vector256 scale = Vector256.Create((float)Scale); + Vector256 zero = Vector256.Zero; + Vector256 offset = Vector256.Create(1); + + // Divide by 2 as 4 elements per Vector4 and 8 per Vector256 + ref Vector256 vectorsBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(vectors)); + ref Vector256 vectorsLast = ref Unsafe.Add(ref vectorsBase, (uint)vectors.Length / 2u); + + while (Unsafe.IsAddressLessThan(ref vectorsBase, ref vectorsLast)) + { + Vector256 multiplied = Avx.Multiply(scale, vectorsBase); + multiplied = Avx.Min(Avx.Max(zero, multiplied), scale); + + Vector256 truncated = Avx.ConvertToVector256Int32WithTruncation(multiplied); + Vector256 truncatedF = Avx.ConvertToVector256Single(truncated); + + Vector256 low = Avx2.GatherVector256(tablePointer, truncated, sizeof(float)); + Vector256 high = Avx2.GatherVector256(tablePointer, Avx2.Add(truncated, offset), sizeof(float)); + + // Alpha is already a linear representation of opacity so we do not want to convert it. + Vector256 companded = Numerics.Lerp(low, high, Avx.Subtract(multiplied, truncatedF)); + vectorsBase = Avx.Blend(companded, vectorsBase, Numerics.BlendAlphaControl); + vectorsBase = ref Unsafe.Add(ref vectorsBase, 1); + } + } + } + + private static unsafe void CompandScalar(Span vectors, float[] table) + { + fixed (float* tablePointer = &MemoryMarshal.GetArrayDataReference(table)) + { + Vector4 zero = Vector4.Zero; + Vector4 scale = new(Scale); + ref Vector4 vectorsBase = ref MemoryMarshal.GetReference(vectors); + ref Vector4 vectorsLast = ref Unsafe.Add(ref vectorsBase, (uint)vectors.Length); + + while (Unsafe.IsAddressLessThan(ref vectorsBase, ref vectorsLast)) + { + Vector4 multiplied = Numerics.Clamp(vectorsBase * Scale, zero, scale); + + float f0 = multiplied.X; + float f1 = multiplied.Y; + float f2 = multiplied.Z; + + uint i0 = (uint)f0; + uint i1 = (uint)f1; + uint i2 = (uint)f2; + + // Alpha is already a linear representation of opacity so we do not want to convert it. + vectorsBase.X = Numerics.Lerp(tablePointer[i0], tablePointer[i0 + 1], f0 - (int)i0); + vectorsBase.Y = Numerics.Lerp(tablePointer[i1], tablePointer[i1 + 1], f1 - (int)i1); + vectorsBase.Z = Numerics.Lerp(tablePointer[i2], tablePointer[i2 + 1], f2 - (int)i2); + + vectorsBase = ref Unsafe.Add(ref vectorsBase, 1); + } + } + } +} diff --git a/src/ImageSharp/ColorProfiles/Companding/GammaCompanding.cs b/src/ImageSharp/ColorProfiles/Companding/GammaCompanding.cs new file mode 100644 index 0000000000..34ca8bf5e3 --- /dev/null +++ b/src/ImageSharp/ColorProfiles/Companding/GammaCompanding.cs @@ -0,0 +1,56 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using System.Numerics; + +namespace SixLabors.ImageSharp.ColorProfiles.Companding; + +/// +/// Implements gamma companding. +/// +/// +/// +/// +/// +public static class GammaCompanding +{ + private static Func CompressFunction => (d, m) => Math.Pow(d, 1 / m); + + private static Func ExpandFunction => Math.Pow; + + /// + /// Compresses the linear vectors to their nonlinear equivalents with respect to the energy. + /// + /// The span of vectors. + /// The gamma value. + public static void Compress(Span vectors, double gamma) + => CompandingUtilities.Compand(vectors, CompandingUtilities.GetCompressLookupTable(CompressFunction, gamma)); + + /// + /// Expands the nonlinear vectors to their linear equivalents with respect to the energy. + /// + /// The span of vectors. + /// The gamma value. + public static void Expand(Span vectors, double gamma) + => CompandingUtilities.Compand(vectors, CompandingUtilities.GetExpandLookupTable(ExpandFunction, gamma)); + + /// + /// Compresses the linear vector to its nonlinear equivalent with respect to the energy. + /// + /// The vector. + /// The gamma value. + /// The . + public static Vector4 Compress(Vector4 vector, double gamma) + => CompandingUtilities.Compand(vector, CompandingUtilities.GetCompressLookupTable(CompressFunction, gamma)); + + /// + /// Expands the nonlinear vector to its linear equivalent with respect to the energy. + /// + /// The vector. + /// The gamma value. + /// The . + public static Vector4 Expand(Vector4 vector, double gamma) + => CompandingUtilities.Compand(vector, CompandingUtilities.GetExpandLookupTable(ExpandFunction, gamma)); + + private class GammaCompandingKey; +} diff --git a/src/ImageSharp/ColorProfiles/Companding/LCompanding.cs b/src/ImageSharp/ColorProfiles/Companding/LCompanding.cs new file mode 100644 index 0000000000..4f53830380 --- /dev/null +++ b/src/ImageSharp/ColorProfiles/Companding/LCompanding.cs @@ -0,0 +1,71 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using System.Numerics; + +namespace SixLabors.ImageSharp.ColorProfiles.Companding; + +/// +/// Implements L* companding. +/// +/// +/// For more info see: +/// +/// +/// +public static class LCompanding +{ + private static Func CompressFunction + => (d, _) => + { + if (d <= CieConstants.Epsilon) + { + return (d * CieConstants.Kappa) / 100; + } + + return (1.16 * Math.Pow(d, 0.3333333)) - 0.16; + }; + + private static Func ExpandFunction + => (d, _) => + { + if (d <= 0.08) + { + return (100 * d) / CieConstants.Kappa; + } + + return Numerics.Pow3(((float)(d + 0.16f)) / 1.16f); + }; + + /// + /// Compresses the linear vectors to their nonlinear equivalents with respect to the energy. + /// + /// The span of vectors. + public static void Compress(Span vectors) + => CompandingUtilities.Compand(vectors, CompandingUtilities.GetCompressLookupTable(CompressFunction)); + + /// + /// Expands the nonlinear vectors to their linear equivalents with respect to the energy. + /// + /// The span of vectors. + public static void Expand(Span vectors) + => CompandingUtilities.Compand(vectors, CompandingUtilities.GetExpandLookupTable(ExpandFunction)); + + /// + /// Compresses the linear vector to its nonlinear equivalent with respect to the energy. + /// + /// The vector. + /// The . + public static Vector4 Compress(Vector4 vector) + => CompandingUtilities.Compand(vector, CompandingUtilities.GetCompressLookupTable(CompressFunction)); + + /// + /// Expands the nonlinear vector to its linear equivalent with respect to the energy. + /// + /// The vector. + /// The . + public static Vector4 Expand(Vector4 vector) + => CompandingUtilities.Compand(vector, CompandingUtilities.GetExpandLookupTable(ExpandFunction)); + + private class LCompandingKey; +} diff --git a/src/ImageSharp/ColorProfiles/Companding/Rec2020Companding.cs b/src/ImageSharp/ColorProfiles/Companding/Rec2020Companding.cs new file mode 100644 index 0000000000..1901e64713 --- /dev/null +++ b/src/ImageSharp/ColorProfiles/Companding/Rec2020Companding.cs @@ -0,0 +1,75 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using System.Numerics; + +namespace SixLabors.ImageSharp.ColorProfiles.Companding; + +/// +/// Implements Rec. 2020 companding function. +/// +/// +/// +/// +public static class Rec2020Companding +{ + private const double Alpha = 1.09929682680944; + private const double AlphaMinusOne = Alpha - 1; + private const double Beta = 0.018053968510807; + private const double InverseBeta = Beta * 4.5; + private const double Epsilon = 1 / 0.45; + + private static Func CompressFunction + => (d, _) => + { + if (d < Beta) + { + return 4.5 * d; + } + + return (Alpha * Math.Pow(d, 0.45)) - AlphaMinusOne; + }; + + private static Func ExpandFunction + => (d, _) => + { + if (d < InverseBeta) + { + return d / 4.5; + } + + return Math.Pow((d + AlphaMinusOne) / Alpha, Epsilon); + }; + + /// + /// Compresses the linear vectors to their nonlinear equivalents with respect to the energy. + /// + /// The span of vectors. + public static void Compress(Span vectors) + => CompandingUtilities.Compand(vectors, CompandingUtilities.GetCompressLookupTable(CompressFunction)); + + /// + /// Expands the nonlinear vectors to their linear equivalents with respect to the energy. + /// + /// The span of vectors. + public static void Expand(Span vectors) + => CompandingUtilities.Compand(vectors, CompandingUtilities.GetExpandLookupTable(ExpandFunction)); + + /// + /// Compresses the linear vector to its nonlinear equivalent with respect to the energy. + /// + /// The vector. + /// The . + public static Vector4 Compress(Vector4 vector) + => CompandingUtilities.Compand(vector, CompandingUtilities.GetCompressLookupTable(CompressFunction)); + + /// + /// Expands the nonlinear vector to its linear equivalent with respect to the energy. + /// + /// The vector. + /// The . + public static Vector4 Expand(Vector4 vector) + => CompandingUtilities.Compand(vector, CompandingUtilities.GetExpandLookupTable(ExpandFunction)); + + private class Rec2020CompandingKey; +} diff --git a/src/ImageSharp/ColorProfiles/Companding/Rec709Companding.cs b/src/ImageSharp/ColorProfiles/Companding/Rec709Companding.cs new file mode 100644 index 0000000000..94b17d8d08 --- /dev/null +++ b/src/ImageSharp/ColorProfiles/Companding/Rec709Companding.cs @@ -0,0 +1,71 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using System.Numerics; + +namespace SixLabors.ImageSharp.ColorProfiles.Companding; + +/// +/// Implements the Rec. 709 companding function. +/// +/// +/// http://en.wikipedia.org/wiki/Rec._709 +/// +public static class Rec709Companding +{ + private const double Epsilon = 1 / 0.45; + + private static Func CompressFunction + => (d, _) => + { + if (d < 0.018) + { + return 4.5 * d; + } + + return (1.099 * Math.Pow(d, 0.45)) - 0.099; + }; + + private static Func ExpandFunction + => (d, _) => + { + if (d < 0.081) + { + return d / 4.5; + } + + return Math.Pow((d + 0.099) / 1.099, Epsilon); + }; + + /// + /// Compresses the linear vectors to their nonlinear equivalents with respect to the energy. + /// + /// The span of vectors. + public static void Compress(Span vectors) + => CompandingUtilities.Compand(vectors, CompandingUtilities.GetCompressLookupTable(CompressFunction)); + + /// + /// Expands the nonlinear vectors to their linear equivalents with respect to the energy. + /// + /// The span of vectors. + public static void Expand(Span vectors) + => CompandingUtilities.Compand(vectors, CompandingUtilities.GetExpandLookupTable(ExpandFunction)); + + /// + /// Compresses the linear vector to its nonlinear equivalent with respect to the energy. + /// + /// The vector. + /// The . + public static Vector4 Compress(Vector4 vector) + => CompandingUtilities.Compand(vector, CompandingUtilities.GetCompressLookupTable(CompressFunction)); + + /// + /// Expands the nonlinear vector to its linear equivalent with respect to the energy. + /// + /// The vector. + /// The . + public static Vector4 Expand(Vector4 vector) + => CompandingUtilities.Compand(vector, CompandingUtilities.GetExpandLookupTable(ExpandFunction)); + + private class Rec2020CompandingKey; +} diff --git a/src/ImageSharp/ColorProfiles/Companding/SRgbCompanding.cs b/src/ImageSharp/ColorProfiles/Companding/SRgbCompanding.cs new file mode 100644 index 0000000000..ab27102306 --- /dev/null +++ b/src/ImageSharp/ColorProfiles/Companding/SRgbCompanding.cs @@ -0,0 +1,71 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using System.Numerics; + +namespace SixLabors.ImageSharp.ColorProfiles.Companding; + +/// +/// Implements sRGB companding. +/// +/// +/// For more info see: +/// +/// +/// +public static class SRgbCompanding +{ + private static Func CompressFunction + => (d, _) => + { + if (d <= (0.04045 / 12.92)) + { + return d * 12.92; + } + + return (1.055 * Math.Pow(d, 1.0 / 2.4)) - 0.055; + }; + + private static Func ExpandFunction + => (d, _) => + { + if (d <= 0.04045) + { + return d / 12.92; + } + + return Math.Pow((d + 0.055) / 1.055, 2.4); + }; + + /// + /// Compresses the linear vectors to their nonlinear equivalents with respect to the energy. + /// + /// The span of vectors. + public static void Compress(Span vectors) + => CompandingUtilities.Compand(vectors, CompandingUtilities.GetCompressLookupTable(CompressFunction)); + + /// + /// Expands the nonlinear vectors to their linear equivalents with respect to the energy. + /// + /// The span of vectors. + public static void Expand(Span vectors) + => CompandingUtilities.Compand(vectors, CompandingUtilities.GetExpandLookupTable(ExpandFunction)); + + /// + /// Compresses the linear vector to its nonlinear equivalent with respect to the energy. + /// + /// The vector. + /// The . + public static Vector4 Compress(Vector4 vector) + => CompandingUtilities.Compand(vector, CompandingUtilities.GetCompressLookupTable(CompressFunction)); + + /// + /// Expands the nonlinear vector to its linear equivalent with respect to the energy. + /// + /// The vector. + /// The . + public static Vector4 Expand(Vector4 vector) + => CompandingUtilities.Compand(vector, CompandingUtilities.GetExpandLookupTable(ExpandFunction)); + + private class SRgbCompandingKey; +} diff --git a/src/ImageSharp/ColorProfiles/Hsl.cs b/src/ImageSharp/ColorProfiles/Hsl.cs new file mode 100644 index 0000000000..2c98c7df99 --- /dev/null +++ b/src/ImageSharp/ColorProfiles/Hsl.cs @@ -0,0 +1,245 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +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; + private static readonly Vector3 Max = new(360, 1, 1); + + /// + /// Initializes a new instance of the struct. + /// + /// The h hue component. + /// The s saturation component. + /// The l value (lightness) component. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Hsl(float h, float s, float l) + : this(new Vector3(h, s, l)) + { + } + + /// + /// Initializes a new instance of the struct. + /// + /// The vector representing the h, s, l components. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Hsl(Vector3 vector) + { + vector = Vector3.Clamp(vector, Min, Max); + this.H = vector.X; + this.S = vector.Y; + this.L = vector.Z; + } + + /// + /// Gets the hue component. + /// A value ranging between 0 and 360. + /// + public float H { get; } + + /// + /// Gets the saturation component. + /// A value ranging between 0 and 1. + /// + public float S { get; } + + /// + /// Gets the lightness component. + /// A value ranging between 0 and 1. + /// + public float L { get; } + + /// + /// Compares two objects for equality. + /// + /// + /// 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 ==(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. + /// + /// True if the current left is unequal to the parameter; otherwise, false. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool operator !=(Hsl left, Hsl right) => !left.Equals(right); + + /// + public static Hsl FromProfileConnectingSpace(ColorConversionOptions options, in Rgb source) + { + float r = source.R; + float g = source.G; + float b = source.B; + + float max = MathF.Max(r, MathF.Max(g, b)); + float min = MathF.Min(r, MathF.Min(g, b)); + float chroma = max - min; + float h = 0F; + float s = 0F; + float l = (max + min) / 2F; + + if (MathF.Abs(chroma) < Constants.Epsilon) + { + return new Hsl(0F, s, l); + } + + if (MathF.Abs(r - max) < Constants.Epsilon) + { + h = (g - b) / chroma; + } + else if (MathF.Abs(g - max) < Constants.Epsilon) + { + h = 2F + ((b - r) / chroma); + } + else if (MathF.Abs(b - max) < Constants.Epsilon) + { + h = 4F + ((r - g) / chroma); + } + + h *= 60F; + if (h < -Constants.Epsilon) + { + h += 360F; + } + + if (l <= .5F) + { + s = chroma / (max + min); + } + else + { + s = chroma / (2F - max - min); + } + + return new Hsl(h, s, l); + } + + /// + public static void FromProfileConnectionSpace(ColorConversionOptions options, ReadOnlySpan source, Span destination) + { + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + for (int i = 0; i < source.Length; i++) + { + Rgb rgb = source[i]; + destination[i] = FromProfileConnectingSpace(options, in rgb); + } + } + + /// + public Rgb ToProfileConnectingSpace(ColorConversionOptions options) + { + float rangedH = this.H / 360F; + float r = 0; + float g = 0; + float b = 0; + float s = this.S; + float l = this.L; + + if (MathF.Abs(l) > Constants.Epsilon) + { + if (MathF.Abs(s) < Constants.Epsilon) + { + r = g = b = l; + } + else + { + float temp2 = (l < .5F) ? l * (1F + s) : l + s - (l * s); + float temp1 = (2F * l) - temp2; + + r = GetColorComponent(temp1, temp2, rangedH + 0.3333333F); + g = GetColorComponent(temp1, temp2, rangedH); + b = GetColorComponent(temp1, temp2, rangedH - 0.3333333F); + } + } + + return new Rgb(r, g, b); + } + + /// + public static void ToProfileConnectionSpace(ColorConversionOptions options, ReadOnlySpan source, Span destination) + { + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + for (int i = 0; i < source.Length; i++) + { + Hsl hsl = source[i]; + destination[i] = hsl.ToProfileConnectingSpace(options); + } + } + + /// + public static ChromaticAdaptionWhitePointSource GetChromaticAdaptionWhitePointSource() + => ChromaticAdaptionWhitePointSource.RgbWorkingSpace; + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public override int GetHashCode() => HashCode.Combine(this.H, this.S, this.L); + + /// + public override string ToString() => FormattableString.Invariant($"Hsl({this.H:#0.##}, {this.S:#0.##}, {this.L:#0.##})"); + + /// + public override bool Equals(object? obj) => obj is Hsl other && this.Equals(other); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool Equals(Hsl other) + => 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) + { + third = MoveIntoRange(third); + if (third < 0.1666667F) + { + return first + ((second - first) * 6F * third); + } + + if (third < .5F) + { + return second; + } + + if (third < 0.6666667F) + { + return first + ((second - first) * (0.6666667F - third) * 6F); + } + + return first; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static float MoveIntoRange(float value) + { + if (value < 0F) + { + value++; + } + else if (value > 1F) + { + value--; + } + + return value; + } +} diff --git a/src/ImageSharp/ColorProfiles/Hsv.cs b/src/ImageSharp/ColorProfiles/Hsv.cs new file mode 100644 index 0000000000..7535f2463d --- /dev/null +++ b/src/ImageSharp/ColorProfiles/Hsv.cs @@ -0,0 +1,231 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +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; + private static readonly Vector3 Max = new(360, 1, 1); + + /// + /// Initializes a new instance of the struct. + /// + /// The h hue component. + /// The s saturation component. + /// The v value (brightness) component. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Hsv(float h, float s, float v) + : this(new Vector3(h, s, v)) + { + } + + /// + /// Initializes a new instance of the struct. + /// + /// The vector representing the h, s, v components. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Hsv(Vector3 vector) + { + vector = Vector3.Clamp(vector, Min, Max); + 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 { get; } + + /// + /// Gets the saturation component. + /// A value ranging between 0 and 1. + /// + public float S { get; } + + /// + /// Gets the value (brightness) component. + /// A value ranging between 0 and 1. + /// + public float V { get; } + + /// + /// Compares two objects for equality. + /// + /// 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) => left.Equals(right); + + /// + /// Compares two objects for inequality. + /// + /// 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) => !left.Equals(right); + + /// + public static Hsv FromProfileConnectingSpace(ColorConversionOptions options, in Rgb source) + { + float r = source.R; + float g = source.G; + float b = source.B; + + float max = MathF.Max(r, MathF.Max(g, b)); + float min = MathF.Min(r, MathF.Min(g, b)); + float chroma = max - min; + float h = 0; + float s = 0; + float v = max; + + if (MathF.Abs(chroma) < Constants.Epsilon) + { + return new Hsv(0, s, v); + } + + if (MathF.Abs(r - max) < Constants.Epsilon) + { + h = (g - b) / chroma; + } + else if (MathF.Abs(g - max) < Constants.Epsilon) + { + h = 2 + ((b - r) / chroma); + } + else if (MathF.Abs(b - max) < Constants.Epsilon) + { + h = 4 + ((r - g) / chroma); + } + + h *= 60F; + if (h < -Constants.Epsilon) + { + h += 360F; + } + + s = chroma / v; + + return new Hsv(h, s, v); + } + + /// + public static void FromProfileConnectionSpace(ColorConversionOptions options, ReadOnlySpan source, Span destination) + { + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + for (int i = 0; i < source.Length; i++) + { + Rgb rgb = source[i]; + destination[i] = FromProfileConnectingSpace(options, in rgb); + } + } + + /// + public Rgb ToProfileConnectingSpace(ColorConversionOptions options) + { + float s = this.S; + float v = this.V; + + if (MathF.Abs(s) < Constants.Epsilon) + { + return new Rgb(v, v, v); + } + + float h = (MathF.Abs(this.H - 360) < Constants.Epsilon) ? 0 : this.H / 60; + int i = (int)Math.Truncate(h); + float f = h - i; + + float p = v * (1F - s); + float q = v * (1F - (s * f)); + float t = v * (1F - (s * (1F - f))); + + float r, g, b; + switch (i) + { + case 0: + r = v; + g = t; + b = p; + break; + + case 1: + r = q; + g = v; + b = p; + break; + + case 2: + r = p; + g = v; + b = t; + break; + + case 3: + r = p; + g = q; + b = v; + break; + + case 4: + r = t; + g = p; + b = v; + break; + + default: + r = v; + g = p; + b = q; + break; + } + + return new Rgb(r, g, b); + } + + /// + public static void ToProfileConnectionSpace(ColorConversionOptions options, ReadOnlySpan source, Span destination) + { + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + for (int i = 0; i < source.Length; i++) + { + Hsv hsv = source[i]; + destination[i] = hsv.ToProfileConnectingSpace(options); + } + } + + /// + public static ChromaticAdaptionWhitePointSource GetChromaticAdaptionWhitePointSource() + => ChromaticAdaptionWhitePointSource.RgbWorkingSpace; + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public override int GetHashCode() => HashCode.Combine(this.H, this.S, this.V); + + /// + public override string ToString() => FormattableString.Invariant($"Hsv({this.H:#0.##}, {this.S:#0.##}, {this.V:#0.##})"); + + /// + public override bool Equals(object? obj) => obj is Hsv other && this.Equals(other); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool Equals(Hsv other) + => 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 new file mode 100644 index 0000000000..43ad2ac5c0 --- /dev/null +++ b/src/ImageSharp/ColorProfiles/HunterLab.cs @@ -0,0 +1,200 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using System.Numerics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace SixLabors.ImageSharp.ColorProfiles; + +/// +/// Represents an Hunter LAB color. +/// . +/// +[StructLayout(LayoutKind.Sequential)] +public readonly struct HunterLab : IColorProfile +{ + /// + /// Initializes a new instance of the struct. + /// + /// The lightness dimension. + /// The a (green - magenta) component. + /// The b (blue - yellow) component. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public HunterLab(float l, float a, float b) + { + this.L = l; + this.A = a; + this.B = b; + } + + /// + /// Initializes a new instance of the struct. + /// + /// The vector representing the l a b components. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public HunterLab(Vector3 vector) + { + // Not clamping as documentation about this space only indicates "usual" ranges + this.L = vector.X; + this.A = vector.Y; + this.B = vector.Z; + } + + /// + /// Gets the lightness dimension. + /// A value usually ranging between 0 (black), 100 (diffuse white) or higher (specular white). + /// + public float L { get; } + + /// + /// Gets the a color component. + /// A value usually ranging from -100 to 100. Negative is green, positive magenta. + /// + public float A { get; } + + /// + /// Gets the b color component. + /// A value usually ranging from -100 to 100. Negative is blue, positive is yellow + /// + public float B { get; } + + /// + /// Compares two objects for equality. + /// + /// 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) => left.Equals(right); + + /// + /// Compares two objects for inequality + /// + /// 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) => !left.Equals(right); + + /// + public static HunterLab FromProfileConnectingSpace(ColorConversionOptions options, in CieXyz source) + { + // Conversion algorithm described here: + // http://en.wikipedia.org/wiki/Lab_color_space#Hunter_Lab + CieXyz whitePoint = options.TargetWhitePoint; + float x = source.X, y = source.Y, z = source.Z; + float xn = whitePoint.X, yn = whitePoint.Y, zn = whitePoint.Z; + + float ka = ComputeKa(in whitePoint); + float kb = ComputeKb(in whitePoint); + + float yByYn = y / yn; + float sqrtYbyYn = MathF.Sqrt(yByYn); + float l = 100 * sqrtYbyYn; + float a = ka * (((x / xn) - yByYn) / sqrtYbyYn); + float b = kb * ((yByYn - (z / zn)) / sqrtYbyYn); + + if (float.IsNaN(a)) + { + a = 0; + } + + if (float.IsNaN(b)) + { + b = 0; + } + + return new HunterLab(l, a, b); + } + + /// + public static void FromProfileConnectionSpace(ColorConversionOptions options, ReadOnlySpan source, Span destination) + { + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + for (int i = 0; i < source.Length; i++) + { + CieXyz xyz = source[i]; + destination[i] = FromProfileConnectingSpace(options, in xyz); + } + } + + /// + public CieXyz ToProfileConnectingSpace(ColorConversionOptions options) + { + // Conversion algorithm described here: + // http://en.wikipedia.org/wiki/Lab_color_space#Hunter_Lab + CieXyz whitePoint = options.WhitePoint; + float l = this.L, a = this.A, b = this.B; + float xn = whitePoint.X, yn = whitePoint.Y, zn = whitePoint.Z; + + float ka = ComputeKa(in whitePoint); + float kb = ComputeKb(in whitePoint); + + float pow = Numerics.Pow2(l / 100F); + float sqrtPow = MathF.Sqrt(pow); + float y = pow * yn; + + float x = (((a / ka) * sqrtPow) + pow) * xn; + float z = (((b / kb) * sqrtPow) - pow) * (-zn); + + return new CieXyz(x, y, z); + } + + /// + public static void ToProfileConnectionSpace(ColorConversionOptions options, ReadOnlySpan source, Span destination) + { + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + for (int i = 0; i < source.Length; i++) + { + HunterLab lab = source[i]; + destination[i] = lab.ToProfileConnectingSpace(options); + } + } + + /// + public static ChromaticAdaptionWhitePointSource GetChromaticAdaptionWhitePointSource() + => ChromaticAdaptionWhitePointSource.WhitePoint; + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public override int GetHashCode() => HashCode.Combine(this.L, this.A, this.B); + + /// + public override string ToString() => FormattableString.Invariant($"HunterLab({this.L:#0.##}, {this.A:#0.##}, {this.B:#0.##})"); + + /// + public override bool Equals(object? obj) => obj is HunterLab other && this.Equals(other); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool Equals(HunterLab other) + => this.AsVector3Unsafe() == other.AsVector3Unsafe(); + + private Vector3 AsVector3Unsafe() => Unsafe.As(ref Unsafe.AsRef(in this)); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static float ComputeKa(in CieXyz whitePoint) + { + if (whitePoint.Equals(KnownIlluminants.C)) + { + return 175F; + } + + return 100F * (175F / 198.04F) * (whitePoint.X + whitePoint.Y); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static float ComputeKb(in CieXyz whitePoint) + { + if (whitePoint == KnownIlluminants.C) + { + return 70F; + } + + return 100F * (70F / 218.11F) * (whitePoint.Y + whitePoint.Z); + } +} diff --git a/src/ImageSharp/ColorProfiles/IColorProfile.cs b/src/ImageSharp/ColorProfiles/IColorProfile.cs new file mode 100644 index 0000000000..6a1b2ee8d0 --- /dev/null +++ b/src/ImageSharp/ColorProfiles/IColorProfile.cs @@ -0,0 +1,59 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +namespace SixLabors.ImageSharp.ColorProfiles; + +/// +/// Defines the contract for all color profiles. +/// +public interface IColorProfile +{ + /// + /// Gets the chromatic adaption white point source. + /// + /// The . + public static abstract ChromaticAdaptionWhitePointSource GetChromaticAdaptionWhitePointSource(); +} + +/// +/// Defines the contract for all color profiles. +/// +/// The type of color profile. +/// The type of color profile connecting space. +public interface IColorProfile : IColorProfile, IEquatable + where TSelf : IColorProfile + where TProfileSpace : struct, IProfileConnectingSpace +{ +#pragma warning disable CA1000 // Do not declare static members on generic types + /// + /// Converts the color from the profile connection space. + /// + /// The color profile conversion options. + /// The color profile connecting space. + /// The . + public static abstract TSelf FromProfileConnectingSpace(ColorConversionOptions options, in TProfileSpace source); + + /// + /// Converts the span of colors from the profile connection space. + /// + /// The color profile conversion options. + /// The color profile span to convert from. + /// The color span to write the results to. + public static abstract void FromProfileConnectionSpace(ColorConversionOptions options, ReadOnlySpan source, Span destination); + + /// + /// Converts the color to the profile connection space. + /// + /// The color profile conversion options. + /// The . + public TProfileSpace ToProfileConnectingSpace(ColorConversionOptions options); + + /// + /// Converts the span of colors to the profile connection space. + /// + /// The color profile conversion options. + /// The color span to convert from. + /// The color profile span to write the results to. + public static abstract void ToProfileConnectionSpace(ColorConversionOptions options, ReadOnlySpan source, Span destination); +#pragma warning restore CA1000 // Do not declare static members on generic types +} diff --git a/src/ImageSharp/ColorProfiles/IProfileConnectingSpace.cs b/src/ImageSharp/ColorProfiles/IProfileConnectingSpace.cs new file mode 100644 index 0000000000..2ac736f444 --- /dev/null +++ b/src/ImageSharp/ColorProfiles/IProfileConnectingSpace.cs @@ -0,0 +1,18 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +namespace SixLabors.ImageSharp.ColorProfiles; + +/// +/// Defines the contract for all color profile connection spaces. +/// +public interface IProfileConnectingSpace; + +/// +/// Defines the contract for all color profile connection spaces. +/// +/// The type of color profile. +/// The type of color profile connecting space. +public interface IProfileConnectingSpace : IColorProfile, IProfileConnectingSpace + where TSelf : struct, IColorProfile, IProfileConnectingSpace + where TProfileSpace : struct, IProfileConnectingSpace; diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/LmsAdaptationMatrix.cs b/src/ImageSharp/ColorProfiles/KnownChromaticAdaptationMatrices.cs similarity index 76% rename from src/ImageSharp/ColorSpaces/Conversion/Implementation/LmsAdaptationMatrix.cs rename to src/ImageSharp/ColorProfiles/KnownChromaticAdaptationMatrices.cs index 80bd160e8a..71d565f87f 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/LmsAdaptationMatrix.cs +++ b/src/ImageSharp/ColorProfiles/KnownChromaticAdaptationMatrices.cs @@ -3,23 +3,25 @@ using System.Numerics; -namespace SixLabors.ImageSharp.ColorSpaces.Conversion; +namespace SixLabors.ImageSharp.ColorProfiles; /// -/// Matrices used for transformation from to , defining the cone response domain. -/// Used in +/// Provides matrices for chromatic adaptation, facilitating the adjustment of color values +/// under different light sources to maintain color constancy. This class supports common +/// adaptation transforms based on the von Kries coefficient law, which assumes independent +/// scaling of the cone responses in the human eye. These matrices can be applied to convert +/// color coordinates between different illuminants, ensuring consistent color appearance +/// across various lighting conditions. /// /// -/// Matrix data obtained from: -/// Two New von Kries Based Chromatic Adaptation Transforms Found by Numerical Optimization -/// S. Bianco, R. Schettini -/// DISCo, Department of Informatics, Systems and Communication, University of Milan-Bicocca, viale Sarca 336, 20126 Milan, Italy -/// https://web.stanford.edu/~sujason/ColorBalancing/Papers/Two%20New%20von%20Kries%20Based%20Chromatic%20Adaptation.pdf +/// Supported adaptation matrices include the Bradford, von Kries, and Sharp transforms. +/// These matrices are typically used in conjunction with color space conversions, such as from XYZ +/// to RGB, to achieve accurate color rendition in digital imaging applications. /// -public static class LmsAdaptationMatrix +public static class KnownChromaticAdaptationMatrices { /// - /// Von Kries chromatic adaptation transform matrix (Hunt-Pointer-Estevez adjusted for D65) + /// von Kries chromatic adaptation transform matrix (Hunt-Pointer-Estevez adjusted for D65) /// public static readonly Matrix4x4 VonKriesHPEAdjusted = Matrix4x4.Transpose(new Matrix4x4 @@ -37,7 +39,7 @@ public static class LmsAdaptationMatrix }); /// - /// Von Kries chromatic adaptation transform matrix (Hunt-Pointer-Estevez for equal energy) + /// von Kries chromatic adaptation transform matrix (Hunt-Pointer-Estevez for equal energy) /// public static readonly Matrix4x4 VonKriesHPE = Matrix4x4.Transpose(new Matrix4x4 diff --git a/src/ImageSharp/ColorProfiles/KnownIlluminants.cs b/src/ImageSharp/ColorProfiles/KnownIlluminants.cs new file mode 100644 index 0000000000..b9236497fe --- /dev/null +++ b/src/ImageSharp/ColorProfiles/KnownIlluminants.cs @@ -0,0 +1,71 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +namespace SixLabors.ImageSharp.ColorProfiles; + +/// +/// The well known standard illuminants. +/// Standard illuminants provide a basis for comparing images or colors recorded under different lighting +/// +/// +/// Coefficients taken from: http://www.brucelindbloom.com/index.html?Eqn_ChromAdapt.html +///
+/// Descriptions taken from: http://en.wikipedia.org/wiki/Standard_illuminant +///
+public static class KnownIlluminants +{ + /// + /// Gets the Incandescent / Tungsten illuminant. + /// + public static CieXyz A { get; } = new(1.09850F, 1F, 0.35585F); + + /// + /// Gets the Direct sunlight at noon (obsoleteF) illuminant. + /// + public static CieXyz B { get; } = new(0.99072F, 1F, 0.85223F); + + /// + /// Gets the Average / North sky Daylight (obsoleteF) illuminant. + /// + public static CieXyz C { get; } = new(0.98074F, 1F, 1.18232F); + + /// + /// Gets the Horizon Light. ICC profile PCS illuminant. + /// + public static CieXyz D50 { get; } = new(0.96422F, 1F, 0.82521F); + + /// + /// Gets the Mid-morning / Mid-afternoon Daylight illuminant. + /// + public static CieXyz D55 { get; } = new(0.95682F, 1F, 0.92149F); + + /// + /// Gets the Noon Daylight: TelevisionF, sRGB color space illuminant. + /// + public static CieXyz D65 { get; } = new(0.95047F, 1F, 1.08883F); + + /// + /// Gets the North sky Daylight illuminant. + /// + public static CieXyz D75 { get; } = new(0.94972F, 1F, 1.22638F); + + /// + /// Gets the Equal energy illuminant. + /// + public static CieXyz E { get; } = new(1F, 1F, 1F); + + /// + /// Gets the Cool White Fluorescent illuminant. + /// + public static CieXyz F2 { get; } = new(0.99186F, 1F, 0.67393F); + + /// + /// Gets the D65 simulatorF, Daylight simulator illuminant. + /// + public static CieXyz F7 { get; } = new(0.95041F, 1F, 1.08747F); + + /// + /// Gets the Philips TL84F, Ultralume 40 illuminant. + /// + public static CieXyz F11 { get; } = new(1.00962F, 1F, 0.64350F); +} diff --git a/src/ImageSharp/ColorProfiles/KnownRgbWorkingSpaces.cs b/src/ImageSharp/ColorProfiles/KnownRgbWorkingSpaces.cs new file mode 100644 index 0000000000..9163839363 --- /dev/null +++ b/src/ImageSharp/ColorProfiles/KnownRgbWorkingSpaces.cs @@ -0,0 +1,113 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using SixLabors.ImageSharp.ColorProfiles.Companding; +using SixLabors.ImageSharp.ColorProfiles.WorkingSpaces; + +namespace SixLabors.ImageSharp.ColorProfiles; + +/// +/// Chromaticity coordinates based on: +/// +public static class KnownRgbWorkingSpaces +{ + /// + /// sRgb working space. + /// + /// + /// Uses proper companding function, according to: + /// + /// + public static readonly RgbWorkingSpace SRgb = new SRgbWorkingSpace(KnownIlluminants.D65, new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.6400F, 0.3300F), new CieXyChromaticityCoordinates(0.3000F, 0.6000F), new CieXyChromaticityCoordinates(0.1500F, 0.0600F))); + + /// + /// Simplified sRgb working space (uses gamma companding instead of ). + /// See also . + /// + public static readonly RgbWorkingSpace SRgbSimplified = new GammaWorkingSpace(2.2F, KnownIlluminants.D65, new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.6400F, 0.3300F), new CieXyChromaticityCoordinates(0.3000F, 0.6000F), new CieXyChromaticityCoordinates(0.1500F, 0.0600F))); + + /// + /// Rec. 709 (ITU-R Recommendation BT.709) working space. + /// + public static readonly RgbWorkingSpace Rec709 = new Rec709WorkingSpace(KnownIlluminants.D65, new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.64F, 0.33F), new CieXyChromaticityCoordinates(0.30F, 0.60F), new CieXyChromaticityCoordinates(0.15F, 0.06F))); + + /// + /// Rec. 2020 (ITU-R Recommendation BT.2020F) working space. + /// + public static readonly RgbWorkingSpace Rec2020 = new Rec2020WorkingSpace(KnownIlluminants.D65, new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.708F, 0.292F), new CieXyChromaticityCoordinates(0.170F, 0.797F), new CieXyChromaticityCoordinates(0.131F, 0.046F))); + + /// + /// ECI Rgb v2 working space. + /// + public static readonly RgbWorkingSpace ECIRgbv2 = new LWorkingSpace(KnownIlluminants.D50, new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.6700F, 0.3300F), new CieXyChromaticityCoordinates(0.2100F, 0.7100F), new CieXyChromaticityCoordinates(0.1400F, 0.0800F))); + + /// + /// Adobe Rgb (1998) working space. + /// + public static readonly RgbWorkingSpace AdobeRgb1998 = new GammaWorkingSpace(2.2F, KnownIlluminants.D65, new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.6400F, 0.3300F), new CieXyChromaticityCoordinates(0.2100F, 0.7100F), new CieXyChromaticityCoordinates(0.1500F, 0.0600F))); + + /// + /// Apple sRgb working space. + /// + public static readonly RgbWorkingSpace ApplesRgb = new GammaWorkingSpace(1.8F, KnownIlluminants.D65, new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.6250F, 0.3400F), new CieXyChromaticityCoordinates(0.2800F, 0.5950F), new CieXyChromaticityCoordinates(0.1550F, 0.0700F))); + + /// + /// Best Rgb working space. + /// + public static readonly RgbWorkingSpace BestRgb = new GammaWorkingSpace(2.2F, KnownIlluminants.D50, new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.7347F, 0.2653F), new CieXyChromaticityCoordinates(0.2150F, 0.7750F), new CieXyChromaticityCoordinates(0.1300F, 0.0350F))); + + /// + /// Beta Rgb working space. + /// + public static readonly RgbWorkingSpace BetaRgb = new GammaWorkingSpace(2.2F, KnownIlluminants.D50, new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.6888F, 0.3112F), new CieXyChromaticityCoordinates(0.1986F, 0.7551F), new CieXyChromaticityCoordinates(0.1265F, 0.0352F))); + + /// + /// Bruce Rgb working space. + /// + public static readonly RgbWorkingSpace BruceRgb = new GammaWorkingSpace(2.2F, KnownIlluminants.D65, new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.6400F, 0.3300F), new CieXyChromaticityCoordinates(0.2800F, 0.6500F), new CieXyChromaticityCoordinates(0.1500F, 0.0600F))); + + /// + /// CIE Rgb working space. + /// + public static readonly RgbWorkingSpace CIERgb = new GammaWorkingSpace(2.2F, KnownIlluminants.E, new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.7350F, 0.2650F), new CieXyChromaticityCoordinates(0.2740F, 0.7170F), new CieXyChromaticityCoordinates(0.1670F, 0.0090F))); + + /// + /// ColorMatch Rgb working space. + /// + public static readonly RgbWorkingSpace ColorMatchRgb = new GammaWorkingSpace(1.8F, KnownIlluminants.D50, new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.6300F, 0.3400F), new CieXyChromaticityCoordinates(0.2950F, 0.6050F), new CieXyChromaticityCoordinates(0.1500F, 0.0750F))); + + /// + /// Don Rgb 4 working space. + /// + public static readonly RgbWorkingSpace DonRgb4 = new GammaWorkingSpace(2.2F, KnownIlluminants.D50, new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.6960F, 0.3000F), new CieXyChromaticityCoordinates(0.2150F, 0.7650F), new CieXyChromaticityCoordinates(0.1300F, 0.0350F))); + + /// + /// Ekta Space PS5 working space. + /// + public static readonly RgbWorkingSpace EktaSpacePS5 = new GammaWorkingSpace(2.2F, KnownIlluminants.D50, new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.6950F, 0.3050F), new CieXyChromaticityCoordinates(0.2600F, 0.7000F), new CieXyChromaticityCoordinates(0.1100F, 0.0050F))); + + /// + /// NTSC Rgb working space. + /// + public static readonly RgbWorkingSpace NTSCRgb = new GammaWorkingSpace(2.2F, KnownIlluminants.C, new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.6700F, 0.3300F), new CieXyChromaticityCoordinates(0.2100F, 0.7100F), new CieXyChromaticityCoordinates(0.1400F, 0.0800F))); + + /// + /// PAL/SECAM Rgb working space. + /// + public static readonly RgbWorkingSpace PALSECAMRgb = new GammaWorkingSpace(2.2F, KnownIlluminants.D65, new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.6400F, 0.3300F), new CieXyChromaticityCoordinates(0.2900F, 0.6000F), new CieXyChromaticityCoordinates(0.1500F, 0.0600F))); + + /// + /// ProPhoto Rgb working space. + /// + public static readonly RgbWorkingSpace ProPhotoRgb = new GammaWorkingSpace(1.8F, KnownIlluminants.D50, new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.7347F, 0.2653F), new CieXyChromaticityCoordinates(0.1596F, 0.8404F), new CieXyChromaticityCoordinates(0.0366F, 0.0001F))); + + /// + /// SMPTE-C Rgb working space. + /// + public static readonly RgbWorkingSpace SMPTECRgb = new GammaWorkingSpace(2.2F, KnownIlluminants.D65, new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.6300F, 0.3400F), new CieXyChromaticityCoordinates(0.3100F, 0.5950F), new CieXyChromaticityCoordinates(0.1550F, 0.0700F))); + + /// + /// Wide Gamut Rgb working space. + /// + public static readonly RgbWorkingSpace WideGamutRgb = new GammaWorkingSpace(2.2F, KnownIlluminants.D50, new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.7350F, 0.2650F), new CieXyChromaticityCoordinates(0.1150F, 0.8260F), new CieXyChromaticityCoordinates(0.1570F, 0.0180F))); +} diff --git a/src/ImageSharp/ColorSpaces/Lms.cs b/src/ImageSharp/ColorProfiles/Lms.cs similarity index 58% rename from src/ImageSharp/ColorSpaces/Lms.cs rename to src/ImageSharp/ColorProfiles/Lms.cs index 99210ff6e4..5a6791b2d7 100644 --- a/src/ImageSharp/ColorSpaces/Lms.cs +++ b/src/ImageSharp/ColorProfiles/Lms.cs @@ -3,15 +3,17 @@ using System.Numerics; using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; -namespace SixLabors.ImageSharp.ColorSpaces; +namespace SixLabors.ImageSharp.ColorProfiles; /// /// 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. /// /// -public readonly struct Lms : IEquatable +[StructLayout(LayoutKind.Sequential)] +public readonly struct Lms : IColorProfile { /// /// Initializes a new instance of the struct. @@ -19,17 +21,19 @@ public readonly struct Lms : IEquatable /// L represents the responsivity at long wavelengths. /// M represents the responsivity at medium wavelengths. /// S represents the responsivity at short wavelengths. - [MethodImpl(InliningOptions.ShortMethod)] + [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; } /// /// Initializes a new instance of the struct. /// /// The vector representing the l, m, s components. - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public Lms(Vector3 vector) { // Not clamping as documentation about this space only indicates "usual" ranges @@ -42,19 +46,19 @@ public readonly struct Lms : IEquatable /// Gets the L long component. /// A value usually ranging between -1 and 1. /// - public readonly float L { get; } + public float L { get; } /// /// Gets the M medium component. /// A value usually ranging between -1 and 1. /// - public readonly float M { get; } + public float M { get; } /// /// Gets the S short component. /// A value usually ranging between -1 and 1. /// - public readonly float S { get; } + public float S { get; } /// /// Compares two objects for equality. @@ -64,7 +68,7 @@ public readonly struct Lms : IEquatable /// /// True if the current left is equal to the parameter; otherwise, false. /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(Lms left, Lms right) => left.Equals(right); /// @@ -75,16 +79,57 @@ public readonly struct Lms : IEquatable /// /// True if the current left is unequal to the parameter; otherwise, false. /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(Lms left, Lms right) => !left.Equals(right); /// /// Returns a new representing this instance. /// /// The . - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public Vector3 ToVector3() => new(this.L, this.M, this.S); + /// + public static Lms FromProfileConnectingSpace(ColorConversionOptions options, in CieXyz source) + { + Vector3 vector = Vector3.Transform(source.ToVector3(), options.AdaptationMatrix); + return new Lms(vector); + } + + /// + public static void FromProfileConnectionSpace(ColorConversionOptions options, ReadOnlySpan source, Span destination) + { + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + + for (int i = 0; i < source.Length; i++) + { + CieXyz xyz = source[i]; + destination[i] = FromProfileConnectingSpace(options, in xyz); + } + } + + /// + public CieXyz ToProfileConnectingSpace(ColorConversionOptions options) + { + Vector3 vector = Vector3.Transform(this.ToVector3(), options.InverseAdaptationMatrix); + return new CieXyz(vector); + } + + /// + public static void ToProfileConnectionSpace(ColorConversionOptions options, ReadOnlySpan source, Span destination) + { + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + + for (int i = 0; i < source.Length; i++) + { + Lms lms = source[i]; + destination[i] = lms.ToProfileConnectingSpace(options); + } + } + + /// + public static ChromaticAdaptionWhitePointSource GetChromaticAdaptionWhitePointSource() => ChromaticAdaptionWhitePointSource.WhitePoint; + /// public override int GetHashCode() => HashCode.Combine(this.L, this.M, this.S); @@ -95,9 +140,9 @@ public readonly struct Lms : IEquatable public override bool Equals(object? obj) => obj is Lms other && this.Equals(other); /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool Equals(Lms other) - => this.L.Equals(other.L) - && this.M.Equals(other.M) - && this.S.Equals(other.S); + => 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 new file mode 100644 index 0000000000..6698e12cb8 --- /dev/null +++ b/src/ImageSharp/ColorProfiles/Rgb.cs @@ -0,0 +1,269 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using System.Numerics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using SixLabors.ImageSharp.ColorProfiles.WorkingSpaces; + +namespace SixLabors.ImageSharp.ColorProfiles; + +/// +/// Represents an RGB (red, green, blue) color profile. +/// +[StructLayout(LayoutKind.Sequential)] +public readonly struct Rgb : IProfileConnectingSpace +{ + /// + /// Initializes a new instance of the struct. + /// + /// The red component usually ranging between 0 and 1. + /// The green component usually ranging between 0 and 1. + /// The blue component usually ranging between 0 and 1. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Rgb(float r, float g, float b) + { + // Not clamping as this space can exceed "usual" ranges + this.R = r; + this.G = g; + this.B = b; + } + + /// + /// Initializes a new instance of the struct. + /// + /// The vector representing the r, g, b components. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Rgb(Vector3 source) + { + this.R = source.X; + this.G = source.Y; + this.B = source.Z; + } + + /// + /// Gets the red component. + /// A value usually ranging between 0 and 1. + /// + public float R { get; } + + /// + /// Gets the green component. + /// A value usually ranging between 0 and 1. + /// + public float G { get; } + + /// + /// Gets the blue component. + /// A value usually ranging between 0 and 1. + /// + public float B { get; } + + /// + /// Compares two objects for equality. + /// + /// 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 ==(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. + /// + /// True if the current left is unequal to the parameter; otherwise, false. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool operator !=(Rgb left, Rgb right) => !left.Equals(right); + + /// + public static Rgb FromProfileConnectingSpace(ColorConversionOptions options, in CieXyz source) + { + // Convert to linear rgb then compress. + Rgb linear = new(Vector3.Transform(source.ToVector3(), GetCieXyzToRgbMatrix(options.TargetRgbWorkingSpace))); + return FromScaledVector4(options.TargetRgbWorkingSpace.Compress(linear.ToScaledVector4())); + } + + /// + public static void FromProfileConnectionSpace(ColorConversionOptions options, ReadOnlySpan source, Span destination) + { + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + + Matrix4x4 matrix = GetCieXyzToRgbMatrix(options.TargetRgbWorkingSpace); + for (int i = 0; i < source.Length; i++) + { + // Convert to linear rgb then compress. + Rgb linear = new(Vector3.Transform(source[i].ToVector3(), matrix)); + Vector4 nonlinear = options.TargetRgbWorkingSpace.Compress(linear.ToScaledVector4()); + destination[i] = FromScaledVector4(nonlinear); + } + } + + /// + public CieXyz ToProfileConnectingSpace(ColorConversionOptions options) + { + // First expand to linear rgb + Rgb linear = FromScaledVector4(options.RgbWorkingSpace.Expand(this.ToScaledVector4())); + + // Then convert to xyz + return new CieXyz(Vector3.Transform(linear.ToScaledVector3(), GetRgbToCieXyzMatrix(options.RgbWorkingSpace))); + } + + /// + public static void ToProfileConnectionSpace(ColorConversionOptions options, ReadOnlySpan source, Span destination) + { + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + + Matrix4x4 matrix = GetRgbToCieXyzMatrix(options.RgbWorkingSpace); + for (int i = 0; i < source.Length; i++) + { + Rgb rgb = source[i]; + + // First expand to linear rgb + Rgb linear = FromScaledVector4(options.RgbWorkingSpace.Expand(rgb.ToScaledVector4())); + + // Then convert to xyz + destination[i] = new CieXyz(Vector3.Transform(linear.ToScaledVector3(), matrix)); + } + } + + /// + public static ChromaticAdaptionWhitePointSource GetChromaticAdaptionWhitePointSource() => ChromaticAdaptionWhitePointSource.RgbWorkingSpace; + + /// + /// Initializes the color instance from a generic scaled . + /// + /// The vector to load the color from. + /// The . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgb FromScaledVector3(Vector3 source) => new(Vector3.Clamp(source, Vector3.Zero, Vector3.One)); + + /// + /// Initializes the color instance from a generic scaled . + /// + /// The vector to load the color from. + /// The . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgb FromScaledVector4(Vector4 source) + { + source = Vector4.Clamp(source, Vector4.Zero, Vector4.One); + return new(source.X, source.Y, source.Z); + } + + /// + /// Initializes the color instance for a source clamped between 0 and 1 + /// + /// The source to load the color from. + /// The . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgb Clamp(Rgb source) => new(Vector3.Clamp(new(source.R, source.G, source.B), Vector3.Zero, Vector3.One)); + + /// + /// Expands the color into a generic ("scaled") representation + /// with values scaled and usually clamped between 0 and 1. + /// The vector components are typically expanded in least to greatest significance order. + /// + /// The . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Vector3 ToScaledVector3() => Clamp(this).ToVector3(); + + /// + /// Expands the color into a generic representation. + /// The vector components are typically expanded in least to greatest significance order. + /// + /// The . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Vector3 ToVector3() => new(this.R, this.G, this.B); + + /// + /// Expands the color into a generic ("scaled") representation + /// with values scaled and usually clamped between 0 and 1. + /// The vector components are typically expanded in least to greatest significance order. + /// + /// The . + [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); + Matrix4x4.Invert(matrix, out Matrix4x4 inverseMatrix); + return inverseMatrix; + } + + private static Matrix4x4 GetRgbToCieXyzMatrix(RgbWorkingSpace workingSpace) + { + DebugGuard.NotNull(workingSpace, nameof(workingSpace)); + RgbPrimariesChromaticityCoordinates chromaticity = workingSpace.ChromaticityCoordinates; + + float xr = chromaticity.R.X; + float xg = chromaticity.G.X; + float xb = chromaticity.B.X; + float yr = chromaticity.R.Y; + float yg = chromaticity.G.Y; + float yb = chromaticity.B.Y; + + float mXr = xr / yr; + float mZr = (1 - xr - yr) / yr; + + float mXg = xg / yg; + float mZg = (1 - xg - yg) / yg; + + float mXb = xb / yb; + float mZb = (1 - xb - yb) / yb; + + Matrix4x4 xyzMatrix = new() + { + M11 = mXr, + M21 = mXg, + M31 = mXb, + M12 = 1F, + M22 = 1F, + M32 = 1F, + M13 = mZr, + M23 = mZg, + M33 = mZb, + M44 = 1F + }; + + Matrix4x4.Invert(xyzMatrix, out Matrix4x4 inverseXyzMatrix); + + Vector3 vector = Vector3.Transform(workingSpace.WhitePoint.ToVector3(), inverseXyzMatrix); + + // Use transposed Rows/Columns + return new Matrix4x4 + { + M11 = vector.X * mXr, + M21 = vector.Y * mXg, + M31 = vector.Z * mXb, + M12 = vector.X, + M22 = vector.Y, + M32 = vector.Z, + M13 = vector.X * mZr, + M23 = vector.Y * mZg, + M33 = vector.Z * mZb, + M44 = 1F + }; + } +} diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/RGBPrimariesChromaticityCoordinates.cs b/src/ImageSharp/ColorProfiles/RgbPrimariesChromaticityCoordinates.cs similarity index 89% rename from src/ImageSharp/ColorSpaces/Conversion/Implementation/RGBPrimariesChromaticityCoordinates.cs rename to src/ImageSharp/ColorProfiles/RgbPrimariesChromaticityCoordinates.cs index 625e6c551a..1040f23acb 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/RGBPrimariesChromaticityCoordinates.cs +++ b/src/ImageSharp/ColorProfiles/RgbPrimariesChromaticityCoordinates.cs @@ -1,7 +1,9 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -namespace SixLabors.ImageSharp.ColorSpaces.Conversion; +using SixLabors.ImageSharp.ColorProfiles.WorkingSpaces; + +namespace SixLabors.ImageSharp.ColorProfiles; /// /// Represents the chromaticity coordinates of RGB primaries. @@ -50,9 +52,7 @@ public readonly struct RgbPrimariesChromaticityCoordinates : IEquatable parameter; otherwise, false. /// public static bool operator ==(RgbPrimariesChromaticityCoordinates left, RgbPrimariesChromaticityCoordinates right) - { - return left.Equals(right); - } + => left.Equals(right); /// /// Compares two objects for inequality @@ -67,21 +67,15 @@ public readonly struct RgbPrimariesChromaticityCoordinates : IEquatable parameter; otherwise, false. /// public static bool operator !=(RgbPrimariesChromaticityCoordinates left, RgbPrimariesChromaticityCoordinates right) - { - return !left.Equals(right); - } + => !left.Equals(right); /// public override bool Equals(object? obj) - { - return obj is RgbPrimariesChromaticityCoordinates other && this.Equals(other); - } + => obj is RgbPrimariesChromaticityCoordinates other && this.Equals(other); /// public bool Equals(RgbPrimariesChromaticityCoordinates other) - { - return this.R.Equals(other.R) && this.G.Equals(other.G) && this.B.Equals(other.B); - } + => this.R.Equals(other.R) && this.G.Equals(other.G) && this.B.Equals(other.B); /// public override int GetHashCode() => HashCode.Combine(this.R, this.G, this.B); diff --git a/src/ImageSharp/ColorProfiles/VonKriesChromaticAdaptation.cs b/src/ImageSharp/ColorProfiles/VonKriesChromaticAdaptation.cs new file mode 100644 index 0000000000..2f9a52912e --- /dev/null +++ b/src/ImageSharp/ColorProfiles/VonKriesChromaticAdaptation.cs @@ -0,0 +1,95 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using System.Numerics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace SixLabors.ImageSharp.ColorProfiles; + +/// +/// Implementation of the Von Kries chromatic adaptation model. +/// +/// +/// Transformation described here: +/// http://www.brucelindbloom.com/index.html?Eqn_ChromAdapt.html +/// +public static class VonKriesChromaticAdaptation +{ + /// + /// Performs a linear transformation of a source color in to the destination color. + /// + /// Doesn't crop the resulting color space coordinates (e.g. allows negative values for XYZ coordinates). + /// The source color. + /// The conversion white points. + /// The chromatic adaptation matrix. + /// The + public static CieXyz Transform(in CieXyz source, (CieXyz From, CieXyz To) whitePoints, Matrix4x4 matrix) + { + CieXyz from = whitePoints.From; + CieXyz to = whitePoints.To; + + if (from.Equals(to)) + { + return new(source.X, source.Y, source.Z); + } + + Vector3 sourceColorLms = Vector3.Transform(source.ToVector3(), matrix); + Vector3 sourceWhitePointLms = Vector3.Transform(from.ToVector3(), matrix); + Vector3 targetWhitePointLms = Vector3.Transform(to.ToVector3(), matrix); + + Vector3 vector = targetWhitePointLms / sourceWhitePointLms; + Vector3 targetColorLms = Vector3.Multiply(vector, sourceColorLms); + + Matrix4x4.Invert(matrix, out Matrix4x4 inverseMatrix); + return new CieXyz(Vector3.Transform(targetColorLms, inverseMatrix)); + } + + /// + /// Performs a bulk linear transformation of a source color in to the destination color. + /// + /// Doesn't crop the resulting color space coordinates (e. g. allows negative values for XYZ coordinates). + /// The span to the source colors. + /// The span to the destination colors. + /// The conversion white points. + /// The chromatic adaptation matrix. + public static void Transform( + ReadOnlySpan source, + Span destination, + (CieXyz From, CieXyz To) whitePoints, + Matrix4x4 matrix) + { + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; + + CieXyz from = whitePoints.From; + CieXyz to = whitePoints.To; + + if (from.Equals(to)) + { + source.CopyTo(destination[..count]); + return; + } + + Matrix4x4.Invert(matrix, out Matrix4x4 inverseMatrix); + + ref CieXyz sourceBase = ref MemoryMarshal.GetReference(source); + ref CieXyz destinationBase = ref MemoryMarshal.GetReference(destination); + + Vector3 sourceWhitePointLms = Vector3.Transform(from.ToVector3(), matrix); + Vector3 targetWhitePointLms = Vector3.Transform(to.ToVector3(), matrix); + + Vector3 vector = targetWhitePointLms / sourceWhitePointLms; + + for (nuint i = 0; i < (uint)count; i++) + { + ref CieXyz sp = ref Unsafe.Add(ref sourceBase, i); + ref CieXyz dp = ref Unsafe.Add(ref destinationBase, i); + + Vector3 sourceColorLms = Vector3.Transform(sp.ToVector3(), matrix); + + Vector3 targetColorLms = Vector3.Multiply(vector, sourceColorLms); + dp = new CieXyz(Vector3.Transform(targetColorLms, inverseMatrix)); + } + } +} diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/GammaWorkingSpace.cs b/src/ImageSharp/ColorProfiles/WorkingSpaces/GammaWorkingSpace.cs similarity index 72% rename from src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/GammaWorkingSpace.cs rename to src/ImageSharp/ColorProfiles/WorkingSpaces/GammaWorkingSpace.cs index e95f1f2b47..91fa426241 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/GammaWorkingSpace.cs +++ b/src/ImageSharp/ColorProfiles/WorkingSpaces/GammaWorkingSpace.cs @@ -1,10 +1,10 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -using System.Runtime.CompilerServices; -using SixLabors.ImageSharp.ColorSpaces.Companding; +using System.Numerics; +using SixLabors.ImageSharp.ColorProfiles.Companding; -namespace SixLabors.ImageSharp.ColorSpaces.Conversion; +namespace SixLabors.ImageSharp.ColorProfiles.WorkingSpaces; /// /// The gamma working space. @@ -26,12 +26,16 @@ public sealed class GammaWorkingSpace : RgbWorkingSpace public float Gamma { get; } /// - [MethodImpl(InliningOptions.ShortMethod)] - public override float Compress(float channel) => GammaCompanding.Compress(channel, this.Gamma); + public override void Compress(Span vectors) => GammaCompanding.Compress(vectors, this.Gamma); /// - [MethodImpl(InliningOptions.ShortMethod)] - public override float Expand(float channel) => GammaCompanding.Expand(channel, this.Gamma); + public override void Expand(Span vectors) => GammaCompanding.Expand(vectors, this.Gamma); + + /// + public override Vector4 Compress(Vector4 vector) => GammaCompanding.Compress(vector, this.Gamma); + + /// + public override Vector4 Expand(Vector4 vector) => GammaCompanding.Expand(vector, this.Gamma); /// public override bool Equals(object? obj) diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/LWorkingSpace.cs b/src/ImageSharp/ColorProfiles/WorkingSpaces/LWorkingSpace.cs similarity index 56% rename from src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/LWorkingSpace.cs rename to src/ImageSharp/ColorProfiles/WorkingSpaces/LWorkingSpace.cs index 199f6c8d85..77dc2c06d9 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/LWorkingSpace.cs +++ b/src/ImageSharp/ColorProfiles/WorkingSpaces/LWorkingSpace.cs @@ -1,10 +1,10 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -using System.Runtime.CompilerServices; -using SixLabors.ImageSharp.ColorSpaces.Companding; +using System.Numerics; +using SixLabors.ImageSharp.ColorProfiles.Companding; -namespace SixLabors.ImageSharp.ColorSpaces.Conversion; +namespace SixLabors.ImageSharp.ColorProfiles.WorkingSpaces; /// /// L* working space. @@ -22,10 +22,14 @@ public sealed class LWorkingSpace : RgbWorkingSpace } /// - [MethodImpl(InliningOptions.ShortMethod)] - public override float Compress(float channel) => LCompanding.Compress(channel); + public override void Compress(Span vectors) => LCompanding.Compress(vectors); /// - [MethodImpl(InliningOptions.ShortMethod)] - public override float Expand(float channel) => LCompanding.Expand(channel); + public override void Expand(Span vectors) => LCompanding.Expand(vectors); + + /// + public override Vector4 Compress(Vector4 vector) => LCompanding.Compress(vector); + + /// + public override Vector4 Expand(Vector4 vector) => LCompanding.Expand(vector); } diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/Rec2020WorkingSpace.cs b/src/ImageSharp/ColorProfiles/WorkingSpaces/Rec2020WorkingSpace.cs similarity index 57% rename from src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/Rec2020WorkingSpace.cs rename to src/ImageSharp/ColorProfiles/WorkingSpaces/Rec2020WorkingSpace.cs index 52cc0f95af..970d103029 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/Rec2020WorkingSpace.cs +++ b/src/ImageSharp/ColorProfiles/WorkingSpaces/Rec2020WorkingSpace.cs @@ -1,10 +1,10 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -using System.Runtime.CompilerServices; -using SixLabors.ImageSharp.ColorSpaces.Companding; +using System.Numerics; +using SixLabors.ImageSharp.ColorProfiles.Companding; -namespace SixLabors.ImageSharp.ColorSpaces.Conversion; +namespace SixLabors.ImageSharp.ColorProfiles.WorkingSpaces; /// /// Rec. 2020 (ITU-R Recommendation BT.2020F) working space. @@ -22,10 +22,14 @@ public sealed class Rec2020WorkingSpace : RgbWorkingSpace } /// - [MethodImpl(InliningOptions.ShortMethod)] - public override float Compress(float channel) => Rec2020Companding.Compress(channel); + public override void Compress(Span vectors) => Rec2020Companding.Compress(vectors); /// - [MethodImpl(InliningOptions.ShortMethod)] - public override float Expand(float channel) => Rec2020Companding.Expand(channel); + public override void Expand(Span vectors) => Rec2020Companding.Expand(vectors); + + /// + public override Vector4 Compress(Vector4 vector) => Rec2020Companding.Compress(vector); + + /// + public override Vector4 Expand(Vector4 vector) => Rec2020Companding.Expand(vector); } diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/Rec709WorkingSpace.cs b/src/ImageSharp/ColorProfiles/WorkingSpaces/Rec709WorkingSpace.cs similarity index 57% rename from src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/Rec709WorkingSpace.cs rename to src/ImageSharp/ColorProfiles/WorkingSpaces/Rec709WorkingSpace.cs index c030e91025..011da58077 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/Rec709WorkingSpace.cs +++ b/src/ImageSharp/ColorProfiles/WorkingSpaces/Rec709WorkingSpace.cs @@ -1,10 +1,10 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -using System.Runtime.CompilerServices; -using SixLabors.ImageSharp.ColorSpaces.Companding; +using System.Numerics; +using SixLabors.ImageSharp.ColorProfiles.Companding; -namespace SixLabors.ImageSharp.ColorSpaces.Conversion; +namespace SixLabors.ImageSharp.ColorProfiles.WorkingSpaces; /// /// Rec. 709 (ITU-R Recommendation BT.709) working space. @@ -22,10 +22,14 @@ public sealed class Rec709WorkingSpace : RgbWorkingSpace } /// - [MethodImpl(InliningOptions.ShortMethod)] - public override float Compress(float channel) => Rec709Companding.Compress(channel); + public override void Compress(Span vectors) => Rec709Companding.Compress(vectors); /// - [MethodImpl(InliningOptions.ShortMethod)] - public override float Expand(float channel) => Rec709Companding.Expand(channel); + public override void Expand(Span vectors) => Rec709Companding.Expand(vectors); + + /// + public override Vector4 Compress(Vector4 vector) => Rec709Companding.Compress(vector); + + /// + public override Vector4 Expand(Vector4 vector) => Rec709Companding.Expand(vector); } diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/RgbWorkingSpace.cs b/src/ImageSharp/ColorProfiles/WorkingSpaces/RgbWorkingSpace.cs similarity index 61% rename from src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/RgbWorkingSpace.cs rename to src/ImageSharp/ColorProfiles/WorkingSpaces/RgbWorkingSpace.cs index dd1dc62a86..97069b856b 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/RgbWorkingSpace.cs +++ b/src/ImageSharp/ColorProfiles/WorkingSpaces/RgbWorkingSpace.cs @@ -1,7 +1,9 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -namespace SixLabors.ImageSharp.ColorSpaces.Conversion; +using System.Numerics; + +namespace SixLabors.ImageSharp.ColorProfiles.WorkingSpaces; /// /// Base class for all implementations of . @@ -30,26 +32,30 @@ public abstract class RgbWorkingSpace public RgbPrimariesChromaticityCoordinates ChromaticityCoordinates { get; } /// - /// Expands a companded channel to its linear equivalent with respect to the energy. + /// Compresses the linear vectors to their nonlinear equivalents with respect to the energy. + /// + /// The span of vectors. + public abstract void Compress(Span vectors); + + /// + /// Expands the nonlinear vectors to their linear equivalents with respect to the energy. + /// + /// The span of vectors. + public abstract void Expand(Span vectors); + + /// + /// Compresses the linear vector to its nonlinear equivalent with respect to the energy. /// - /// - /// For more info see: - /// - /// - /// The channel value. - /// The representing the linear channel value. - public abstract float Expand(float channel); + /// The vector. + /// The . + public abstract Vector4 Compress(Vector4 vector); /// - /// Compresses an uncompanded channel (linear) to its nonlinear equivalent (depends on the RGB color system). + /// Compresses the linear vector to its nonlinear equivalent with respect to the energy. /// - /// - /// For more info see: - /// - /// - /// The channel value. - /// The representing the nonlinear channel value. - public abstract float Compress(float channel); + /// The vector. + /// The . + public abstract Vector4 Expand(Vector4 vector); /// public override bool Equals(object? obj) diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/SRgbWorkingSpace.cs b/src/ImageSharp/ColorProfiles/WorkingSpaces/SRgbWorkingSpace.cs similarity index 56% rename from src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/SRgbWorkingSpace.cs rename to src/ImageSharp/ColorProfiles/WorkingSpaces/SRgbWorkingSpace.cs index 767157f4cb..b88e6c8983 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/SRgbWorkingSpace.cs +++ b/src/ImageSharp/ColorProfiles/WorkingSpaces/SRgbWorkingSpace.cs @@ -1,10 +1,10 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -using System.Runtime.CompilerServices; -using SixLabors.ImageSharp.ColorSpaces.Companding; +using System.Numerics; +using SixLabors.ImageSharp.ColorProfiles.Companding; -namespace SixLabors.ImageSharp.ColorSpaces.Conversion; +namespace SixLabors.ImageSharp.ColorProfiles.WorkingSpaces; /// /// The sRgb working space. @@ -22,10 +22,14 @@ public sealed class SRgbWorkingSpace : RgbWorkingSpace } /// - [MethodImpl(InliningOptions.ShortMethod)] - public override float Compress(float channel) => SRgbCompanding.Compress(channel); + public override void Compress(Span vectors) => SRgbCompanding.Compress(vectors); /// - [MethodImpl(InliningOptions.ShortMethod)] - public override float Expand(float channel) => SRgbCompanding.Expand(channel); + public override void Expand(Span vectors) => SRgbCompanding.Expand(vectors); + + /// + public override Vector4 Compress(Vector4 vector) => SRgbCompanding.Compress(vector); + + /// + public override Vector4 Expand(Vector4 vector) => SRgbCompanding.Expand(vector); } diff --git a/src/ImageSharp/ColorSpaces/YCbCr.cs b/src/ImageSharp/ColorProfiles/YCbCr.cs similarity index 52% rename from src/ImageSharp/ColorSpaces/YCbCr.cs rename to src/ImageSharp/ColorProfiles/YCbCr.cs index acb59388fb..03bd1d3120 100644 --- a/src/ImageSharp/ColorSpaces/YCbCr.cs +++ b/src/ImageSharp/ColorProfiles/YCbCr.cs @@ -3,15 +3,17 @@ using System.Numerics; using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; -namespace SixLabors.ImageSharp.ColorSpaces; +namespace SixLabors.ImageSharp.ColorProfiles; /// /// Represents an YCbCr (luminance, blue chroma, red chroma) color as defined in the ITU-T T.871 specification for the JFIF use with Jpeg. /// /// /// -public readonly struct YCbCr : IEquatable +[StructLayout(LayoutKind.Sequential)] +public readonly struct YCbCr : IColorProfile { private static readonly Vector3 Min = Vector3.Zero; private static readonly Vector3 Max = new(255); @@ -22,7 +24,7 @@ public readonly struct YCbCr : IEquatable /// The y luminance component. /// The cb chroma component. /// The cr chroma component. - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public YCbCr(float y, float cb, float cr) : this(new Vector3(y, cb, cr)) { @@ -32,7 +34,7 @@ public readonly struct YCbCr : IEquatable /// Initializes a new instance of the struct. /// /// The vector representing the y, cb, cr components. - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public YCbCr(Vector3 vector) { vector = Vector3.Clamp(vector, Min, Max); @@ -45,19 +47,19 @@ public readonly struct YCbCr : IEquatable /// Gets the Y luminance component. /// A value ranging between 0 and 255. /// - public readonly float Y { get; } + public float Y { get; } /// /// Gets the Cb chroma component. /// A value ranging between 0 and 255. /// - public readonly float Cb { get; } + public float Cb { get; } /// /// Gets the Cr chroma component. /// A value ranging between 0 and 255. /// - public readonly float Cr { get; } + public float Cr { get; } /// /// Compares two objects for equality. @@ -77,11 +79,70 @@ public readonly struct YCbCr : IEquatable /// /// True if the current left is unequal to the parameter; otherwise, false. /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(YCbCr left, YCbCr right) => !left.Equals(right); /// - [MethodImpl(InliningOptions.ShortMethod)] + public static YCbCr FromProfileConnectingSpace(ColorConversionOptions options, in Rgb source) + { + Vector3 rgb = source.ToScaledVector3() * Max; + float r = rgb.X; + float g = rgb.Y; + float b = rgb.Z; + + float y = (0.299F * r) + (0.587F * g) + (0.114F * b); + float cb = 128F + ((-0.168736F * r) - (0.331264F * g) + (0.5F * b)); + float cr = 128F + ((0.5F * r) - (0.418688F * g) - (0.081312F * b)); + + return new YCbCr(y, cb, cr); + } + + /// + public static void FromProfileConnectionSpace(ColorConversionOptions options, ReadOnlySpan source, Span destination) + { + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + + // TODO: We can optimize this by using SIMD + for (int i = 0; i < source.Length; i++) + { + Rgb rgb = source[i]; + destination[i] = FromProfileConnectingSpace(options, in rgb); + } + } + + /// + public Rgb ToProfileConnectingSpace(ColorConversionOptions options) + { + float y = this.Y; + float cb = this.Cb - 128F; + float cr = this.Cr - 128F; + + float r = MathF.Round(y + (1.402F * cr), MidpointRounding.AwayFromZero); + float g = MathF.Round(y - (0.344136F * cb) - (0.714136F * cr), MidpointRounding.AwayFromZero); + float b = MathF.Round(y + (1.772F * cb), MidpointRounding.AwayFromZero); + + return Rgb.FromScaledVector3(new Vector3(r, g, b) / Max); + } + + /// + public static void ToProfileConnectionSpace(ColorConversionOptions options, ReadOnlySpan source, Span destination) + { + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + + // TODO: We can optimize this by using SIMD + for (int i = 0; i < source.Length; i++) + { + YCbCr ycbcr = source[i]; + destination[i] = ycbcr.ToProfileConnectingSpace(options); + } + } + + /// + public static ChromaticAdaptionWhitePointSource GetChromaticAdaptionWhitePointSource() + => ChromaticAdaptionWhitePointSource.RgbWorkingSpace; + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] public override int GetHashCode() => HashCode.Combine(this.Y, this.Cb, this.Cr); /// @@ -91,9 +152,9 @@ public readonly struct YCbCr : IEquatable public override bool Equals(object? obj) => obj is YCbCr other && this.Equals(other); /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool Equals(YCbCr other) - => this.Y.Equals(other.Y) - && this.Cb.Equals(other.Cb) - && this.Cr.Equals(other.Cr); + => this.AsVector3Unsafe() == other.AsVector3Unsafe(); + + private Vector3 AsVector3Unsafe() => Unsafe.As(ref Unsafe.AsRef(in this)); } diff --git a/src/ImageSharp/ColorSpaces/CieLab.cs b/src/ImageSharp/ColorSpaces/CieLab.cs deleted file mode 100644 index 2346b395c0..0000000000 --- a/src/ImageSharp/ColorSpaces/CieLab.cs +++ /dev/null @@ -1,135 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using System.Numerics; -using System.Runtime.CompilerServices; - -namespace SixLabors.ImageSharp.ColorSpaces; - -/// -/// Represents a CIE L*a*b* 1976 color. -/// -/// -public readonly struct CieLab : IEquatable -{ - /// - /// D50 standard illuminant. - /// Used when reference white is not specified explicitly. - /// - public static readonly CieXyz DefaultWhitePoint = Illuminants.D50; - - /// - /// Initializes a new instance of the struct. - /// - /// The lightness dimension. - /// The a (green - magenta) component. - /// The b (blue - yellow) component. - /// Uses as white point. - [MethodImpl(InliningOptions.ShortMethod)] - public CieLab(float l, float a, float b) - : this(l, a, b, DefaultWhitePoint) - { - } - - /// - /// Initializes a new instance of the struct. - /// - /// The lightness dimension. - /// The a (green - magenta) component. - /// The b (blue - yellow) component. - /// The reference white point. - [MethodImpl(InliningOptions.ShortMethod)] - public CieLab(float l, float a, float b, CieXyz whitePoint) - : this(new Vector3(l, a, b), whitePoint) - { - } - - /// - /// Initializes a new instance of the struct. - /// - /// The vector representing the l, a, b components. - /// Uses as white point. - [MethodImpl(InliningOptions.ShortMethod)] - public CieLab(Vector3 vector) - : this(vector, DefaultWhitePoint) - { - } - - /// - /// Initializes a new instance of the struct. - /// - /// The vector representing the l, a, b components. - /// The reference white point. - [MethodImpl(InliningOptions.ShortMethod)] - public CieLab(Vector3 vector, CieXyz whitePoint) - : this() - { - // Not clamping as documentation about this space only indicates "usual" ranges - this.L = vector.X; - this.A = vector.Y; - this.B = vector.Z; - this.WhitePoint = whitePoint; - } - - /// - /// Gets the lightness dimension. - /// A value usually ranging between 0 (black), 100 (diffuse white) or higher (specular white). - /// - public readonly float L { get; } - - /// - /// Gets the a color component. - /// A value usually ranging from -100 to 100. Negative is green, positive magenta. - /// - public readonly float A { get; } - - /// - /// Gets the b color component. - /// A value usually ranging from -100 to 100. Negative is blue, positive is yellow - /// - public readonly float B { get; } - - /// - /// Gets the reference white point of this color - /// - public readonly CieXyz WhitePoint { get; } - - /// - /// Compares two objects for equality. - /// - /// 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(InliningOptions.ShortMethod)] - 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. - /// - /// True if the current left is unequal to the parameter; otherwise, false. - /// - [MethodImpl(InliningOptions.ShortMethod)] - public static bool operator !=(CieLab left, CieLab right) => !left.Equals(right); - - /// - public override int GetHashCode() => HashCode.Combine(this.L, this.A, this.B, this.WhitePoint); - - /// - 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(InliningOptions.ShortMethod)] - public bool Equals(CieLab other) => - this.L.Equals(other.L) - && this.A.Equals(other.A) - && this.B.Equals(other.B) - && this.WhitePoint.Equals(other.WhitePoint); -} diff --git a/src/ImageSharp/ColorSpaces/CieLchuv.cs b/src/ImageSharp/ColorSpaces/CieLchuv.cs deleted file mode 100644 index 4d47be5aa3..0000000000 --- a/src/ImageSharp/ColorSpaces/CieLchuv.cs +++ /dev/null @@ -1,156 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using System.Numerics; -using System.Runtime.CompilerServices; - -namespace SixLabors.ImageSharp.ColorSpaces; - -/// -/// Represents the CIE L*C*h°, cylindrical form of the CIE L*u*v* 1976 color. -/// -/// -public readonly struct CieLchuv : IEquatable -{ - private static readonly Vector3 Min = new(0, -200, 0); - private static readonly Vector3 Max = new(100, 200, 360); - - /// - /// D50 standard illuminant. - /// Used when reference white is not specified explicitly. - /// - public static readonly CieXyz DefaultWhitePoint = Illuminants.D65; - - /// - /// Initializes a new instance of the struct. - /// - /// The lightness dimension. - /// The chroma, relative saturation. - /// The hue in degrees. - /// Uses as white point. - [MethodImpl(InliningOptions.ShortMethod)] - public CieLchuv(float l, float c, float h) - : this(l, c, h, DefaultWhitePoint) - { - } - - /// - /// Initializes a new instance of the struct. - /// - /// The lightness dimension. - /// The chroma, relative saturation. - /// The hue in degrees. - /// The reference white point. - [MethodImpl(InliningOptions.ShortMethod)] - public CieLchuv(float l, float c, float h, CieXyz whitePoint) - : this(new Vector3(l, c, h), whitePoint) - { - } - - /// - /// Initializes a new instance of the struct. - /// - /// The vector representing the l, c, h components. - /// Uses as white point. - [MethodImpl(InliningOptions.ShortMethod)] - public CieLchuv(Vector3 vector) - : this(vector, DefaultWhitePoint) - { - } - - /// - /// Initializes a new instance of the struct. - /// - /// The vector representing the l, c, h components. - /// The reference white point. - [MethodImpl(InliningOptions.ShortMethod)] - public CieLchuv(Vector3 vector, CieXyz whitePoint) - : this() - { - vector = Vector3.Clamp(vector, Min, Max); - this.L = vector.X; - this.C = vector.Y; - this.H = vector.Z; - this.WhitePoint = whitePoint; - } - - /// - /// Gets the lightness dimension. - /// A value ranging between 0 (black), 100 (diffuse white) or higher (specular white). - /// - public readonly float L { get; } - - /// - /// Gets the a chroma component. - /// A value ranging from 0 to 200. - /// - public readonly float C { get; } - - /// - /// Gets the h° hue component in degrees. - /// A value ranging from 0 to 360. - /// - public readonly float H { get; } - - /// - /// Gets the reference white point of this color - /// - public readonly CieXyz WhitePoint { get; } - - /// - /// Compares two objects for equality. - /// - /// 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) => left.Equals(right); - - /// - /// Compares two objects for inequality - /// - /// 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) => !left.Equals(right); - - /// - public override int GetHashCode() => HashCode.Combine(this.L, this.C, this.H, this.WhitePoint); - - /// - public override string ToString() => FormattableString.Invariant($"CieLchuv({this.L:#0.##}, {this.C:#0.##}, {this.H:#0.##})"); - - /// - public override bool Equals(object? obj) => obj is CieLchuv other && this.Equals(other); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public bool Equals(CieLchuv other) - => this.L.Equals(other.L) - && this.C.Equals(other.C) - && this.H.Equals(other.H) - && this.WhitePoint.Equals(other.WhitePoint); - - /// - /// Computes the saturation of the color (chroma normalized by lightness) - /// - /// - /// A value ranging from 0 to 100. - /// - /// The - [MethodImpl(InliningOptions.ShortMethod)] - public float Saturation() - { - float result = 100 * (this.C / this.L); - - if (float.IsNaN(result)) - { - return 0; - } - - return result; - } -} diff --git a/src/ImageSharp/ColorSpaces/CieLuv.cs b/src/ImageSharp/ColorSpaces/CieLuv.cs deleted file mode 100644 index 04bc96cfa2..0000000000 --- a/src/ImageSharp/ColorSpaces/CieLuv.cs +++ /dev/null @@ -1,136 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using System.Numerics; -using System.Runtime.CompilerServices; - -namespace SixLabors.ImageSharp.ColorSpaces; - -/// -/// The CIE 1976 (L*, u*, v*) color space, commonly known by its abbreviation CIELUV, is a color space adopted by the International -/// Commission on Illumination (CIE) in 1976, as a simple-to-compute transformation of the 1931 CIE XYZ color space, but which -/// attempted perceptual uniformity -/// -/// -public readonly struct CieLuv : IEquatable -{ - /// - /// D65 standard illuminant. - /// Used when reference white is not specified explicitly. - /// - public static readonly CieXyz DefaultWhitePoint = Illuminants.D65; - - /// - /// Initializes a new instance of the struct. - /// - /// The lightness dimension. - /// The blue-yellow chromaticity coordinate of the given whitepoint. - /// The red-green chromaticity coordinate of the given whitepoint. - /// Uses as white point. - [MethodImpl(InliningOptions.ShortMethod)] - public CieLuv(float l, float u, float v) - : this(l, u, v, DefaultWhitePoint) - { - } - - /// - /// Initializes a new instance of the struct. - /// - /// The lightness dimension. - /// The blue-yellow chromaticity coordinate of the given whitepoint. - /// The red-green chromaticity coordinate of the given whitepoint. - /// The reference white point. - [MethodImpl(InliningOptions.ShortMethod)] - public CieLuv(float l, float u, float v, CieXyz whitePoint) - : this(new Vector3(l, u, v), whitePoint) - { - } - - /// - /// Initializes a new instance of the struct. - /// - /// The vector representing the l, u, v components. - /// Uses as white point. - [MethodImpl(InliningOptions.ShortMethod)] - public CieLuv(Vector3 vector) - : this(vector, DefaultWhitePoint) - { - } - - /// - /// Initializes a new instance of the struct. - /// - /// The vector representing the l, u, v components. - /// The reference white point. - [MethodImpl(InliningOptions.ShortMethod)] - public CieLuv(Vector3 vector, CieXyz whitePoint) - { - // Not clamping as documentation about this space only indicates "usual" ranges - this.L = vector.X; - this.U = vector.Y; - this.V = vector.Z; - this.WhitePoint = whitePoint; - } - - /// - /// Gets the lightness dimension - /// A value usually ranging between 0 and 100. - /// - public readonly float L { get; } - - /// - /// Gets the blue-yellow chromaticity coordinate of the given whitepoint. - /// A value usually ranging between -100 and 100. - /// - public readonly float U { get; } - - /// - /// Gets the red-green chromaticity coordinate of the given whitepoint. - /// A value usually ranging between -100 and 100. - /// - public readonly float V { get; } - - /// - /// Gets the reference white point of this color - /// - public readonly CieXyz WhitePoint { get; } - - /// - /// Compares two objects for equality. - /// - /// 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(InliningOptions.ShortMethod)] - 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. - /// - /// True if the current left is unequal to the parameter; otherwise, false. - /// - [MethodImpl(InliningOptions.ShortMethod)] - public static bool operator !=(CieLuv left, CieLuv right) => !left.Equals(right); - - /// - public override int GetHashCode() => HashCode.Combine(this.L, this.U, this.V, this.WhitePoint); - - /// - public override string ToString() => FormattableString.Invariant($"CieLuv({this.L:#0.##}, {this.U:#0.##}, {this.V:#0.##})"); - - /// - public override bool Equals(object? obj) => obj is CieLuv other && this.Equals(other); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public bool Equals(CieLuv other) - => this.L.Equals(other.L) - && this.U.Equals(other.U) - && this.V.Equals(other.V) - && this.WhitePoint.Equals(other.WhitePoint); -} diff --git a/src/ImageSharp/ColorSpaces/Cmyk.cs b/src/ImageSharp/ColorSpaces/Cmyk.cs deleted file mode 100644 index a5aacf38ad..0000000000 --- a/src/ImageSharp/ColorSpaces/Cmyk.cs +++ /dev/null @@ -1,107 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using System.Numerics; -using System.Runtime.CompilerServices; - -namespace SixLabors.ImageSharp.ColorSpaces; - -/// -/// Represents an CMYK (cyan, magenta, yellow, keyline) color. -/// -public readonly struct Cmyk : IEquatable -{ - private static readonly Vector4 Min = Vector4.Zero; - private static readonly Vector4 Max = Vector4.One; - - /// - /// Initializes a new instance of the struct. - /// - /// The cyan component. - /// The magenta component. - /// The yellow component. - /// The keyline black component. - [MethodImpl(InliningOptions.ShortMethod)] - public Cmyk(float c, float m, float y, float k) - : this(new Vector4(c, m, y, k)) - { - } - - /// - /// Initializes a new instance of the struct. - /// - /// The vector representing the c, m, y, k components. - [MethodImpl(InliningOptions.ShortMethod)] - public Cmyk(Vector4 vector) - { - vector = Numerics.Clamp(vector, Min, Max); - this.C = vector.X; - this.M = vector.Y; - this.Y = vector.Z; - this.K = vector.W; - } - - /// - /// Gets the cyan color component. - /// A value ranging between 0 and 1. - /// - public readonly float C { get; } - - /// - /// Gets the magenta color component. - /// A value ranging between 0 and 1. - /// - public readonly float M { get; } - - /// - /// Gets the yellow color component. - /// A value ranging between 0 and 1. - /// - public readonly float Y { get; } - - /// - /// Gets the keyline black color component. - /// A value ranging between 0 and 1. - /// - public readonly float K { get; } - - /// - /// Compares two objects for equality. - /// - /// 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(InliningOptions.ShortMethod)] - 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. - /// - /// True if the current left is unequal to the parameter; otherwise, false. - /// - [MethodImpl(InliningOptions.ShortMethod)] - public static bool operator !=(Cmyk left, Cmyk right) => !left.Equals(right); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public override int GetHashCode() => HashCode.Combine(this.C, this.M, this.Y, this.K); - - /// - public override string ToString() => FormattableString.Invariant($"Cmyk({this.C:#0.##}, {this.M:#0.##}, {this.Y:#0.##}, {this.K:#0.##})"); - - /// - public override bool Equals(object? obj) => obj is Cmyk other && this.Equals(other); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public bool Equals(Cmyk other) - => this.C.Equals(other.C) - && this.M.Equals(other.M) - && this.Y.Equals(other.Y) - && this.K.Equals(other.K); -} diff --git a/src/ImageSharp/ColorSpaces/Companding/GammaCompanding.cs b/src/ImageSharp/ColorSpaces/Companding/GammaCompanding.cs deleted file mode 100644 index e5d98430fd..0000000000 --- a/src/ImageSharp/ColorSpaces/Companding/GammaCompanding.cs +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using System.Runtime.CompilerServices; - -namespace SixLabors.ImageSharp.ColorSpaces.Companding; - -/// -/// Implements gamma companding. -/// -/// -/// -/// -/// -public static class GammaCompanding -{ - /// - /// Expands a companded channel to its linear equivalent with respect to the energy. - /// - /// The channel value. - /// The gamma value. - /// The representing the linear channel value. - [MethodImpl(InliningOptions.ShortMethod)] - public static float Expand(float channel, float gamma) => MathF.Pow(channel, gamma); - - /// - /// Compresses an uncompanded channel (linear) to its nonlinear equivalent. - /// - /// The channel value. - /// The gamma value. - /// The representing the nonlinear channel value. - [MethodImpl(InliningOptions.ShortMethod)] - public static float Compress(float channel, float gamma) => MathF.Pow(channel, 1 / gamma); -} diff --git a/src/ImageSharp/ColorSpaces/Companding/LCompanding.cs b/src/ImageSharp/ColorSpaces/Companding/LCompanding.cs deleted file mode 100644 index db44fd069f..0000000000 --- a/src/ImageSharp/ColorSpaces/Companding/LCompanding.cs +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using System.Runtime.CompilerServices; -using SixLabors.ImageSharp.ColorSpaces.Conversion; - -namespace SixLabors.ImageSharp.ColorSpaces.Companding; - -/// -/// Implements L* companding. -/// -/// -/// For more info see: -/// -/// -/// -public static class LCompanding -{ - /// - /// Expands a companded channel to its linear equivalent with respect to the energy. - /// - /// The channel value. - /// The representing the linear channel value. - [MethodImpl(InliningOptions.ShortMethod)] - public static float Expand(float channel) - => channel <= 0.08F ? (100F * channel) / CieConstants.Kappa : Numerics.Pow3((channel + 0.16F) / 1.16F); - - /// - /// Compresses an uncompanded channel (linear) to its nonlinear equivalent. - /// - /// The channel value - /// The representing the nonlinear channel value. - [MethodImpl(InliningOptions.ShortMethod)] - public static float Compress(float channel) - => channel <= CieConstants.Epsilon ? (channel * CieConstants.Kappa) / 100F : (1.16F * MathF.Pow(channel, 0.3333333F)) - 0.16F; -} diff --git a/src/ImageSharp/ColorSpaces/Companding/Rec2020Companding.cs b/src/ImageSharp/ColorSpaces/Companding/Rec2020Companding.cs deleted file mode 100644 index 4500976189..0000000000 --- a/src/ImageSharp/ColorSpaces/Companding/Rec2020Companding.cs +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using System.Runtime.CompilerServices; - -namespace SixLabors.ImageSharp.ColorSpaces.Companding; - -/// -/// Implements Rec. 2020 companding function. -/// -/// -/// -/// -public static class Rec2020Companding -{ - private const float Alpha = 1.09929682680944F; - private const float AlphaMinusOne = Alpha - 1F; - private const float Beta = 0.018053968510807F; - private const float InverseBeta = Beta * 4.5F; - private const float Epsilon = 1 / 0.45F; - - /// - /// Expands a companded channel to its linear equivalent with respect to the energy. - /// - /// The channel value. - /// The representing the linear channel value. - [MethodImpl(InliningOptions.ShortMethod)] - public static float Expand(float channel) - => channel < InverseBeta ? channel / 4.5F : MathF.Pow((channel + AlphaMinusOne) / Alpha, Epsilon); - - /// - /// Compresses an uncompanded channel (linear) to its nonlinear equivalent. - /// - /// The channel value. - /// The representing the nonlinear channel value. - [MethodImpl(InliningOptions.ShortMethod)] - public static float Compress(float channel) - => channel < Beta ? 4.5F * channel : (Alpha * MathF.Pow(channel, 0.45F)) - AlphaMinusOne; -} diff --git a/src/ImageSharp/ColorSpaces/Companding/Rec709Companding.cs b/src/ImageSharp/ColorSpaces/Companding/Rec709Companding.cs deleted file mode 100644 index 6e4767bcd9..0000000000 --- a/src/ImageSharp/ColorSpaces/Companding/Rec709Companding.cs +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using System.Runtime.CompilerServices; - -namespace SixLabors.ImageSharp.ColorSpaces.Companding; - -/// -/// Implements the Rec. 709 companding function. -/// -/// -/// http://en.wikipedia.org/wiki/Rec._709 -/// -public static class Rec709Companding -{ - private const float Epsilon = 1 / 0.45F; - - /// - /// Expands a companded channel to its linear equivalent with respect to the energy. - /// - /// The channel value. - /// The representing the linear channel value. - [MethodImpl(InliningOptions.ShortMethod)] - public static float Expand(float channel) - => channel < 0.081F ? channel / 4.5F : MathF.Pow((channel + 0.099F) / 1.099F, Epsilon); - - /// - /// Compresses an uncompanded channel (linear) to its nonlinear equivalent. - /// - /// The channel value. - /// The representing the nonlinear channel value. - [MethodImpl(InliningOptions.ShortMethod)] - public static float Compress(float channel) - => channel < 0.018F ? 4.5F * channel : (1.099F * MathF.Pow(channel, 0.45F)) - 0.099F; -} diff --git a/src/ImageSharp/ColorSpaces/Companding/SRgbCompanding.cs b/src/ImageSharp/ColorSpaces/Companding/SRgbCompanding.cs deleted file mode 100644 index 4c3923c888..0000000000 --- a/src/ImageSharp/ColorSpaces/Companding/SRgbCompanding.cs +++ /dev/null @@ -1,230 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using System.Numerics; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; -using System.Runtime.Intrinsics; -using System.Runtime.Intrinsics.X86; - -namespace SixLabors.ImageSharp.ColorSpaces.Companding; - -/// -/// Implements sRGB companding. -/// -/// -/// For more info see: -/// -/// -/// -public static class SRgbCompanding -{ - private const int Length = Scale + 2; // 256kb @ 16bit precision. - private const int Scale = (1 << 16) - 1; - - private static readonly Lazy LazyCompressTable = new( - () => - { - float[] result = new float[Length]; - - for (int i = 0; i < result.Length; i++) - { - double d = (double)i / Scale; - if (d <= (0.04045 / 12.92)) - { - d *= 12.92; - } - else - { - d = (1.055 * Math.Pow(d, 1.0 / 2.4)) - 0.055; - } - - result[i] = (float)d; - } - - return result; - }, - true); - - private static readonly Lazy LazyExpandTable = new( - () => - { - float[] result = new float[Length]; - - for (int i = 0; i < result.Length; i++) - { - double d = (double)i / Scale; - if (d <= 0.04045) - { - d /= 12.92; - } - else - { - d = Math.Pow((d + 0.055) / 1.055, 2.4); - } - - result[i] = (float)d; - } - - return result; - }, - true); - - private static float[] ExpandTable => LazyExpandTable.Value; - - private static float[] CompressTable => LazyCompressTable.Value; - - /// - /// Expands the companded vectors to their linear equivalents with respect to the energy. - /// - /// The span of vectors. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void Expand(Span vectors) - { - if (Avx2.IsSupported && vectors.Length >= 2) - { - CompandAvx2(vectors, ExpandTable); - - if (Numerics.Modulo2(vectors.Length) != 0) - { - // Vector4 fits neatly in pairs. Any overlap has to be equal to 1. - Expand(ref MemoryMarshal.GetReference(vectors[^1..])); - } - } - else - { - CompandScalar(vectors, ExpandTable); - } - } - - /// - /// Compresses the uncompanded vectors to their nonlinear equivalents with respect to the energy. - /// - /// The span of vectors. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static unsafe void Compress(Span vectors) - { - if (Avx2.IsSupported && vectors.Length >= 2) - { - CompandAvx2(vectors, CompressTable); - - if (Numerics.Modulo2(vectors.Length) != 0) - { - // Vector4 fits neatly in pairs. Any overlap has to be equal to 1. - Compress(ref MemoryMarshal.GetReference(vectors[^1..])); - } - } - else - { - CompandScalar(vectors, CompressTable); - } - } - - /// - /// Expands a companded vector to its linear equivalent with respect to the energy. - /// - /// The vector. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void Expand(ref Vector4 vector) - { - // Alpha is already a linear representation of opacity so we do not want to convert it. - vector.X = Expand(vector.X); - vector.Y = Expand(vector.Y); - vector.Z = Expand(vector.Z); - } - - /// - /// Compresses an uncompanded vector (linear) to its nonlinear equivalent. - /// - /// The vector. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void Compress(ref Vector4 vector) - { - // Alpha is already a linear representation of opacity so we do not want to convert it. - vector.X = Compress(vector.X); - vector.Y = Compress(vector.Y); - vector.Z = Compress(vector.Z); - } - - /// - /// Expands a companded channel to its linear equivalent with respect to the energy. - /// - /// The channel value. - /// The representing the linear channel value. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static float Expand(float channel) - => channel <= 0.04045F ? channel / 12.92F : MathF.Pow((channel + 0.055F) / 1.055F, 2.4F); - - /// - /// Compresses an uncompanded channel (linear) to its nonlinear equivalent. - /// - /// The channel value. - /// The representing the nonlinear channel value. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static float Compress(float channel) - => channel <= 0.0031308F ? 12.92F * channel : (1.055F * MathF.Pow(channel, 0.416666666666667F)) - 0.055F; - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static unsafe void CompandAvx2(Span vectors, float[] table) - { - fixed (float* tablePointer = &MemoryMarshal.GetArrayDataReference(table)) - { - var scale = Vector256.Create((float)Scale); - Vector256 zero = Vector256.Zero; - var offset = Vector256.Create(1); - - // Divide by 2 as 4 elements per Vector4 and 8 per Vector256 - ref Vector256 vectorsBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(vectors)); - ref Vector256 vectorsLast = ref Unsafe.Add(ref vectorsBase, (uint)vectors.Length / 2u); - - while (Unsafe.IsAddressLessThan(ref vectorsBase, ref vectorsLast)) - { - Vector256 multiplied = Avx.Multiply(scale, vectorsBase); - multiplied = Avx.Min(Avx.Max(zero, multiplied), scale); - - Vector256 truncated = Avx.ConvertToVector256Int32WithTruncation(multiplied); - Vector256 truncatedF = Avx.ConvertToVector256Single(truncated); - - Vector256 low = Avx2.GatherVector256(tablePointer, truncated, sizeof(float)); - Vector256 high = Avx2.GatherVector256(tablePointer, Avx2.Add(truncated, offset), sizeof(float)); - - // Alpha is already a linear representation of opacity so we do not want to convert it. - Vector256 companded = Numerics.Lerp(low, high, Avx.Subtract(multiplied, truncatedF)); - vectorsBase = Avx.Blend(companded, vectorsBase, Numerics.BlendAlphaControl); - vectorsBase = ref Unsafe.Add(ref vectorsBase, 1); - } - } - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static unsafe void CompandScalar(Span vectors, float[] table) - { - fixed (float* tablePointer = &MemoryMarshal.GetArrayDataReference(table)) - { - Vector4 zero = Vector4.Zero; - var scale = new Vector4(Scale); - ref Vector4 vectorsBase = ref MemoryMarshal.GetReference(vectors); - ref Vector4 vectorsLast = ref Unsafe.Add(ref vectorsBase, (uint)vectors.Length); - - while (Unsafe.IsAddressLessThan(ref vectorsBase, ref vectorsLast)) - { - Vector4 multiplied = Numerics.Clamp(vectorsBase * Scale, zero, scale); - - float f0 = multiplied.X; - float f1 = multiplied.Y; - float f2 = multiplied.Z; - - uint i0 = (uint)f0; - uint i1 = (uint)f1; - uint i2 = (uint)f2; - - // Alpha is already a linear representation of opacity so we do not want to convert it. - vectorsBase.X = Numerics.Lerp(tablePointer[i0], tablePointer[i0 + 1], f0 - (int)i0); - vectorsBase.Y = Numerics.Lerp(tablePointer[i1], tablePointer[i1 + 1], f1 - (int)i1); - vectorsBase.Z = Numerics.Lerp(tablePointer[i2], tablePointer[i2 + 1], f2 - (int)i2); - - vectorsBase = ref Unsafe.Add(ref vectorsBase, 1); - } - } - } -} diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Adapt.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Adapt.cs deleted file mode 100644 index b4934e44ac..0000000000 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Adapt.cs +++ /dev/null @@ -1,159 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -namespace SixLabors.ImageSharp.ColorSpaces.Conversion; - -/// -/// Performs chromatic adaptation on the various color spaces. -/// -public partial class ColorSpaceConverter -{ - /// - /// Performs chromatic adaptation of given color. - /// Target white point is . - /// - /// The color to adapt - /// The source white point. - /// The adapted color - public CieXyz Adapt(in CieXyz color, in CieXyz sourceWhitePoint) => this.Adapt(color, sourceWhitePoint, this.whitePoint); - - /// - /// Performs chromatic adaptation of given color. - /// Target white point is . - /// - /// The color to adapt - /// The source white point. - /// The target white point. - /// The adapted color - public CieXyz Adapt(in CieXyz color, in CieXyz sourceWhitePoint, in CieXyz targetWhitePoint) - { - if (!this.performChromaticAdaptation || sourceWhitePoint.Equals(targetWhitePoint)) - { - return color; - } - - // We know that chromaticAdaption is not null because performChromaticAdaption is checked - return this.chromaticAdaptation!.Transform(color, sourceWhitePoint, targetWhitePoint); - } - - /// - /// Adapts color from the source white point to white point set in . - /// - /// The color to adapt - /// The adapted color - public CieLab Adapt(in CieLab color) - { - if (!this.performChromaticAdaptation || color.WhitePoint.Equals(this.targetLabWhitePoint)) - { - return color; - } - - var xyzColor = this.ToCieXyz(color); - return this.ToCieLab(xyzColor); - } - - /// - /// Adapts color from the source white point to white point set in . - /// - /// The color to adapt - /// The adapted color - public CieLch Adapt(in CieLch color) - { - if (!this.performChromaticAdaptation || color.WhitePoint.Equals(this.targetLabWhitePoint)) - { - return color; - } - - var labColor = this.ToCieLab(color); - return this.ToCieLch(labColor); - } - - /// - /// Adapts color from the source white point to white point set in . - /// - /// The color to adapt - /// The adapted color - public CieLchuv Adapt(in CieLchuv color) - { - if (!this.performChromaticAdaptation || color.WhitePoint.Equals(this.targetLabWhitePoint)) - { - return color; - } - - var luvColor = this.ToCieLuv(color); - return this.ToCieLchuv(luvColor); - } - - /// - /// Adapts color from the source white point to white point set in . - /// - /// The color to adapt - /// The adapted color - public CieLuv Adapt(in CieLuv color) - { - if (!this.performChromaticAdaptation || color.WhitePoint.Equals(this.targetLuvWhitePoint)) - { - return color; - } - - var xyzColor = this.ToCieXyz(color); - return this.ToCieLuv(xyzColor); - } - - /// - /// Adapts color from the source white point to white point set in . - /// - /// The color to adapt - /// The adapted color - public HunterLab Adapt(in HunterLab color) - { - if (!this.performChromaticAdaptation || color.WhitePoint.Equals(this.targetHunterLabWhitePoint)) - { - return color; - } - - var xyzColor = this.ToCieXyz(color); - return this.ToHunterLab(xyzColor); - } - - /// - /// Adapts a color from the source working space to working space set in . - /// - /// The color to adapt - /// The adapted color - public LinearRgb Adapt(in LinearRgb color) - { - if (!this.performChromaticAdaptation || color.WorkingSpace.Equals(this.targetRgbWorkingSpace)) - { - return color; - } - - // Conversion to XYZ - LinearRgbToCieXyzConverter converterToXYZ = GetLinearRgbToCieXyzConverter(color.WorkingSpace); - CieXyz unadapted = converterToXYZ.Convert(color); - - // Adaptation - // We know that chromaticAdaption is not null because performChromaticAdaption is checked - CieXyz adapted = this.chromaticAdaptation!.Transform(unadapted, color.WorkingSpace.WhitePoint, this.targetRgbWorkingSpace.WhitePoint); - - // Conversion back to RGB - return this.cieXyzToLinearRgbConverter.Convert(adapted); - } - - /// - /// Adapts an color from the source working space to working space set in . - /// - /// The color to adapt - /// The adapted color - public Rgb Adapt(in Rgb color) - { - if (!this.performChromaticAdaptation) - { - return color; - } - - var linearInput = ToLinearRgb(color); - LinearRgb linearOutput = this.Adapt(linearInput); - return ToRgb(linearOutput); - } -} diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLab.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLab.cs deleted file mode 100644 index 54667ca2af..0000000000 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLab.cs +++ /dev/null @@ -1,441 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -namespace SixLabors.ImageSharp.ColorSpaces.Conversion; - -/// -/// Allows conversion to . -/// -public partial class ColorSpaceConverter -{ - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public CieLab ToCieLab(in CieLch color) - { - // Conversion (preserving white point) - CieLab unadapted = CieLchToCieLabConverter.Convert(color); - - return this.Adapt(unadapted); - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref CieLch sourceRef = ref MemoryMarshal.GetReference(source); - ref CieLab destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref CieLch sp = ref Unsafe.Add(ref sourceRef, i); - ref CieLab dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCieLab(sp); - } - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public CieLab ToCieLab(in CieLchuv color) - { - CieXyz xyzColor = this.ToCieXyz(color); - - return this.ToCieLab(xyzColor); - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref CieLchuv sourceRef = ref MemoryMarshal.GetReference(source); - ref CieLab destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref CieLchuv sp = ref Unsafe.Add(ref sourceRef, i); - ref CieLab dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCieLab(sp); - } - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public CieLab ToCieLab(in CieLuv color) - { - CieXyz xyzColor = this.ToCieXyz(color); - - return this.ToCieLab(xyzColor); - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref CieLuv sourceRef = ref MemoryMarshal.GetReference(source); - ref CieLab destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref CieLuv sp = ref Unsafe.Add(ref sourceRef, i); - ref CieLab dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCieLab(sp); - } - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public CieLab ToCieLab(in CieXyy color) - { - CieXyz xyzColor = ToCieXyz(color); - - return this.ToCieLab(xyzColor); - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref CieXyy sourceRef = ref MemoryMarshal.GetReference(source); - ref CieLab destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref CieXyy sp = ref Unsafe.Add(ref sourceRef, i); - ref CieLab dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCieLab(sp); - } - } - - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public CieLab ToCieLab(in CieXyz color) - { - CieXyz adapted = this.Adapt(color, this.whitePoint, this.targetLabWhitePoint); - - return this.cieXyzToCieLabConverter.Convert(adapted); - } - - /// - /// Performs the bulk conversion from into - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref CieXyz sourceRef = ref MemoryMarshal.GetReference(source); - ref CieLab destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref CieXyz sp = ref Unsafe.Add(ref sourceRef, i); - ref CieLab dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCieLab(sp); - } - } - - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public CieLab ToCieLab(in Cmyk color) - { - CieXyz xyzColor = this.ToCieXyz(color); - return this.ToCieLab(xyzColor); - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref Cmyk sourceRef = ref MemoryMarshal.GetReference(source); - ref CieLab destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref Cmyk sp = ref Unsafe.Add(ref sourceRef, i); - ref CieLab dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCieLab(sp); - } - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public CieLab ToCieLab(in Hsl color) - { - CieXyz xyzColor = this.ToCieXyz(color); - - return this.ToCieLab(xyzColor); - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref Hsl sourceRef = ref MemoryMarshal.GetReference(source); - ref CieLab destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref Hsl sp = ref Unsafe.Add(ref sourceRef, i); - ref CieLab dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCieLab(sp); - } - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public CieLab ToCieLab(in Hsv color) - { - CieXyz xyzColor = this.ToCieXyz(color); - return this.ToCieLab(xyzColor); - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref Hsv sourceRef = ref MemoryMarshal.GetReference(source); - ref CieLab destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref Hsv sp = ref Unsafe.Add(ref sourceRef, i); - ref CieLab dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCieLab(sp); - } - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public CieLab ToCieLab(in HunterLab color) - { - CieXyz xyzColor = this.ToCieXyz(color); - - return this.ToCieLab(xyzColor); - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref HunterLab sourceRef = ref MemoryMarshal.GetReference(source); - ref CieLab destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref HunterLab sp = ref Unsafe.Add(ref sourceRef, i); - ref CieLab dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCieLab(sp); - } - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public CieLab ToCieLab(in Lms color) - { - CieXyz xyzColor = this.ToCieXyz(color); - - return this.ToCieLab(xyzColor); - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref Lms sourceRef = ref MemoryMarshal.GetReference(source); - ref CieLab destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref Lms sp = ref Unsafe.Add(ref sourceRef, i); - ref CieLab dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCieLab(sp); - } - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public CieLab ToCieLab(in LinearRgb color) - { - CieXyz xyzColor = this.ToCieXyz(color); - - return this.ToCieLab(xyzColor); - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref LinearRgb sourceRef = ref MemoryMarshal.GetReference(source); - ref CieLab destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref LinearRgb sp = ref Unsafe.Add(ref sourceRef, i); - ref CieLab dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCieLab(sp); - } - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public CieLab ToCieLab(in Rgb color) - { - CieXyz xyzColor = this.ToCieXyz(color); - - return this.ToCieLab(xyzColor); - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref Rgb sourceRef = ref MemoryMarshal.GetReference(source); - ref CieLab destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref Rgb sp = ref Unsafe.Add(ref sourceRef, i); - ref CieLab dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCieLab(sp); - } - } - - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public CieLab ToCieLab(in YCbCr color) - { - CieXyz xyzColor = this.ToCieXyz(color); - - return this.ToCieLab(xyzColor); - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref YCbCr sourceRef = ref MemoryMarshal.GetReference(source); - ref CieLab destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref YCbCr sp = ref Unsafe.Add(ref sourceRef, i); - ref CieLab dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCieLab(sp); - } - } -} diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLch.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLch.cs deleted file mode 100644 index 9949b5d91b..0000000000 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLch.cs +++ /dev/null @@ -1,441 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -namespace SixLabors.ImageSharp.ColorSpaces.Conversion; - -/// -/// Allows conversion to . -/// -public partial class ColorSpaceConverter -{ - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public CieLch ToCieLch(in CieLab color) - { - CieLab adapted = this.Adapt(color); - - return CieLabToCieLchConverter.Convert(adapted); - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref CieLab sourceRef = ref MemoryMarshal.GetReference(source); - ref CieLch destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref CieLab sp = ref Unsafe.Add(ref sourceRef, i); - ref CieLch dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCieLch(sp); - } - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public CieLch ToCieLch(in CieLchuv color) - { - var xyzColor = this.ToCieXyz(color); - - return this.ToCieLch(xyzColor); - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref CieLchuv sourceRef = ref MemoryMarshal.GetReference(source); - ref CieLch destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref CieLchuv sp = ref Unsafe.Add(ref sourceRef, i); - ref CieLch dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCieLch(sp); - } - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public CieLch ToCieLch(in CieLuv color) - { - var xyzColor = this.ToCieXyz(color); - - return this.ToCieLch(xyzColor); - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref CieLuv sourceRef = ref MemoryMarshal.GetReference(source); - ref CieLch destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref CieLuv sp = ref Unsafe.Add(ref sourceRef, i); - ref CieLch dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCieLch(sp); - } - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public CieLch ToCieLch(in CieXyy color) - { - var xyzColor = ToCieXyz(color); - - return this.ToCieLch(xyzColor); - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref CieXyy sourceRef = ref MemoryMarshal.GetReference(source); - ref CieLch destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref CieXyy sp = ref Unsafe.Add(ref sourceRef, i); - ref CieLch dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCieLch(sp); - } - } - - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public CieLch ToCieLch(in CieXyz color) - { - var labColor = this.ToCieLab(color); - - return this.ToCieLch(labColor); - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref CieXyz sourceRef = ref MemoryMarshal.GetReference(source); - ref CieLch destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref CieXyz sp = ref Unsafe.Add(ref sourceRef, i); - ref CieLch dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCieLch(sp); - } - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public CieLch ToCieLch(in Cmyk color) - { - var xyzColor = this.ToCieXyz(color); - return this.ToCieLch(xyzColor); - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref Cmyk sourceRef = ref MemoryMarshal.GetReference(source); - ref CieLch destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref Cmyk sp = ref Unsafe.Add(ref sourceRef, i); - ref CieLch dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCieLch(sp); - } - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public CieLch ToCieLch(in Hsl color) - { - var xyzColor = this.ToCieXyz(color); - - return this.ToCieLch(xyzColor); - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref Hsl sourceRef = ref MemoryMarshal.GetReference(source); - ref CieLch destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref Hsl sp = ref Unsafe.Add(ref sourceRef, i); - ref CieLch dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCieLch(sp); - } - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public CieLch ToCieLch(in Hsv color) - { - var xyzColor = this.ToCieXyz(color); - - return this.ToCieLch(xyzColor); - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref Hsv sourceRef = ref MemoryMarshal.GetReference(source); - ref CieLch destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref Hsv sp = ref Unsafe.Add(ref sourceRef, i); - ref CieLch dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCieLch(sp); - } - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public CieLch ToCieLch(in HunterLab color) - { - var xyzColor = this.ToCieXyz(color); - - return this.ToCieLch(xyzColor); - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref HunterLab sourceRef = ref MemoryMarshal.GetReference(source); - ref CieLch destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref HunterLab sp = ref Unsafe.Add(ref sourceRef, i); - ref CieLch dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCieLch(sp); - } - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public CieLch ToCieLch(in LinearRgb color) - { - var xyzColor = this.ToCieXyz(color); - - return this.ToCieLch(xyzColor); - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref LinearRgb sourceRef = ref MemoryMarshal.GetReference(source); - ref CieLch destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref LinearRgb sp = ref Unsafe.Add(ref sourceRef, i); - ref CieLch dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCieLch(sp); - } - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public CieLch ToCieLch(in Lms color) - { - var xyzColor = this.ToCieXyz(color); - - return this.ToCieLch(xyzColor); - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref Lms sourceRef = ref MemoryMarshal.GetReference(source); - ref CieLch destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref Lms sp = ref Unsafe.Add(ref sourceRef, i); - ref CieLch dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCieLch(sp); - } - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public CieLch ToCieLch(in Rgb color) - { - var xyzColor = this.ToCieXyz(color); - - return this.ToCieLch(xyzColor); - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref Rgb sourceRef = ref MemoryMarshal.GetReference(source); - ref CieLch destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref Rgb sp = ref Unsafe.Add(ref sourceRef, i); - ref CieLch dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCieLch(sp); - } - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public CieLch ToCieLch(in YCbCr color) - { - var xyzColor = this.ToCieXyz(color); - - return this.ToCieLch(xyzColor); - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref YCbCr sourceRef = ref MemoryMarshal.GetReference(source); - ref CieLch destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref YCbCr sp = ref Unsafe.Add(ref sourceRef, i); - ref CieLch dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCieLch(sp); - } - } -} diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLchuv.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLchuv.cs deleted file mode 100644 index 4b856d1189..0000000000 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLchuv.cs +++ /dev/null @@ -1,441 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -namespace SixLabors.ImageSharp.ColorSpaces.Conversion; - -/// -/// Allows conversion to . -/// -public partial class ColorSpaceConverter -{ - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public CieLchuv ToCieLchuv(in CieLab color) - { - CieXyz xyzColor = this.ToCieXyz(color); - - return this.ToCieLchuv(xyzColor); - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref CieLab sourceRef = ref MemoryMarshal.GetReference(source); - ref CieLchuv destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref CieLab sp = ref Unsafe.Add(ref sourceRef, i); - ref CieLchuv dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCieLchuv(sp); - } - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public CieLchuv ToCieLchuv(in CieLch color) - { - CieXyz xyzColor = this.ToCieXyz(color); - - return this.ToCieLchuv(xyzColor); - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref CieLch sourceRef = ref MemoryMarshal.GetReference(source); - ref CieLchuv destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref CieLch sp = ref Unsafe.Add(ref sourceRef, i); - ref CieLchuv dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCieLchuv(sp); - } - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public CieLchuv ToCieLchuv(in CieLuv color) - { - CieLuv adapted = this.Adapt(color); - - return CieLuvToCieLchuvConverter.Convert(adapted); - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref CieLuv sourceRef = ref MemoryMarshal.GetReference(source); - ref CieLchuv destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref CieLuv sp = ref Unsafe.Add(ref sourceRef, i); - ref CieLchuv dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCieLchuv(sp); - } - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public CieLchuv ToCieLchuv(in CieXyy color) - { - CieXyz xyzColor = ToCieXyz(color); - - return this.ToCieLchuv(xyzColor); - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref CieXyy sourceRef = ref MemoryMarshal.GetReference(source); - ref CieLchuv destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref CieXyy sp = ref Unsafe.Add(ref sourceRef, i); - ref CieLchuv dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCieLchuv(sp); - } - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public CieLchuv ToCieLchuv(in CieXyz color) - { - CieLuv luvColor = this.ToCieLuv(color); - - return this.ToCieLchuv(luvColor); - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref CieXyz sourceRef = ref MemoryMarshal.GetReference(source); - ref CieLchuv destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref CieXyz sp = ref Unsafe.Add(ref sourceRef, i); - ref CieLchuv dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCieLchuv(sp); - } - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public CieLchuv ToCieLchuv(in Cmyk color) - { - CieXyz xyzColor = this.ToCieXyz(color); - - return this.ToCieLchuv(xyzColor); - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref Cmyk sourceRef = ref MemoryMarshal.GetReference(source); - ref CieLchuv destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref Cmyk sp = ref Unsafe.Add(ref sourceRef, i); - ref CieLchuv dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCieLchuv(sp); - } - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public CieLchuv ToCieLchuv(in Hsl color) - { - CieXyz xyzColor = this.ToCieXyz(color); - - return this.ToCieLchuv(xyzColor); - } - - /// - /// Performs the bulk conversion from into - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref Hsl sourceRef = ref MemoryMarshal.GetReference(source); - ref CieLchuv destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref Hsl sp = ref Unsafe.Add(ref sourceRef, i); - ref CieLchuv dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCieLchuv(sp); - } - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public CieLchuv ToCieLchuv(in Hsv color) - { - CieXyz xyzColor = this.ToCieXyz(color); - - return this.ToCieLchuv(xyzColor); - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref Hsv sourceRef = ref MemoryMarshal.GetReference(source); - ref CieLchuv destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref Hsv sp = ref Unsafe.Add(ref sourceRef, i); - ref CieLchuv dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCieLchuv(sp); - } - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public CieLchuv ToCieLchuv(in HunterLab color) - { - CieXyz xyzColor = this.ToCieXyz(color); - - return this.ToCieLchuv(xyzColor); - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref HunterLab sourceRef = ref MemoryMarshal.GetReference(source); - ref CieLchuv destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref HunterLab sp = ref Unsafe.Add(ref sourceRef, i); - ref CieLchuv dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCieLchuv(sp); - } - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public CieLchuv ToCieLchuv(in LinearRgb color) - { - CieXyz xyzColor = this.ToCieXyz(color); - - return this.ToCieLchuv(xyzColor); - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref LinearRgb sourceRef = ref MemoryMarshal.GetReference(source); - ref CieLchuv destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref LinearRgb sp = ref Unsafe.Add(ref sourceRef, i); - ref CieLchuv dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCieLchuv(sp); - } - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public CieLchuv ToCieLchuv(in Lms color) - { - CieXyz xyzColor = this.ToCieXyz(color); - - return this.ToCieLchuv(xyzColor); - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref Lms sourceRef = ref MemoryMarshal.GetReference(source); - ref CieLchuv destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref Lms sp = ref Unsafe.Add(ref sourceRef, i); - ref CieLchuv dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCieLchuv(sp); - } - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public CieLchuv ToCieLchuv(in Rgb color) - { - CieXyz xyzColor = this.ToCieXyz(color); - - return this.ToCieLchuv(xyzColor); - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref Rgb sourceRef = ref MemoryMarshal.GetReference(source); - ref CieLchuv destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref Rgb sp = ref Unsafe.Add(ref sourceRef, i); - ref CieLchuv dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCieLchuv(sp); - } - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public CieLchuv ToCieLchuv(in YCbCr color) - { - CieXyz xyzColor = this.ToCieXyz(color); - return this.ToCieLchuv(xyzColor); - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref YCbCr sourceRef = ref MemoryMarshal.GetReference(source); - ref CieLchuv destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref YCbCr sp = ref Unsafe.Add(ref sourceRef, i); - ref CieLchuv dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCieLchuv(sp); - } - } -} diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLuv.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLuv.cs deleted file mode 100644 index 2e8029f64a..0000000000 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLuv.cs +++ /dev/null @@ -1,435 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -namespace SixLabors.ImageSharp.ColorSpaces.Conversion; - -/// -/// Allows conversion to . -/// -public partial class ColorSpaceConverter -{ - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public CieLuv ToCieLuv(in CieLab color) - { - CieXyz xyzColor = this.ToCieXyz(color); - return this.ToCieLuv(xyzColor); - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref CieLab sourceRef = ref MemoryMarshal.GetReference(source); - ref CieLuv destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref CieLab sp = ref Unsafe.Add(ref sourceRef, i); - ref CieLuv dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCieLuv(sp); - } - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public CieLuv ToCieLuv(in CieLch color) - { - CieXyz xyzColor = this.ToCieXyz(color); - return this.ToCieLuv(xyzColor); - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref CieLch sourceRef = ref MemoryMarshal.GetReference(source); - ref CieLuv destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref CieLch sp = ref Unsafe.Add(ref sourceRef, i); - ref CieLuv dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCieLuv(sp); - } - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public CieLuv ToCieLuv(in CieLchuv color) - { - // Conversion (preserving white point) - CieLuv unadapted = CieLchuvToCieLuvConverter.Convert(color); - - // Adaptation - return this.Adapt(unadapted); - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref CieLchuv sourceRef = ref MemoryMarshal.GetReference(source); - ref CieLuv destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref CieLchuv sp = ref Unsafe.Add(ref sourceRef, i); - ref CieLuv dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCieLuv(sp); - } - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public CieLuv ToCieLuv(in CieXyy color) - { - CieXyz xyzColor = ToCieXyz(color); - return this.ToCieLuv(xyzColor); - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref CieXyy sourceRef = ref MemoryMarshal.GetReference(source); - ref CieLuv destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref CieXyy sp = ref Unsafe.Add(ref sourceRef, i); - ref CieLuv dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCieLuv(sp); - } - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public CieLuv ToCieLuv(in CieXyz color) - { - // Adaptation - CieXyz adapted = this.Adapt(color, this.whitePoint, this.targetLuvWhitePoint); - - // Conversion - return this.cieXyzToCieLuvConverter.Convert(adapted); - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref CieXyz sourceRef = ref MemoryMarshal.GetReference(source); - ref CieLuv destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref CieXyz sp = ref Unsafe.Add(ref sourceRef, i); - ref CieLuv dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCieLuv(sp); - } - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public CieLuv ToCieLuv(in Cmyk color) - { - CieXyz xyzColor = this.ToCieXyz(color); - return this.ToCieLuv(xyzColor); - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref Cmyk sourceRef = ref MemoryMarshal.GetReference(source); - ref CieLuv destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref Cmyk sp = ref Unsafe.Add(ref sourceRef, i); - ref CieLuv dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCieLuv(sp); - } - } - - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public CieLuv ToCieLuv(in Hsl color) - { - CieXyz xyzColor = this.ToCieXyz(color); - return this.ToCieLuv(xyzColor); - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref Hsl sourceRef = ref MemoryMarshal.GetReference(source); - ref CieLuv destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref Hsl sp = ref Unsafe.Add(ref sourceRef, i); - ref CieLuv dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCieLuv(sp); - } - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public CieLuv ToCieLuv(in Hsv color) - { - CieXyz xyzColor = this.ToCieXyz(color); - return this.ToCieLuv(xyzColor); - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref Hsv sourceRef = ref MemoryMarshal.GetReference(source); - ref CieLuv destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref Hsv sp = ref Unsafe.Add(ref sourceRef, i); - ref CieLuv dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCieLuv(sp); - } - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public CieLuv ToCieLuv(in HunterLab color) - { - CieXyz xyzColor = this.ToCieXyz(color); - return this.ToCieLuv(xyzColor); - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref HunterLab sourceRef = ref MemoryMarshal.GetReference(source); - ref CieLuv destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref HunterLab sp = ref Unsafe.Add(ref sourceRef, i); - ref CieLuv dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCieLuv(sp); - } - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public CieLuv ToCieLuv(in Lms color) - { - CieXyz xyzColor = this.ToCieXyz(color); - return this.ToCieLuv(xyzColor); - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref Lms sourceRef = ref MemoryMarshal.GetReference(source); - ref CieLuv destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref Lms sp = ref Unsafe.Add(ref sourceRef, i); - ref CieLuv dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCieLuv(sp); - } - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public CieLuv ToCieLuv(in LinearRgb color) - { - CieXyz xyzColor = this.ToCieXyz(color); - return this.ToCieLuv(xyzColor); - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref LinearRgb sourceRef = ref MemoryMarshal.GetReference(source); - ref CieLuv destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref LinearRgb sp = ref Unsafe.Add(ref sourceRef, i); - ref CieLuv dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCieLuv(sp); - } - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public CieLuv ToCieLuv(in Rgb color) - { - CieXyz xyzColor = this.ToCieXyz(color); - return this.ToCieLuv(xyzColor); - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref Rgb sourceRef = ref MemoryMarshal.GetReference(source); - ref CieLuv destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref Rgb sp = ref Unsafe.Add(ref sourceRef, i); - ref CieLuv dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCieLuv(sp); - } - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public CieLuv ToCieLuv(in YCbCr color) - { - CieXyz xyzColor = this.ToCieXyz(color); - return this.ToCieLuv(xyzColor); - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors. - /// The span to the destination colors. - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref YCbCr sourceRef = ref MemoryMarshal.GetReference(source); - ref CieLuv destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref YCbCr sp = ref Unsafe.Add(ref sourceRef, i); - ref CieLuv dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCieLuv(sp); - } - } -} diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieXyy.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieXyy.cs deleted file mode 100644 index 13b2a225c3..0000000000 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieXyy.cs +++ /dev/null @@ -1,437 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -namespace SixLabors.ImageSharp.ColorSpaces.Conversion; - -/// -/// Allows conversion to . -/// -public partial class ColorSpaceConverter -{ - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public CieXyy ToCieXyy(in CieLab color) - { - CieXyz xyzColor = this.ToCieXyz(color); - - return ToCieXyy(xyzColor); - } - - /// - /// Performs the bulk conversion from into - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref CieLab sourceRef = ref MemoryMarshal.GetReference(source); - ref CieXyy destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref CieLab sp = ref Unsafe.Add(ref sourceRef, i); - ref CieXyy dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCieXyy(sp); - } - } - - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public CieXyy ToCieXyy(in CieLch color) - { - CieXyz xyzColor = this.ToCieXyz(color); - - return ToCieXyy(xyzColor); - } - - /// - /// Performs the bulk conversion from into - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref CieLch sourceRef = ref MemoryMarshal.GetReference(source); - ref CieXyy destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref CieLch sp = ref Unsafe.Add(ref sourceRef, i); - ref CieXyy dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCieXyy(sp); - } - } - - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public CieXyy ToCieXyy(in CieLchuv color) - { - CieXyz xyzColor = this.ToCieXyz(color); - - return ToCieXyy(xyzColor); - } - - /// - /// Performs the bulk conversion from into - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref CieLchuv sourceRef = ref MemoryMarshal.GetReference(source); - ref CieXyy destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref CieLchuv sp = ref Unsafe.Add(ref sourceRef, i); - ref CieXyy dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCieXyy(sp); - } - } - - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public CieXyy ToCieXyy(in CieLuv color) - { - CieXyz xyzColor = this.ToCieXyz(color); - - return ToCieXyy(xyzColor); - } - - /// - /// Performs the bulk conversion from into - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref CieLuv sourceRef = ref MemoryMarshal.GetReference(source); - ref CieXyy destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref CieLuv sp = ref Unsafe.Add(ref sourceRef, i); - ref CieXyy dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCieXyy(sp); - } - } - - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public static CieXyy ToCieXyy(in CieXyz color) => CieXyzAndCieXyyConverter.Convert(color); - - /// - /// Performs the bulk conversion from into - /// - /// The span to the source colors - /// The span to the destination colors - public static void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref CieXyz sourceRef = ref MemoryMarshal.GetReference(source); - ref CieXyy destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref CieXyz sp = ref Unsafe.Add(ref sourceRef, i); - ref CieXyy dp = ref Unsafe.Add(ref destRef, i); - dp = ToCieXyy(sp); - } - } - - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public CieXyy ToCieXyy(in Cmyk color) - { - CieXyz xyzColor = this.ToCieXyz(color); - - return ToCieXyy(xyzColor); - } - - /// - /// Performs the bulk conversion from into - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref Cmyk sourceRef = ref MemoryMarshal.GetReference(source); - ref CieXyy destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref Cmyk sp = ref Unsafe.Add(ref sourceRef, i); - ref CieXyy dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCieXyy(sp); - } - } - - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public CieXyy ToCieXyy(Hsl color) - { - CieXyz xyzColor = this.ToCieXyz(color); - - return ToCieXyy(xyzColor); - } - - /// - /// Performs the bulk conversion from into - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref Hsl sourceRef = ref MemoryMarshal.GetReference(source); - ref CieXyy destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref Hsl sp = ref Unsafe.Add(ref sourceRef, i); - ref CieXyy dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCieXyy(sp); - } - } - - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public CieXyy ToCieXyy(in Hsv color) - { - CieXyz xyzColor = this.ToCieXyz(color); - - return ToCieXyy(xyzColor); - } - - /// - /// Performs the bulk conversion from into - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref Hsv sourceRef = ref MemoryMarshal.GetReference(source); - ref CieXyy destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref Hsv sp = ref Unsafe.Add(ref sourceRef, i); - ref CieXyy dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCieXyy(sp); - } - } - - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public CieXyy ToCieXyy(in HunterLab color) - { - CieXyz xyzColor = this.ToCieXyz(color); - - return ToCieXyy(xyzColor); - } - - /// - /// Performs the bulk conversion from into - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref HunterLab sourceRef = ref MemoryMarshal.GetReference(source); - ref CieXyy destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref HunterLab sp = ref Unsafe.Add(ref sourceRef, i); - ref CieXyy dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCieXyy(sp); - } - } - - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public CieXyy ToCieXyy(in LinearRgb color) - { - CieXyz xyzColor = this.ToCieXyz(color); - - return ToCieXyy(xyzColor); - } - - /// - /// Performs the bulk conversion from into - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref LinearRgb sourceRef = ref MemoryMarshal.GetReference(source); - ref CieXyy destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref LinearRgb sp = ref Unsafe.Add(ref sourceRef, i); - ref CieXyy dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCieXyy(sp); - } - } - - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public CieXyy ToCieXyy(in Lms color) - { - CieXyz xyzColor = this.ToCieXyz(color); - - return ToCieXyy(xyzColor); - } - - /// - /// Performs the bulk conversion from into - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref Lms sourceRef = ref MemoryMarshal.GetReference(source); - ref CieXyy destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref Lms sp = ref Unsafe.Add(ref sourceRef, i); - ref CieXyy dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCieXyy(sp); - } - } - - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public CieXyy ToCieXyy(in Rgb color) - { - CieXyz xyzColor = this.ToCieXyz(color); - - return ToCieXyy(xyzColor); - } - - /// - /// Performs the bulk conversion from into - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref Rgb sourceRef = ref MemoryMarshal.GetReference(source); - ref CieXyy destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref Rgb sp = ref Unsafe.Add(ref sourceRef, i); - ref CieXyy dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCieXyy(sp); - } - } - - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public CieXyy ToCieXyy(in YCbCr color) - { - CieXyz xyzColor = this.ToCieXyz(color); - - return ToCieXyy(xyzColor); - } - - /// - /// Performs the bulk conversion from into - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref YCbCr sourceRef = ref MemoryMarshal.GetReference(source); - ref CieXyy destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref YCbCr sp = ref Unsafe.Add(ref sourceRef, i); - ref CieXyy dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCieXyy(sp); - } - } -} diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieXyz.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieXyz.cs deleted file mode 100644 index 2212ca2e58..0000000000 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieXyz.cs +++ /dev/null @@ -1,458 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using System.Collections.Concurrent; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -namespace SixLabors.ImageSharp.ColorSpaces.Conversion; - -/// -/// Allows conversion to . -/// -public partial class ColorSpaceConverter -{ - private static readonly ConcurrentDictionary ConverterCache = new(); - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public CieXyz ToCieXyz(in CieLab color) - { - // Conversion - CieXyz unadapted = CieLabToCieXyzConverter.Convert(color); - - // Adaptation - return this.Adapt(unadapted, color.WhitePoint); - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref CieLab sourceRef = ref MemoryMarshal.GetReference(source); - ref CieXyz destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref CieLab sp = ref Unsafe.Add(ref sourceRef, i); - ref CieXyz dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCieXyz(sp); - } - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public CieXyz ToCieXyz(in CieLch color) - { - // Conversion to Lab - CieLab labColor = CieLchToCieLabConverter.Convert(color); - - // Conversion to XYZ (incl. adaptation) - return this.ToCieXyz(labColor); - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref CieLch sourceRef = ref MemoryMarshal.GetReference(source); - ref CieXyz destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref CieLch sp = ref Unsafe.Add(ref sourceRef, i); - ref CieXyz dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCieXyz(sp); - } - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public CieXyz ToCieXyz(in CieLchuv color) - { - // Conversion to Luv - CieLuv luvColor = CieLchuvToCieLuvConverter.Convert(color); - - // Conversion to XYZ (incl. adaptation) - return this.ToCieXyz(luvColor); - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref CieLchuv sourceRef = ref MemoryMarshal.GetReference(source); - ref CieXyz destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref CieLchuv sp = ref Unsafe.Add(ref sourceRef, i); - ref CieXyz dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCieXyz(sp); - } - } - - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public CieXyz ToCieXyz(in CieLuv color) - { - // Conversion - CieXyz unadapted = CieLuvToCieXyzConverter.Convert(color); - - // Adaptation - return this.Adapt(unadapted, color.WhitePoint); - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref CieLuv sourceRef = ref MemoryMarshal.GetReference(source); - ref CieXyz destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref CieLuv sp = ref Unsafe.Add(ref sourceRef, i); - ref CieXyz dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCieXyz(sp); - } - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public static CieXyz ToCieXyz(in CieXyy color) - - // Conversion - => CieXyzAndCieXyyConverter.Convert(color); - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public static void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref CieXyy sourceRef = ref MemoryMarshal.GetReference(source); - ref CieXyz destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref CieXyy sp = ref Unsafe.Add(ref sourceRef, i); - ref CieXyz dp = ref Unsafe.Add(ref destRef, i); - dp = ToCieXyz(sp); - } - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public CieXyz ToCieXyz(in Cmyk color) - { - Rgb rgb = ToRgb(color); - - return this.ToCieXyz(rgb); - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref Cmyk sourceRef = ref MemoryMarshal.GetReference(source); - ref CieXyz destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref Cmyk sp = ref Unsafe.Add(ref sourceRef, i); - ref CieXyz dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCieXyz(sp); - } - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public CieXyz ToCieXyz(in Hsl color) - { - Rgb rgb = ToRgb(color); - - return this.ToCieXyz(rgb); - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors. - /// The span to the destination colors. - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref Hsl sourceRef = ref MemoryMarshal.GetReference(source); - ref CieXyz destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref Hsl sp = ref Unsafe.Add(ref sourceRef, i); - ref CieXyz dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCieXyz(sp); - } - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public CieXyz ToCieXyz(in Hsv color) - { - // Conversion - Rgb rgb = ToRgb(color); - - return this.ToCieXyz(rgb); - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref Hsv sourceRef = ref MemoryMarshal.GetReference(source); - ref CieXyz destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref Hsv sp = ref Unsafe.Add(ref sourceRef, i); - ref CieXyz dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCieXyz(sp); - } - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public CieXyz ToCieXyz(in HunterLab color) - { - CieXyz unadapted = HunterLabToCieXyzConverter.Convert(color); - - return this.Adapt(unadapted, color.WhitePoint); - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref HunterLab sourceRef = ref MemoryMarshal.GetReference(source); - ref CieXyz destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref HunterLab sp = ref Unsafe.Add(ref sourceRef, i); - ref CieXyz dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCieXyz(sp); - } - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public CieXyz ToCieXyz(in LinearRgb color) - { - // Conversion - LinearRgbToCieXyzConverter converter = GetLinearRgbToCieXyzConverter(color.WorkingSpace); - CieXyz unadapted = converter.Convert(color); - - return this.Adapt(unadapted, color.WorkingSpace.WhitePoint); - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors. - /// The span to the destination colors. - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref LinearRgb sourceRef = ref MemoryMarshal.GetReference(source); - ref CieXyz destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref LinearRgb sp = ref Unsafe.Add(ref sourceRef, i); - ref CieXyz dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCieXyz(sp); - } - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public CieXyz ToCieXyz(in Lms color) - => this.cieXyzAndLmsConverter.Convert(color); - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref Lms sourceRef = ref MemoryMarshal.GetReference(source); - ref CieXyz destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref Lms sp = ref Unsafe.Add(ref sourceRef, i); - ref CieXyz dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCieXyz(sp); - } - } - - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public CieXyz ToCieXyz(in Rgb color) - { - // Conversion - LinearRgb linear = RgbToLinearRgbConverter.Convert(color); - return this.ToCieXyz(linear); - } - - /// - /// Performs the bulk conversion from into - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref Rgb sourceRef = ref MemoryMarshal.GetReference(source); - ref CieXyz destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref Rgb sp = ref Unsafe.Add(ref sourceRef, i); - ref CieXyz dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCieXyz(sp); - } - } - - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public CieXyz ToCieXyz(in YCbCr color) - { - Rgb rgb = this.ToRgb(color); - - return this.ToCieXyz(rgb); - } - - /// - /// Performs the bulk conversion from into - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref YCbCr sourceRef = ref MemoryMarshal.GetReference(source); - ref CieXyz destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref YCbCr sp = ref Unsafe.Add(ref sourceRef, i); - ref CieXyz dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCieXyz(sp); - } - } - - /// - /// Gets the correct converter for the given rgb working space. - /// - /// The source working space - /// The - private static LinearRgbToCieXyzConverter GetLinearRgbToCieXyzConverter(RgbWorkingSpace workingSpace) - => ConverterCache.GetOrAdd(workingSpace, (key) => new LinearRgbToCieXyzConverter(key)); -} diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Cmyk.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Cmyk.cs deleted file mode 100644 index ea9a5d734b..0000000000 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Cmyk.cs +++ /dev/null @@ -1,437 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -namespace SixLabors.ImageSharp.ColorSpaces.Conversion; - -/// -/// Allows conversion to . -/// -public partial class ColorSpaceConverter -{ - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public Cmyk ToCmyk(in CieLab color) - { - CieXyz xyzColor = this.ToCieXyz(color); - - return this.ToCmyk(xyzColor); - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref CieLab sourceRef = ref MemoryMarshal.GetReference(source); - ref Cmyk destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref CieLab sp = ref Unsafe.Add(ref sourceRef, i); - ref Cmyk dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCmyk(sp); - } - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public Cmyk ToCmyk(in CieLch color) - { - CieXyz xyzColor = this.ToCieXyz(color); - - return this.ToCmyk(xyzColor); - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref CieLch sourceRef = ref MemoryMarshal.GetReference(source); - ref Cmyk destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref CieLch sp = ref Unsafe.Add(ref sourceRef, i); - ref Cmyk dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCmyk(sp); - } - } - - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public Cmyk ToCmyk(in CieLchuv color) - { - CieXyz xyzColor = this.ToCieXyz(color); - - return this.ToCmyk(xyzColor); - } - - /// - /// Performs the bulk conversion from into - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref CieLchuv sourceRef = ref MemoryMarshal.GetReference(source); - ref Cmyk destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref CieLchuv sp = ref Unsafe.Add(ref sourceRef, i); - ref Cmyk dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCmyk(sp); - } - } - - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public Cmyk ToCmyk(in CieLuv color) - { - CieXyz xyzColor = this.ToCieXyz(color); - - return this.ToCmyk(xyzColor); - } - - /// - /// Performs the bulk conversion from into - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref CieLuv sourceRef = ref MemoryMarshal.GetReference(source); - ref Cmyk destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref CieLuv sp = ref Unsafe.Add(ref sourceRef, i); - ref Cmyk dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCmyk(sp); - } - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public Cmyk ToCmyk(in CieXyy color) - { - CieXyz xyzColor = ToCieXyz(color); - - return this.ToCmyk(xyzColor); - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref CieXyy sourceRef = ref MemoryMarshal.GetReference(source); - ref Cmyk destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref CieXyy sp = ref Unsafe.Add(ref sourceRef, i); - ref Cmyk dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCmyk(sp); - } - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public Cmyk ToCmyk(in CieXyz color) - { - Rgb rgb = this.ToRgb(color); - - return CmykAndRgbConverter.Convert(rgb); - } - - /// - /// Performs the bulk conversion from into - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref CieXyz sourceRef = ref MemoryMarshal.GetReference(source); - ref Cmyk destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref CieXyz sp = ref Unsafe.Add(ref sourceRef, i); - ref Cmyk dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCmyk(sp); - } - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public static Cmyk ToCmyk(in Hsl color) - { - Rgb rgb = ToRgb(color); - - return CmykAndRgbConverter.Convert(rgb); - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public static void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref Hsl sourceRef = ref MemoryMarshal.GetReference(source); - ref Cmyk destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref Hsl sp = ref Unsafe.Add(ref sourceRef, i); - ref Cmyk dp = ref Unsafe.Add(ref destRef, i); - dp = ToCmyk(sp); - } - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public static Cmyk ToCmyk(in Hsv color) - { - Rgb rgb = ToRgb(color); - - return CmykAndRgbConverter.Convert(rgb); - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public static void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref Hsv sourceRef = ref MemoryMarshal.GetReference(source); - ref Cmyk destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref Hsv sp = ref Unsafe.Add(ref sourceRef, i); - ref Cmyk dp = ref Unsafe.Add(ref destRef, i); - dp = ToCmyk(sp); - } - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public Cmyk ToCmyk(in HunterLab color) - { - CieXyz xyzColor = this.ToCieXyz(color); - - return this.ToCmyk(xyzColor); - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref HunterLab sourceRef = ref MemoryMarshal.GetReference(source); - ref Cmyk destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref HunterLab sp = ref Unsafe.Add(ref sourceRef, i); - ref Cmyk dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCmyk(sp); - } - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public static Cmyk ToCmyk(in LinearRgb color) - { - Rgb rgb = ToRgb(color); - - return CmykAndRgbConverter.Convert(rgb); - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public static void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref LinearRgb sourceRef = ref MemoryMarshal.GetReference(source); - ref Cmyk destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref LinearRgb sp = ref Unsafe.Add(ref sourceRef, i); - ref Cmyk dp = ref Unsafe.Add(ref destRef, i); - dp = ToCmyk(sp); - } - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public Cmyk ToCmyk(in Lms color) - { - CieXyz xyzColor = this.ToCieXyz(color); - - return this.ToCmyk(xyzColor); - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors, - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref Lms sourceRef = ref MemoryMarshal.GetReference(source); - ref Cmyk destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref Lms sp = ref Unsafe.Add(ref sourceRef, i); - ref Cmyk dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCmyk(sp); - } - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public static Cmyk ToCmyk(in Rgb color) => CmykAndRgbConverter.Convert(color); - - /// - /// Performs the bulk conversion from into - /// - /// The span to the source colors - /// The span to the destination colors - public static void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref Rgb sourceRef = ref MemoryMarshal.GetReference(source); - ref Cmyk destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref Rgb sp = ref Unsafe.Add(ref sourceRef, i); - ref Cmyk dp = ref Unsafe.Add(ref destRef, i); - dp = ToCmyk(sp); - } - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public Cmyk ToCmyk(in YCbCr color) - { - Rgb rgb = this.ToRgb(color); - - return CmykAndRgbConverter.Convert(rgb); - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref YCbCr sourceRef = ref MemoryMarshal.GetReference(source); - ref Cmyk destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref YCbCr sp = ref Unsafe.Add(ref sourceRef, i); - ref Cmyk dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToCmyk(sp); - } - } -} diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Hsl.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Hsl.cs deleted file mode 100644 index 67ec162917..0000000000 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Hsl.cs +++ /dev/null @@ -1,437 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -namespace SixLabors.ImageSharp.ColorSpaces.Conversion; - -/// -/// Allows conversion to . -/// -public partial class ColorSpaceConverter -{ - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public Hsl ToHsl(in CieLab color) - { - CieXyz xyzColor = this.ToCieXyz(color); - - return this.ToHsl(xyzColor); - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref CieLab sourceRef = ref MemoryMarshal.GetReference(source); - ref Hsl destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref CieLab sp = ref Unsafe.Add(ref sourceRef, i); - ref Hsl dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToHsl(sp); - } - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public Hsl ToHsl(in CieLch color) - { - CieXyz xyzColor = this.ToCieXyz(color); - - return this.ToHsl(xyzColor); - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref CieLch sourceRef = ref MemoryMarshal.GetReference(source); - ref Hsl destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref CieLch sp = ref Unsafe.Add(ref sourceRef, i); - ref Hsl dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToHsl(sp); - } - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public Hsl ToHsl(in CieLchuv color) - { - CieXyz xyzColor = this.ToCieXyz(color); - - return this.ToHsl(xyzColor); - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref CieLchuv sourceRef = ref MemoryMarshal.GetReference(source); - ref Hsl destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref CieLchuv sp = ref Unsafe.Add(ref sourceRef, i); - ref Hsl dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToHsl(sp); - } - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public Hsl ToHsl(in CieLuv color) - { - CieXyz xyzColor = this.ToCieXyz(color); - - return this.ToHsl(xyzColor); - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref CieLuv sourceRef = ref MemoryMarshal.GetReference(source); - ref Hsl destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref CieLuv sp = ref Unsafe.Add(ref sourceRef, i); - ref Hsl dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToHsl(sp); - } - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public Hsl ToHsl(in CieXyy color) - { - CieXyz xyzColor = ToCieXyz(color); - - return this.ToHsl(xyzColor); - } - - /// - /// Performs the bulk conversion from into - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref CieXyy sourceRef = ref MemoryMarshal.GetReference(source); - ref Hsl destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref CieXyy sp = ref Unsafe.Add(ref sourceRef, i); - ref Hsl dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToHsl(sp); - } - } - - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public Hsl ToHsl(in CieXyz color) - { - Rgb rgb = this.ToRgb(color); - - return HslAndRgbConverter.Convert(rgb); - } - - /// - /// Performs the bulk conversion from into - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref CieXyz sourceRef = ref MemoryMarshal.GetReference(source); - ref Hsl destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref CieXyz sp = ref Unsafe.Add(ref sourceRef, i); - ref Hsl dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToHsl(sp); - } - } - - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public static Hsl ToHsl(in Cmyk color) - { - Rgb rgb = ToRgb(color); - - return HslAndRgbConverter.Convert(rgb); - } - - /// - /// Performs the bulk conversion from into - /// - /// The span to the source colors - /// The span to the destination colors - public static void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref Cmyk sourceRef = ref MemoryMarshal.GetReference(source); - ref Hsl destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref Cmyk sp = ref Unsafe.Add(ref sourceRef, i); - ref Hsl dp = ref Unsafe.Add(ref destRef, i); - dp = ToHsl(sp); - } - } - - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public static Hsl ToHsl(in Hsv color) - { - Rgb rgb = ToRgb(color); - - return HslAndRgbConverter.Convert(rgb); - } - - /// - /// Performs the bulk conversion from into - /// - /// The span to the source colors - /// The span to the destination colors - public static void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref Hsv sourceRef = ref MemoryMarshal.GetReference(source); - ref Hsl destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref Hsv sp = ref Unsafe.Add(ref sourceRef, i); - ref Hsl dp = ref Unsafe.Add(ref destRef, i); - dp = ToHsl(sp); - } - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public Hsl ToHsl(in HunterLab color) - { - CieXyz xyzColor = this.ToCieXyz(color); - - return this.ToHsl(xyzColor); - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref HunterLab sourceRef = ref MemoryMarshal.GetReference(source); - ref Hsl destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref HunterLab sp = ref Unsafe.Add(ref sourceRef, i); - ref Hsl dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToHsl(sp); - } - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public static Hsl ToHsl(in LinearRgb color) - { - Rgb rgb = ToRgb(color); - - return HslAndRgbConverter.Convert(rgb); - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public static void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref LinearRgb sourceRef = ref MemoryMarshal.GetReference(source); - ref Hsl destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref LinearRgb sp = ref Unsafe.Add(ref sourceRef, i); - ref Hsl dp = ref Unsafe.Add(ref destRef, i); - dp = ToHsl(sp); - } - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public Hsl ToHsl(Lms color) - { - CieXyz xyzColor = this.ToCieXyz(color); - - return this.ToHsl(xyzColor); - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref Lms sourceRef = ref MemoryMarshal.GetReference(source); - ref Hsl destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref Lms sp = ref Unsafe.Add(ref sourceRef, i); - ref Hsl dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToHsl(sp); - } - } - - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public static Hsl ToHsl(in Rgb color) => HslAndRgbConverter.Convert(color); - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public static void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref Rgb sourceRef = ref MemoryMarshal.GetReference(source); - ref Hsl destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref Rgb sp = ref Unsafe.Add(ref sourceRef, i); - ref Hsl dp = ref Unsafe.Add(ref destRef, i); - dp = ToHsl(sp); - } - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public Hsl ToHsl(in YCbCr color) - { - Rgb rgb = this.ToRgb(color); - - return HslAndRgbConverter.Convert(rgb); - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref YCbCr sourceRef = ref MemoryMarshal.GetReference(source); - ref Hsl destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref YCbCr sp = ref Unsafe.Add(ref sourceRef, i); - ref Hsl dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToHsl(sp); - } - } -} diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Hsv.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Hsv.cs deleted file mode 100644 index 47ee42dc5a..0000000000 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Hsv.cs +++ /dev/null @@ -1,437 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -namespace SixLabors.ImageSharp.ColorSpaces.Conversion; - -/// -/// Allows conversion to . -/// -public partial class ColorSpaceConverter -{ - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public Hsv ToHsv(in CieLab color) - { - CieXyz xyzColor = this.ToCieXyz(color); - - return this.ToHsv(xyzColor); - } - - /// - /// Performs the bulk conversion from into - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref CieLab sourceRef = ref MemoryMarshal.GetReference(source); - ref Hsv destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref CieLab sp = ref Unsafe.Add(ref sourceRef, i); - ref Hsv dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToHsv(sp); - } - } - - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public Hsv ToHsv(in CieLch color) - { - CieXyz xyzColor = this.ToCieXyz(color); - - return this.ToHsv(xyzColor); - } - - /// - /// Performs the bulk conversion from into - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref CieLch sourceRef = ref MemoryMarshal.GetReference(source); - ref Hsv destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref CieLch sp = ref Unsafe.Add(ref sourceRef, i); - ref Hsv dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToHsv(sp); - } - } - - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public Hsv ToHsv(in CieLchuv color) - { - CieXyz xyzColor = this.ToCieXyz(color); - - return this.ToHsv(xyzColor); - } - - /// - /// Performs the bulk conversion from into - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref CieLchuv sourceRef = ref MemoryMarshal.GetReference(source); - ref Hsv destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref CieLchuv sp = ref Unsafe.Add(ref sourceRef, i); - ref Hsv dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToHsv(sp); - } - } - - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public Hsv ToHsv(in CieLuv color) - { - CieXyz xyzColor = this.ToCieXyz(color); - - return this.ToHsv(xyzColor); - } - - /// - /// Performs the bulk conversion from into - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref CieLuv sourceRef = ref MemoryMarshal.GetReference(source); - ref Hsv destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref CieLuv sp = ref Unsafe.Add(ref sourceRef, i); - ref Hsv dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToHsv(sp); - } - } - - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public Hsv ToHsv(in CieXyy color) - { - CieXyz xyzColor = ToCieXyz(color); - - return this.ToHsv(xyzColor); - } - - /// - /// Performs the bulk conversion from into - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref CieXyy sourceRef = ref MemoryMarshal.GetReference(source); - ref Hsv destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref CieXyy sp = ref Unsafe.Add(ref sourceRef, i); - ref Hsv dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToHsv(sp); - } - } - - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public Hsv ToHsv(in CieXyz color) - { - Rgb rgb = this.ToRgb(color); - - return HsvAndRgbConverter.Convert(rgb); - } - - /// - /// Performs the bulk conversion from into - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref CieXyz sourceRef = ref MemoryMarshal.GetReference(source); - ref Hsv destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref CieXyz sp = ref Unsafe.Add(ref sourceRef, i); - ref Hsv dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToHsv(sp); - } - } - - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public static Hsv ToHsv(in Cmyk color) - { - Rgb rgb = ToRgb(color); - - return HsvAndRgbConverter.Convert(rgb); - } - - /// - /// Performs the bulk conversion from into - /// - /// The span to the source colors - /// The span to the destination colors - public static void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref Cmyk sourceRef = ref MemoryMarshal.GetReference(source); - ref Hsv destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref Cmyk sp = ref Unsafe.Add(ref sourceRef, i); - ref Hsv dp = ref Unsafe.Add(ref destRef, i); - dp = ToHsv(sp); - } - } - - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public static Hsv ToHsv(in Hsl color) - { - Rgb rgb = ToRgb(color); - - return HsvAndRgbConverter.Convert(rgb); - } - - /// - /// Performs the bulk conversion from into - /// - /// The span to the source colors - /// The span to the destination colors. - public static void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref Hsl sourceRef = ref MemoryMarshal.GetReference(source); - ref Hsv destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref Hsl sp = ref Unsafe.Add(ref sourceRef, i); - ref Hsv dp = ref Unsafe.Add(ref destRef, i); - dp = ToHsv(sp); - } - } - - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public Hsv ToHsv(in HunterLab color) - { - CieXyz xyzColor = this.ToCieXyz(color); - - return this.ToHsv(xyzColor); - } - - /// - /// Performs the bulk conversion from into - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref HunterLab sourceRef = ref MemoryMarshal.GetReference(source); - ref Hsv destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref HunterLab sp = ref Unsafe.Add(ref sourceRef, i); - ref Hsv dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToHsv(sp); - } - } - - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public static Hsv ToHsv(in LinearRgb color) - { - Rgb rgb = ToRgb(color); - - return HsvAndRgbConverter.Convert(rgb); - } - - /// - /// Performs the bulk conversion from into - /// - /// The span to the source colors - /// The span to the destination colors - public static void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref LinearRgb sourceRef = ref MemoryMarshal.GetReference(source); - ref Hsv destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref LinearRgb sp = ref Unsafe.Add(ref sourceRef, i); - ref Hsv dp = ref Unsafe.Add(ref destRef, i); - dp = ToHsv(sp); - } - } - - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public Hsv ToHsv(Lms color) - { - CieXyz xyzColor = this.ToCieXyz(color); - - return this.ToHsv(xyzColor); - } - - /// - /// Performs the bulk conversion from into - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref Lms sourceRef = ref MemoryMarshal.GetReference(source); - ref Hsv destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref Lms sp = ref Unsafe.Add(ref sourceRef, i); - ref Hsv dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToHsv(sp); - } - } - - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public static Hsv ToHsv(in Rgb color) => HsvAndRgbConverter.Convert(color); - - /// - /// Performs the bulk conversion from into - /// - /// The span to the source colors - /// The span to the destination colors - public static void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref Rgb sourceRef = ref MemoryMarshal.GetReference(source); - ref Hsv destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref Rgb sp = ref Unsafe.Add(ref sourceRef, i); - ref Hsv dp = ref Unsafe.Add(ref destRef, i); - dp = ToHsv(sp); - } - } - - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public Hsv ToHsv(in YCbCr color) - { - Rgb rgb = this.ToRgb(color); - - return HsvAndRgbConverter.Convert(rgb); - } - - /// - /// Performs the bulk conversion from into - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref YCbCr sourceRef = ref MemoryMarshal.GetReference(source); - ref Hsv destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref YCbCr sp = ref Unsafe.Add(ref sourceRef, i); - ref Hsv dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToHsv(sp); - } - } -} diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.HunterLab.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.HunterLab.cs deleted file mode 100644 index 0604027760..0000000000 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.HunterLab.cs +++ /dev/null @@ -1,430 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -namespace SixLabors.ImageSharp.ColorSpaces.Conversion; - -/// -/// Allows conversion to . -/// -public partial class ColorSpaceConverter -{ - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors. - /// The span to the destination colors. - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref CieLab sourceRef = ref MemoryMarshal.GetReference(source); - ref HunterLab destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref CieLab sp = ref Unsafe.Add(ref sourceRef, i); - ref HunterLab dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToHunterLab(sp); - } - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors. - /// The span to the destination colors. - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref CieLch sourceRef = ref MemoryMarshal.GetReference(source); - ref HunterLab destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref CieLch sp = ref Unsafe.Add(ref sourceRef, i); - ref HunterLab dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToHunterLab(sp); - } - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref CieLchuv sourceRef = ref MemoryMarshal.GetReference(source); - ref HunterLab destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref CieLchuv sp = ref Unsafe.Add(ref sourceRef, i); - ref HunterLab dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToHunterLab(sp); - } - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref CieLuv sourceRef = ref MemoryMarshal.GetReference(source); - ref HunterLab destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref CieLuv sp = ref Unsafe.Add(ref sourceRef, i); - ref HunterLab dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToHunterLab(sp); - } - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors. - /// The span to the destination colors. - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref CieXyy sourceRef = ref MemoryMarshal.GetReference(source); - ref HunterLab destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref CieXyy sp = ref Unsafe.Add(ref sourceRef, i); - ref HunterLab dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToHunterLab(sp); - } - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors. - /// The span to the destination colors. - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref CieXyz sourceRef = ref MemoryMarshal.GetReference(source); - ref HunterLab destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref CieXyz sp = ref Unsafe.Add(ref sourceRef, i); - ref HunterLab dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToHunterLab(sp); - } - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref Cmyk sourceRef = ref MemoryMarshal.GetReference(source); - ref HunterLab destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref Cmyk sp = ref Unsafe.Add(ref sourceRef, i); - ref HunterLab dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToHunterLab(sp); - } - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors. - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref Hsl sourceRef = ref MemoryMarshal.GetReference(source); - ref HunterLab destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref Hsl sp = ref Unsafe.Add(ref sourceRef, i); - ref HunterLab dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToHunterLab(sp); - } - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref Hsv sourceRef = ref MemoryMarshal.GetReference(source); - ref HunterLab destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref Hsv sp = ref Unsafe.Add(ref sourceRef, i); - ref HunterLab dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToHunterLab(sp); - } - } - - /// - /// Performs the bulk conversion from into - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref LinearRgb sourceRef = ref MemoryMarshal.GetReference(source); - ref HunterLab destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref LinearRgb sp = ref Unsafe.Add(ref sourceRef, i); - ref HunterLab dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToHunterLab(sp); - } - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref Lms sourceRef = ref MemoryMarshal.GetReference(source); - ref HunterLab destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref Lms sp = ref Unsafe.Add(ref sourceRef, i); - ref HunterLab dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToHunterLab(sp); - } - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref Rgb sourceRef = ref MemoryMarshal.GetReference(source); - ref HunterLab destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref Rgb sp = ref Unsafe.Add(ref sourceRef, i); - ref HunterLab dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToHunterLab(sp); - } - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref YCbCr sourceRef = ref MemoryMarshal.GetReference(source); - ref HunterLab destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref YCbCr sp = ref Unsafe.Add(ref sourceRef, i); - ref HunterLab dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToHunterLab(sp); - } - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public HunterLab ToHunterLab(in CieLab color) - { - var xyzColor = this.ToCieXyz(color); - return this.ToHunterLab(xyzColor); - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public HunterLab ToHunterLab(in CieLch color) - { - var xyzColor = this.ToCieXyz(color); - return this.ToHunterLab(xyzColor); - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public HunterLab ToHunterLab(in CieLchuv color) - { - var xyzColor = this.ToCieXyz(color); - return this.ToHunterLab(xyzColor); - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public HunterLab ToHunterLab(in CieLuv color) - { - var xyzColor = this.ToCieXyz(color); - return this.ToHunterLab(xyzColor); - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public HunterLab ToHunterLab(in CieXyy color) - { - var xyzColor = ToCieXyz(color); - return this.ToHunterLab(xyzColor); - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public HunterLab ToHunterLab(in CieXyz color) - { - CieXyz adapted = this.Adapt(color, this.whitePoint, this.targetHunterLabWhitePoint); - - return this.cieXyzToHunterLabConverter.Convert(adapted); - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public HunterLab ToHunterLab(in Cmyk color) - { - var xyzColor = this.ToCieXyz(color); - return this.ToHunterLab(xyzColor); - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public HunterLab ToHunterLab(in Hsl color) - { - var xyzColor = this.ToCieXyz(color); - return this.ToHunterLab(xyzColor); - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public HunterLab ToHunterLab(in Hsv color) - { - var xyzColor = this.ToCieXyz(color); - return this.ToHunterLab(xyzColor); - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public HunterLab ToHunterLab(in LinearRgb color) - { - var xyzColor = this.ToCieXyz(color); - return this.ToHunterLab(xyzColor); - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public HunterLab ToHunterLab(in Lms color) - { - var xyzColor = this.ToCieXyz(color); - return this.ToHunterLab(xyzColor); - } - - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public HunterLab ToHunterLab(in Rgb color) - { - var xyzColor = this.ToCieXyz(color); - return this.ToHunterLab(xyzColor); - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public HunterLab ToHunterLab(in YCbCr color) - { - var xyzColor = this.ToCieXyz(color); - return this.ToHunterLab(xyzColor); - } -} diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.LinearRgb.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.LinearRgb.cs deleted file mode 100644 index fd385a15b0..0000000000 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.LinearRgb.cs +++ /dev/null @@ -1,429 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -namespace SixLabors.ImageSharp.ColorSpaces.Conversion; - -/// -/// Allows conversion to . -/// -public partial class ColorSpaceConverter -{ - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors. - /// The span to the destination colors. - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref CieLab sourceRef = ref MemoryMarshal.GetReference(source); - ref LinearRgb destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref CieLab sp = ref Unsafe.Add(ref sourceRef, i); - ref LinearRgb dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToLinearRgb(sp); - } - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors. - /// The span to the destination colors. - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref CieLch sourceRef = ref MemoryMarshal.GetReference(source); - ref LinearRgb destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref CieLch sp = ref Unsafe.Add(ref sourceRef, i); - ref LinearRgb dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToLinearRgb(sp); - } - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors. - /// The span to the destination colors. - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref CieLchuv sourceRef = ref MemoryMarshal.GetReference(source); - ref LinearRgb destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref CieLchuv sp = ref Unsafe.Add(ref sourceRef, i); - ref LinearRgb dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToLinearRgb(sp); - } - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors. - /// The span to the destination colors. - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref CieLuv sourceRef = ref MemoryMarshal.GetReference(source); - ref LinearRgb destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref CieLuv sp = ref Unsafe.Add(ref sourceRef, i); - ref LinearRgb dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToLinearRgb(sp); - } - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors. - /// The span to the destination colors. - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref CieXyy sourceRef = ref MemoryMarshal.GetReference(source); - ref LinearRgb destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref CieXyy sp = ref Unsafe.Add(ref sourceRef, i); - ref LinearRgb dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToLinearRgb(sp); - } - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors. - /// The span to the destination colors. - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref CieXyz sourceRef = ref MemoryMarshal.GetReference(source); - ref LinearRgb destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref CieXyz sp = ref Unsafe.Add(ref sourceRef, i); - ref LinearRgb dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToLinearRgb(sp); - } - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors. - /// The span to the destination colors. - public static void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref Cmyk sourceRef = ref MemoryMarshal.GetReference(source); - ref LinearRgb destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref Cmyk sp = ref Unsafe.Add(ref sourceRef, i); - ref LinearRgb dp = ref Unsafe.Add(ref destRef, i); - dp = ToLinearRgb(sp); - } - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors. - /// The span to the destination colors. - public static void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref Hsl sourceRef = ref MemoryMarshal.GetReference(source); - ref LinearRgb destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref Hsl sp = ref Unsafe.Add(ref sourceRef, i); - ref LinearRgb dp = ref Unsafe.Add(ref destRef, i); - dp = ToLinearRgb(sp); - } - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors. - /// The span to the destination colors. - public static void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref Hsv sourceRef = ref MemoryMarshal.GetReference(source); - ref LinearRgb destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref Hsv sp = ref Unsafe.Add(ref sourceRef, i); - ref LinearRgb dp = ref Unsafe.Add(ref destRef, i); - dp = ToLinearRgb(sp); - } - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors. - /// The span to the destination colors. - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref HunterLab sourceRef = ref MemoryMarshal.GetReference(source); - ref LinearRgb destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref HunterLab sp = ref Unsafe.Add(ref sourceRef, i); - ref LinearRgb dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToLinearRgb(sp); - } - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors. - /// The span to the destination colors. - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref Lms sourceRef = ref MemoryMarshal.GetReference(source); - ref LinearRgb destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref Lms sp = ref Unsafe.Add(ref sourceRef, i); - ref LinearRgb dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToLinearRgb(sp); - } - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public static void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref Rgb sourceRef = ref MemoryMarshal.GetReference(source); - ref LinearRgb destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref Rgb sp = ref Unsafe.Add(ref sourceRef, i); - ref LinearRgb dp = ref Unsafe.Add(ref destRef, i); - dp = ToLinearRgb(sp); - } - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref YCbCr sourceRef = ref MemoryMarshal.GetReference(source); - ref LinearRgb destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref YCbCr sp = ref Unsafe.Add(ref sourceRef, i); - ref LinearRgb dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToLinearRgb(sp); - } - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public LinearRgb ToLinearRgb(in CieLab color) - { - CieXyz xyzColor = this.ToCieXyz(color); - return this.ToLinearRgb(xyzColor); - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public LinearRgb ToLinearRgb(in CieLch color) - { - CieXyz xyzColor = this.ToCieXyz(color); - return this.ToLinearRgb(xyzColor); - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public LinearRgb ToLinearRgb(in CieLchuv color) - { - CieXyz xyzColor = this.ToCieXyz(color); - return this.ToLinearRgb(xyzColor); - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public LinearRgb ToLinearRgb(in CieLuv color) - { - CieXyz xyzColor = this.ToCieXyz(color); - return this.ToLinearRgb(xyzColor); - } - - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public LinearRgb ToLinearRgb(in CieXyy color) - { - CieXyz xyzColor = ToCieXyz(color); - return this.ToLinearRgb(xyzColor); - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public LinearRgb ToLinearRgb(in CieXyz color) - { - // Adaptation - CieXyz adapted = this.Adapt(color, this.whitePoint, this.targetRgbWorkingSpace.WhitePoint); - - // Conversion - return this.cieXyzToLinearRgbConverter.Convert(adapted); - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public static LinearRgb ToLinearRgb(in Cmyk color) - { - Rgb rgb = ToRgb(color); - return ToLinearRgb(rgb); - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public static LinearRgb ToLinearRgb(in Hsl color) - { - Rgb rgb = ToRgb(color); - return ToLinearRgb(rgb); - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public static LinearRgb ToLinearRgb(in Hsv color) - { - Rgb rgb = ToRgb(color); - return ToLinearRgb(rgb); - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public LinearRgb ToLinearRgb(in HunterLab color) - { - CieXyz xyzColor = this.ToCieXyz(color); - return this.ToLinearRgb(xyzColor); - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public LinearRgb ToLinearRgb(in Lms color) - { - CieXyz xyzColor = this.ToCieXyz(color); - return this.ToLinearRgb(xyzColor); - } - - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public static LinearRgb ToLinearRgb(in Rgb color) - => RgbToLinearRgbConverter.Convert(color); - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public LinearRgb ToLinearRgb(in YCbCr color) - { - Rgb rgb = this.ToRgb(color); - return ToLinearRgb(rgb); - } -} diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Lms.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Lms.cs deleted file mode 100644 index 56f61ef80b..0000000000 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Lms.cs +++ /dev/null @@ -1,425 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -namespace SixLabors.ImageSharp.ColorSpaces.Conversion; - -/// -/// Allows conversion to . -/// -public partial class ColorSpaceConverter -{ - /// - /// Performs the bulk conversion from into - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref CieLab sourceRef = ref MemoryMarshal.GetReference(source); - ref Lms destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref CieLab sp = ref Unsafe.Add(ref sourceRef, i); - ref Lms dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToLms(sp); - } - } - - /// - /// Performs the bulk conversion from into - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref CieLch sourceRef = ref MemoryMarshal.GetReference(source); - ref Lms destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref CieLch sp = ref Unsafe.Add(ref sourceRef, i); - ref Lms dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToLms(sp); - } - } - - /// - /// Performs the bulk conversion from into - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref CieLchuv sourceRef = ref MemoryMarshal.GetReference(source); - ref Lms destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref CieLchuv sp = ref Unsafe.Add(ref sourceRef, i); - ref Lms dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToLms(sp); - } - } - - /// - /// Performs the bulk conversion from into - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref CieLuv sourceRef = ref MemoryMarshal.GetReference(source); - ref Lms destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref CieLuv sp = ref Unsafe.Add(ref sourceRef, i); - ref Lms dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToLms(sp); - } - } - - /// - /// Performs the bulk conversion from into - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref CieXyy sourceRef = ref MemoryMarshal.GetReference(source); - ref Lms destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref CieXyy sp = ref Unsafe.Add(ref sourceRef, i); - ref Lms dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToLms(sp); - } - } - - /// - /// Performs the bulk conversion from into - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref CieXyz sourceRef = ref MemoryMarshal.GetReference(source); - ref Lms destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref CieXyz sp = ref Unsafe.Add(ref sourceRef, i); - ref Lms dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToLms(sp); - } - } - - /// - /// Performs the bulk conversion from into - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref Cmyk sourceRef = ref MemoryMarshal.GetReference(source); - ref Lms destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref Cmyk sp = ref Unsafe.Add(ref sourceRef, i); - ref Lms dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToLms(sp); - } - } - - /// - /// Performs the bulk conversion from into - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref Hsl sourceRef = ref MemoryMarshal.GetReference(source); - ref Lms destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref Hsl sp = ref Unsafe.Add(ref sourceRef, i); - ref Lms dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToLms(sp); - } - } - - /// - /// Performs the bulk conversion from into - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref Hsv sourceRef = ref MemoryMarshal.GetReference(source); - ref Lms destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref Hsv sp = ref Unsafe.Add(ref sourceRef, i); - ref Lms dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToLms(sp); - } - } - - /// - /// Performs the bulk conversion from into - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref HunterLab sourceRef = ref MemoryMarshal.GetReference(source); - ref Lms destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref HunterLab sp = ref Unsafe.Add(ref sourceRef, i); - ref Lms dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToLms(sp); - } - } - - /// - /// Performs the bulk conversion from into - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref LinearRgb sourceRef = ref MemoryMarshal.GetReference(source); - ref Lms destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref LinearRgb sp = ref Unsafe.Add(ref sourceRef, i); - ref Lms dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToLms(sp); - } - } - - /// - /// Performs the bulk conversion from into - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref Rgb sourceRef = ref MemoryMarshal.GetReference(source); - ref Lms destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref Rgb sp = ref Unsafe.Add(ref sourceRef, i); - ref Lms dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToLms(sp); - } - } - - /// - /// Performs the bulk conversion from into - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref YCbCr sourceRef = ref MemoryMarshal.GetReference(source); - ref Lms destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref YCbCr sp = ref Unsafe.Add(ref sourceRef, i); - ref Lms dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToLms(sp); - } - } - - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public Lms ToLms(in CieLab color) - { - var xyzColor = this.ToCieXyz(color); - return this.ToLms(xyzColor); - } - - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public Lms ToLms(in CieLch color) - { - var xyzColor = this.ToCieXyz(color); - return this.ToLms(xyzColor); - } - - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public Lms ToLms(in CieLchuv color) - { - var xyzColor = this.ToCieXyz(color); - return this.ToLms(xyzColor); - } - - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public Lms ToLms(in CieLuv color) - { - var xyzColor = this.ToCieXyz(color); - return this.ToLms(xyzColor); - } - - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public Lms ToLms(in CieXyy color) - { - var xyzColor = ToCieXyz(color); - return this.ToLms(xyzColor); - } - - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public Lms ToLms(in CieXyz color) => this.cieXyzAndLmsConverter.Convert(color); - - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public Lms ToLms(in Cmyk color) - { - var xyzColor = this.ToCieXyz(color); - return this.ToLms(xyzColor); - } - - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public Lms ToLms(in Hsl color) - { - var xyzColor = this.ToCieXyz(color); - return this.ToLms(xyzColor); - } - - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public Lms ToLms(in Hsv color) - { - var xyzColor = this.ToCieXyz(color); - return this.ToLms(xyzColor); - } - - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public Lms ToLms(in HunterLab color) - { - var xyzColor = this.ToCieXyz(color); - return this.ToLms(xyzColor); - } - - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public Lms ToLms(in LinearRgb color) - { - var xyzColor = this.ToCieXyz(color); - return this.ToLms(xyzColor); - } - - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public Lms ToLms(in Rgb color) - { - var xyzColor = this.ToCieXyz(color); - return this.ToLms(xyzColor); - } - - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public Lms ToLms(in YCbCr color) - { - var xyzColor = this.ToCieXyz(color); - return this.ToLms(xyzColor); - } -} diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Rgb.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Rgb.cs deleted file mode 100644 index 080e1fc4bf..0000000000 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Rgb.cs +++ /dev/null @@ -1,419 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -namespace SixLabors.ImageSharp.ColorSpaces.Conversion; - -/// -/// Allows conversion to . -/// -public partial class ColorSpaceConverter -{ - /// - /// Performs the bulk conversion from into - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref CieLab sourceRef = ref MemoryMarshal.GetReference(source); - ref Rgb destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref CieLab sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgb dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToRgb(sp); - } - } - - /// - /// Performs the bulk conversion from into - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref CieLch sourceRef = ref MemoryMarshal.GetReference(source); - ref Rgb destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref CieLch sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgb dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToRgb(sp); - } - } - - /// - /// Performs the bulk conversion from into - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref CieLchuv sourceRef = ref MemoryMarshal.GetReference(source); - ref Rgb destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref CieLchuv sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgb dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToRgb(sp); - } - } - - /// - /// Performs the bulk conversion from into - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref CieLuv sourceRef = ref MemoryMarshal.GetReference(source); - ref Rgb destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref CieLuv sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgb dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToRgb(sp); - } - } - - /// - /// Performs the bulk conversion from into - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref CieXyy sourceRef = ref MemoryMarshal.GetReference(source); - ref Rgb destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref CieXyy sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgb dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToRgb(sp); - } - } - - /// - /// Performs the bulk conversion from into - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref CieXyz sourceRef = ref MemoryMarshal.GetReference(source); - ref Rgb destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref CieXyz sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgb dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToRgb(sp); - } - } - - /// - /// Performs the bulk conversion from into - /// - /// The span to the source colors - /// The span to the destination colors - public static void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref Cmyk sourceRef = ref MemoryMarshal.GetReference(source); - ref Rgb destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref Cmyk sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgb dp = ref Unsafe.Add(ref destRef, i); - dp = ToRgb(sp); - } - } - - /// - /// Performs the bulk conversion from into - /// - /// The span to the source colors - /// The span to the destination colors - public static void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref Hsv sourceRef = ref MemoryMarshal.GetReference(source); - ref Rgb destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref Hsv sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgb dp = ref Unsafe.Add(ref destRef, i); - dp = ToRgb(sp); - } - } - - /// - /// Performs the bulk conversion from into - /// - /// The span to the source colors - /// The span to the destination colors - public static void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref Hsl sourceRef = ref MemoryMarshal.GetReference(source); - ref Rgb destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref Hsl sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgb dp = ref Unsafe.Add(ref destRef, i); - dp = ToRgb(sp); - } - } - - /// - /// Performs the bulk conversion from into - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref HunterLab sourceRef = ref MemoryMarshal.GetReference(source); - ref Rgb destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref HunterLab sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgb dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToRgb(sp); - } - } - - /// - /// Performs the bulk conversion from into - /// - /// The span to the source colors - /// The span to the destination colors - public static void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref LinearRgb sourceRef = ref MemoryMarshal.GetReference(source); - ref Rgb destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref LinearRgb sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgb dp = ref Unsafe.Add(ref destRef, i); - dp = ToRgb(sp); - } - } - - /// - /// Performs the bulk conversion from into - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref Lms sourceRef = ref MemoryMarshal.GetReference(source); - ref Rgb destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref Lms sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgb dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToRgb(sp); - } - } - - /// - /// Performs the bulk conversion from into - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref YCbCr sourceRef = ref MemoryMarshal.GetReference(source); - ref Rgb destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref YCbCr sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgb dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToRgb(sp); - } - } - - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public Rgb ToRgb(in CieLab color) - { - CieXyz xyzColor = this.ToCieXyz(color); - return this.ToRgb(xyzColor); - } - - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public Rgb ToRgb(in CieLch color) - { - CieXyz xyzColor = this.ToCieXyz(color); - return this.ToRgb(xyzColor); - } - - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public Rgb ToRgb(in CieLchuv color) - { - CieXyz xyzColor = this.ToCieXyz(color); - return this.ToRgb(xyzColor); - } - - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public Rgb ToRgb(in CieLuv color) - { - CieXyz xyzColor = this.ToCieXyz(color); - return this.ToRgb(xyzColor); - } - - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public Rgb ToRgb(in CieXyy color) - { - CieXyz xyzColor = ToCieXyz(color); - return this.ToRgb(xyzColor); - } - - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public Rgb ToRgb(in CieXyz color) - { - // Conversion - LinearRgb linear = this.ToLinearRgb(color); - - // Compand - return ToRgb(linear); - } - - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public static Rgb ToRgb(in Cmyk color) => CmykAndRgbConverter.Convert(color); - - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public static Rgb ToRgb(in Hsv color) => HsvAndRgbConverter.Convert(color); - - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public static Rgb ToRgb(in Hsl color) => HslAndRgbConverter.Convert(color); - - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public Rgb ToRgb(in HunterLab color) - { - CieXyz xyzColor = this.ToCieXyz(color); - return this.ToRgb(xyzColor); - } - - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public static Rgb ToRgb(in LinearRgb color) => LinearRgbToRgbConverter.Convert(color); - - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public Rgb ToRgb(in Lms color) - { - CieXyz xyzColor = this.ToCieXyz(color); - return this.ToRgb(xyzColor); - } - - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public Rgb ToRgb(in YCbCr color) - { - // Conversion - Rgb rgb = YCbCrAndRgbConverter.Convert(color); - - // Adaptation - return this.Adapt(rgb); - } -} diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.YCbCr.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.YCbCr.cs deleted file mode 100644 index da8e046ff7..0000000000 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.YCbCr.cs +++ /dev/null @@ -1,404 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -namespace SixLabors.ImageSharp.ColorSpaces.Conversion; - -/// -/// Allows conversion to . -/// -public partial class ColorSpaceConverter -{ - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors. - /// The span to the destination colors. - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref CieLab sourceRef = ref MemoryMarshal.GetReference(source); - ref YCbCr destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref CieLab sp = ref Unsafe.Add(ref sourceRef, i); - ref YCbCr dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToYCbCr(sp); - } - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors. - /// The span to the destination colors. - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref CieLch sourceRef = ref MemoryMarshal.GetReference(source); - ref YCbCr destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref CieLch sp = ref Unsafe.Add(ref sourceRef, i); - ref YCbCr dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToYCbCr(sp); - } - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref CieLuv sourceRef = ref MemoryMarshal.GetReference(source); - ref YCbCr destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref CieLuv sp = ref Unsafe.Add(ref sourceRef, i); - ref YCbCr dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToYCbCr(sp); - } - } - - /// - /// Performs the bulk conversion from into - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref CieXyy sourceRef = ref MemoryMarshal.GetReference(source); - ref YCbCr destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref CieXyy sp = ref Unsafe.Add(ref sourceRef, i); - ref YCbCr dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToYCbCr(sp); - } - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref CieXyz sourceRef = ref MemoryMarshal.GetReference(source); - ref YCbCr destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref CieXyz sp = ref Unsafe.Add(ref sourceRef, i); - ref YCbCr dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToYCbCr(sp); - } - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public static void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref Cmyk sourceRef = ref MemoryMarshal.GetReference(source); - ref YCbCr destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref Cmyk sp = ref Unsafe.Add(ref sourceRef, i); - ref YCbCr dp = ref Unsafe.Add(ref destRef, i); - dp = ToYCbCr(sp); - } - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public static void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref Hsl sourceRef = ref MemoryMarshal.GetReference(source); - ref YCbCr destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref Hsl sp = ref Unsafe.Add(ref sourceRef, i); - ref YCbCr dp = ref Unsafe.Add(ref destRef, i); - dp = ToYCbCr(sp); - } - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public static void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref Hsv sourceRef = ref MemoryMarshal.GetReference(source); - ref YCbCr destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref Hsv sp = ref Unsafe.Add(ref sourceRef, i); - ref YCbCr dp = ref Unsafe.Add(ref destRef, i); - dp = ToYCbCr(sp); - } - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref HunterLab sourceRef = ref MemoryMarshal.GetReference(source); - ref YCbCr destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref HunterLab sp = ref Unsafe.Add(ref sourceRef, i); - ref YCbCr dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToYCbCr(sp); - } - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public static void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref LinearRgb sourceRef = ref MemoryMarshal.GetReference(source); - ref YCbCr destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref LinearRgb sp = ref Unsafe.Add(ref sourceRef, i); - ref YCbCr dp = ref Unsafe.Add(ref destRef, i); - dp = ToYCbCr(sp); - } - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref Lms sourceRef = ref MemoryMarshal.GetReference(source); - ref YCbCr destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref Lms sp = ref Unsafe.Add(ref sourceRef, i); - ref YCbCr dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToYCbCr(sp); - } - } - - /// - /// Performs the bulk conversion from into . - /// - /// The span to the source colors - /// The span to the destination colors - public static void Convert(ReadOnlySpan source, Span destination) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - ref Rgb sourceRef = ref MemoryMarshal.GetReference(source); - ref YCbCr destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref Rgb sp = ref Unsafe.Add(ref sourceRef, i); - ref YCbCr dp = ref Unsafe.Add(ref destRef, i); - dp = ToYCbCr(sp); - } - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public YCbCr ToYCbCr(in CieLab color) - { - CieXyz xyzColor = this.ToCieXyz(color); - - return this.ToYCbCr(xyzColor); - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public YCbCr ToYCbCr(in CieLch color) - { - CieXyz xyzColor = this.ToCieXyz(color); - - return this.ToYCbCr(xyzColor); - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public YCbCr ToYCbCr(in CieLuv color) - { - CieXyz xyzColor = this.ToCieXyz(color); - - return this.ToYCbCr(xyzColor); - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public YCbCr ToYCbCr(in CieXyy color) - { - CieXyz xyzColor = ToCieXyz(color); - - return this.ToYCbCr(xyzColor); - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public YCbCr ToYCbCr(in CieXyz color) - { - Rgb rgb = this.ToRgb(color); - - return YCbCrAndRgbConverter.Convert(rgb); - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public static YCbCr ToYCbCr(in Cmyk color) - { - Rgb rgb = ToRgb(color); - - return YCbCrAndRgbConverter.Convert(rgb); - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public static YCbCr ToYCbCr(in Hsl color) - { - Rgb rgb = ToRgb(color); - - return YCbCrAndRgbConverter.Convert(rgb); - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public static YCbCr ToYCbCr(in Hsv color) - { - Rgb rgb = ToRgb(color); - - return YCbCrAndRgbConverter.Convert(rgb); - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public YCbCr ToYCbCr(in HunterLab color) - { - CieXyz xyzColor = this.ToCieXyz(color); - - return this.ToYCbCr(xyzColor); - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public static YCbCr ToYCbCr(in LinearRgb color) - { - Rgb rgb = ToRgb(color); - - return YCbCrAndRgbConverter.Convert(rgb); - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public YCbCr ToYCbCr(in Lms color) - { - CieXyz xyzColor = this.ToCieXyz(color); - - return this.ToYCbCr(xyzColor); - } - - /// - /// Converts a into a . - /// - /// The color to convert. - /// The - public static YCbCr ToYCbCr(in Rgb color) => YCbCrAndRgbConverter.Convert(color); -} diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.cs deleted file mode 100644 index b5e3162e64..0000000000 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.cs +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using System.Numerics; - -namespace SixLabors.ImageSharp.ColorSpaces.Conversion; - -/// -/// Provides methods to allow the conversion of color values between different color spaces. -/// -public partial class ColorSpaceConverter -{ - // Options. - private static readonly ColorSpaceConverterOptions DefaultOptions = new(); - private readonly Matrix4x4 lmsAdaptationMatrix; - private readonly CieXyz whitePoint; - private readonly CieXyz targetLuvWhitePoint; - private readonly CieXyz targetLabWhitePoint; - private readonly CieXyz targetHunterLabWhitePoint; - private readonly RgbWorkingSpace targetRgbWorkingSpace; - private readonly IChromaticAdaptation? chromaticAdaptation; - private readonly bool performChromaticAdaptation; - private readonly CieXyzAndLmsConverter cieXyzAndLmsConverter; - private readonly CieXyzToCieLabConverter cieXyzToCieLabConverter; - private readonly CieXyzToCieLuvConverter cieXyzToCieLuvConverter; - private readonly CieXyzToHunterLabConverter cieXyzToHunterLabConverter; - private readonly CieXyzToLinearRgbConverter cieXyzToLinearRgbConverter; - - /// - /// Initializes a new instance of the class. - /// - public ColorSpaceConverter() - : this(DefaultOptions) - { - } - - /// - /// Initializes a new instance of the class. - /// - /// The configuration options. - public ColorSpaceConverter(ColorSpaceConverterOptions options) - { - Guard.NotNull(options, nameof(options)); - this.whitePoint = options.WhitePoint; - this.targetLuvWhitePoint = options.TargetLuvWhitePoint; - this.targetLabWhitePoint = options.TargetLabWhitePoint; - this.targetHunterLabWhitePoint = options.TargetHunterLabWhitePoint; - this.targetRgbWorkingSpace = options.TargetRgbWorkingSpace; - this.chromaticAdaptation = options.ChromaticAdaptation; - this.performChromaticAdaptation = this.chromaticAdaptation != null; - this.lmsAdaptationMatrix = options.LmsAdaptationMatrix; - - this.cieXyzAndLmsConverter = new CieXyzAndLmsConverter(this.lmsAdaptationMatrix); - this.cieXyzToCieLabConverter = new CieXyzToCieLabConverter(this.targetLabWhitePoint); - this.cieXyzToCieLuvConverter = new CieXyzToCieLuvConverter(this.targetLuvWhitePoint); - this.cieXyzToHunterLabConverter = new CieXyzToHunterLabConverter(this.targetHunterLabWhitePoint); - this.cieXyzToLinearRgbConverter = new CieXyzToLinearRgbConverter(this.targetRgbWorkingSpace); - } -} diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverterOptions.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverterOptions.cs deleted file mode 100644 index 9f576de726..0000000000 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverterOptions.cs +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using System.Numerics; - -namespace SixLabors.ImageSharp.ColorSpaces.Conversion; - -/// -/// Configuration options for the class. -/// -public class ColorSpaceConverterOptions -{ - /// - /// Gets or sets the white point used for chromatic adaptation in conversions from/to XYZ color space. - /// When default, no adaptation will be performed. - /// Defaults to: . - /// - public CieXyz WhitePoint { get; set; } = CieLuv.DefaultWhitePoint; - - /// - /// Gets or sets the white point used *when creating* Luv/LChuv colors. (Luv/LChuv colors on the input already contain the white point information) - /// Defaults to: . - /// - public CieXyz TargetLuvWhitePoint { get; set; } = CieLuv.DefaultWhitePoint; - - /// - /// Gets or sets the white point used *when creating* Lab/LChab colors. (Lab/LChab colors on the input already contain the white point information) - /// Defaults to: . - /// - public CieXyz TargetLabWhitePoint { get; set; } = CieLab.DefaultWhitePoint; - - /// - /// Gets or sets the white point used *when creating* HunterLab colors. (HunterLab colors on the input already contain the white point information) - /// Defaults to: . - /// - public CieXyz TargetHunterLabWhitePoint { get; set; } = HunterLab.DefaultWhitePoint; - - /// - /// Gets or sets the target working space used *when creating* RGB colors. (RGB colors on the input already contain the working space information) - /// Defaults to: . - /// - public RgbWorkingSpace TargetRgbWorkingSpace { get; set; } = Rgb.DefaultWorkingSpace; - - /// - /// Gets or sets the chromatic adaptation method used. When null, no adaptation will be performed. - /// - public IChromaticAdaptation? ChromaticAdaptation { get; set; } = new VonKriesChromaticAdaptation(); - - /// - /// Gets or sets transformation matrix used in conversion to and from . - /// - public Matrix4x4 LmsAdaptationMatrix { get; set; } = CieXyzAndLmsConverter.DefaultTransformationMatrix; -} diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CIeLchToCieLabConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CIeLchToCieLabConverter.cs deleted file mode 100644 index f16ce7b0fa..0000000000 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CIeLchToCieLabConverter.cs +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using System.Runtime.CompilerServices; - -namespace SixLabors.ImageSharp.ColorSpaces.Conversion; - -/// -/// Converts from to . -/// -internal static class CieLchToCieLabConverter -{ - /// - /// Performs the conversion from the input to an instance of type. - /// - /// The input color instance. - /// The converted result - [MethodImpl(InliningOptions.ShortMethod)] - public static CieLab Convert(in CieLch input) - { - // Conversion algorithm described here: - // https://en.wikipedia.org/wiki/Lab_color_space#Cylindrical_representation:_CIELCh_or_CIEHLC - float l = input.L, c = input.C, hDegrees = input.H; - float hRadians = GeometryUtilities.DegreeToRadian(hDegrees); - - float a = c * MathF.Cos(hRadians); - float b = c * MathF.Sin(hRadians); - - return new CieLab(l, a, b, input.WhitePoint); - } -} diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieLabToCieLchConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieLabToCieLchConverter.cs deleted file mode 100644 index 4eeb7695e1..0000000000 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieLabToCieLchConverter.cs +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using System.Runtime.CompilerServices; - -namespace SixLabors.ImageSharp.ColorSpaces.Conversion; - -/// -/// Converts from to . -/// -internal static class CieLabToCieLchConverter -{ - /// - /// Performs the conversion from the input to an instance of type. - /// - /// The input color instance. - /// The converted result - [MethodImpl(InliningOptions.ShortMethod)] - public static CieLch Convert(in CieLab input) - { - // Conversion algorithm described here: - // https://en.wikipedia.org/wiki/Lab_color_space#Cylindrical_representation:_CIELCh_or_CIEHLC - float l = input.L, a = input.A, b = input.B; - float c = MathF.Sqrt((a * a) + (b * b)); - float hRadians = MathF.Atan2(b, a); - float hDegrees = GeometryUtilities.RadianToDegree(hRadians); - - // Wrap the angle round at 360. - hDegrees %= 360; - - // Make sure it's not negative. - while (hDegrees < 0) - { - hDegrees += 360; - } - - return new CieLch(l, c, hDegrees, input.WhitePoint); - } -} diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieLabToCieXyzConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieLabToCieXyzConverter.cs deleted file mode 100644 index b02ad0000b..0000000000 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieLabToCieXyzConverter.cs +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using System.Numerics; -using System.Runtime.CompilerServices; - -namespace SixLabors.ImageSharp.ColorSpaces.Conversion; - -/// -/// Converts from to . -/// -internal static class CieLabToCieXyzConverter -{ - /// - /// Performs the conversion from the input to an instance of type. - /// - /// The input color instance. - /// The converted result - [MethodImpl(InliningOptions.ShortMethod)] - public static CieXyz Convert(in CieLab input) - { - // Conversion algorithm described here: http://www.brucelindbloom.com/index.html?Eqn_Lab_to_XYZ.html - float l = input.L, a = input.A, b = input.B; - float fy = (l + 16) / 116F; - float fx = (a / 500F) + fy; - float fz = fy - (b / 200F); - - float fx3 = Numerics.Pow3(fx); - float fz3 = Numerics.Pow3(fz); - - float xr = fx3 > CieConstants.Epsilon ? fx3 : ((116F * fx) - 16F) / CieConstants.Kappa; - float yr = l > CieConstants.Kappa * CieConstants.Epsilon ? Numerics.Pow3((l + 16F) / 116F) : l / CieConstants.Kappa; - float zr = fz3 > CieConstants.Epsilon ? fz3 : ((116F * fz) - 16F) / CieConstants.Kappa; - - Vector3 wxyz = new(input.WhitePoint.X, input.WhitePoint.Y, input.WhitePoint.Z); - - // Avoids XYZ coordinates out range (restricted by 0 and XYZ reference white) - Vector3 xyzr = Vector3.Clamp(new Vector3(xr, yr, zr), Vector3.Zero, Vector3.One); - - Vector3 xyz = xyzr * wxyz; - return new CieXyz(xyz); - } -} diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieLchuvToCieLuvConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieLchuvToCieLuvConverter.cs deleted file mode 100644 index 9a1e79da48..0000000000 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieLchuvToCieLuvConverter.cs +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using System.Runtime.CompilerServices; - -namespace SixLabors.ImageSharp.ColorSpaces.Conversion; - -/// -/// Converts from to . -/// -internal static class CieLchuvToCieLuvConverter -{ - /// - /// Performs the conversion from the input to an instance of type. - /// - /// The input color instance. - /// The converted result - [MethodImpl(InliningOptions.ShortMethod)] - public static CieLuv Convert(in CieLchuv input) - { - // Conversion algorithm described here: - // https://en.wikipedia.org/wiki/CIELUV#Cylindrical_representation_.28CIELCH.29 - float l = input.L, c = input.C, hDegrees = input.H; - float hRadians = GeometryUtilities.DegreeToRadian(hDegrees); - - float u = c * MathF.Cos(hRadians); - float v = c * MathF.Sin(hRadians); - - return new CieLuv(l, u, v, input.WhitePoint); - } -} diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieLuvToCieLchuvConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieLuvToCieLchuvConverter.cs deleted file mode 100644 index 4756bab825..0000000000 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieLuvToCieLchuvConverter.cs +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using System.Runtime.CompilerServices; - -namespace SixLabors.ImageSharp.ColorSpaces.Conversion; - -/// -/// Converts from to . -/// -internal static class CieLuvToCieLchuvConverter -{ - /// - /// Performs the conversion from the input to an instance of type. - /// - /// The input color instance. - /// The converted result - [MethodImpl(InliningOptions.ShortMethod)] - public static CieLchuv Convert(in CieLuv input) - { - // Conversion algorithm described here: - // https://en.wikipedia.org/wiki/CIELUV#Cylindrical_representation_.28CIELCH.29 - float l = input.L, a = input.U, b = input.V; - float c = MathF.Sqrt((a * a) + (b * b)); - float hRadians = MathF.Atan2(b, a); - float hDegrees = GeometryUtilities.RadianToDegree(hRadians); - - // Wrap the angle round at 360. - hDegrees %= 360; - - // Make sure it's not negative. - while (hDegrees < 0) - { - hDegrees += 360; - } - - return new CieLchuv(l, c, hDegrees, input.WhitePoint); - } -} diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieLuvToCieXyzConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieLuvToCieXyzConverter.cs deleted file mode 100644 index 404c4e824d..0000000000 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieLuvToCieXyzConverter.cs +++ /dev/null @@ -1,73 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using System.Runtime.CompilerServices; - -namespace SixLabors.ImageSharp.ColorSpaces.Conversion; - -/// -/// Converts from to . -/// -internal static class CieLuvToCieXyzConverter -{ - /// - /// Performs the conversion from the input to an instance of type. - /// - /// The input color instance. - /// The converted result - public static CieXyz Convert(in CieLuv input) - { - // Conversion algorithm described here: http://www.brucelindbloom.com/index.html?Eqn_Luv_to_XYZ.html - float l = input.L, u = input.U, v = input.V; - - float u0 = ComputeU0(input.WhitePoint); - float v0 = ComputeV0(input.WhitePoint); - - float y = l > CieConstants.Kappa * CieConstants.Epsilon - ? Numerics.Pow3((l + 16) / 116) - : l / CieConstants.Kappa; - - float a = ((52 * l / (u + (13 * l * u0))) - 1) / 3; - float b = -5 * y; - const float c = -0.3333333F; - float d = y * ((39 * l / (v + (13 * l * v0))) - 5); - - float x = (d - b) / (a - c); - float z = (x * a) + b; - - if (float.IsNaN(x) || x < 0) - { - x = 0; - } - - if (float.IsNaN(y) || y < 0) - { - y = 0; - } - - if (float.IsNaN(z) || z < 0) - { - z = 0; - } - - return new CieXyz(x, y, z); - } - - /// - /// Calculates the blue-yellow chromacity based on the given whitepoint. - /// - /// The whitepoint - /// The - [MethodImpl(InliningOptions.ShortMethod)] - private static float ComputeU0(in CieXyz input) - => (4 * input.X) / (input.X + (15 * input.Y) + (3 * input.Z)); - - /// - /// Calculates the red-green chromacity based on the given whitepoint. - /// - /// The whitepoint - /// The - [MethodImpl(InliningOptions.ShortMethod)] - private static float ComputeV0(in CieXyz input) - => (9 * input.Y) / (input.X + (15 * input.Y) + (3 * input.Z)); -} diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzAndCieXyyConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzAndCieXyyConverter.cs deleted file mode 100644 index 4cc443cf7b..0000000000 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzAndCieXyyConverter.cs +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using System.Runtime.CompilerServices; - -namespace SixLabors.ImageSharp.ColorSpaces.Conversion; - -/// -/// Color converter between CIE XYZ and CIE xyY. -/// for formulas. -/// -internal static class CieXyzAndCieXyyConverter -{ - /// - /// Performs the conversion from the input to an instance of type. - /// - /// The input color instance. - /// The converted result - [MethodImpl(InliningOptions.ShortMethod)] - public static CieXyy Convert(in CieXyz input) - { - float x = input.X / (input.X + input.Y + input.Z); - float y = input.Y / (input.X + input.Y + input.Z); - - if (float.IsNaN(x) || float.IsNaN(y)) - { - return new CieXyy(0, 0, input.Y); - } - - return new CieXyy(x, y, input.Y); - } - - /// - /// Performs the conversion from the input to an instance of type. - /// - /// The input color instance. - /// The converted result - [MethodImpl(InliningOptions.ShortMethod)] - public static CieXyz Convert(in CieXyy input) - { - if (MathF.Abs(input.Y) < Constants.Epsilon) - { - return new CieXyz(0, 0, input.Yl); - } - - float x = (input.X * input.Yl) / input.Y; - float y = input.Yl; - float z = ((1 - input.X - input.Y) * y) / input.Y; - - return new CieXyz(x, y, z); - } -} diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzAndHunterLabConverterBase.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzAndHunterLabConverterBase.cs deleted file mode 100644 index ba221108fb..0000000000 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzAndHunterLabConverterBase.cs +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using System.Runtime.CompilerServices; - -namespace SixLabors.ImageSharp.ColorSpaces.Conversion; - -/// -/// The base class for converting between and color spaces. -/// -internal abstract class CieXyzAndHunterLabConverterBase -{ - /// - /// Returns the Ka coefficient that depends upon the whitepoint illuminant. - /// - /// The whitepoint - /// The - [MethodImpl(InliningOptions.ShortMethod)] - public static float ComputeKa(CieXyz whitePoint) - { - if (whitePoint.Equals(Illuminants.C)) - { - return 175F; - } - - return 100F * (175F / 198.04F) * (whitePoint.X + whitePoint.Y); - } - - /// - /// Returns the Kb coefficient that depends upon the whitepoint illuminant. - /// - /// The whitepoint - /// The - [MethodImpl(InliningOptions.ShortMethod)] - public static float ComputeKb(CieXyz whitePoint) - { - if (whitePoint == Illuminants.C) - { - return 70F; - } - - return 100F * (70F / 218.11F) * (whitePoint.Y + whitePoint.Z); - } -} diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzAndLmsConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzAndLmsConverter.cs deleted file mode 100644 index b5f8a70b6f..0000000000 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzAndLmsConverter.cs +++ /dev/null @@ -1,69 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using System.Numerics; -using System.Runtime.CompilerServices; - -namespace SixLabors.ImageSharp.ColorSpaces.Conversion; - -/// -/// Color converter between and -/// -internal sealed class CieXyzAndLmsConverter -{ - /// - /// Default transformation matrix used, when no other is set. (Bradford) - /// - /// - public static readonly Matrix4x4 DefaultTransformationMatrix = LmsAdaptationMatrix.Bradford; - - private Matrix4x4 inverseTransformationMatrix; - private Matrix4x4 transformationMatrix; - - /// - /// Initializes a new instance of the class. - /// - public CieXyzAndLmsConverter() - : this(DefaultTransformationMatrix) - { - } - - /// - /// Initializes a new instance of the class. - /// - /// - /// Definition of the cone response domain (see ), - /// if not set will be used. - /// - public CieXyzAndLmsConverter(Matrix4x4 transformationMatrix) - { - this.transformationMatrix = transformationMatrix; - Matrix4x4.Invert(this.transformationMatrix, out this.inverseTransformationMatrix); - } - - /// - /// Performs the conversion from the input to an instance of type. - /// - /// The input color instance. - /// The converted result - [MethodImpl(InliningOptions.ShortMethod)] - public Lms Convert(in CieXyz input) - { - Vector3 vector = Vector3.Transform(input.ToVector3(), this.transformationMatrix); - - return new Lms(vector); - } - - /// - /// Performs the conversion from the input to an instance of type. - /// - /// The input color instance. - /// The converted result - [MethodImpl(InliningOptions.ShortMethod)] - public CieXyz Convert(in Lms input) - { - Vector3 vector = Vector3.Transform(input.ToVector3(), this.inverseTransformationMatrix); - - return new CieXyz(vector); - } -} diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzToCieLabConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzToCieLabConverter.cs deleted file mode 100644 index 0ce6e3c9ff..0000000000 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzToCieLabConverter.cs +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using System.Runtime.CompilerServices; - -namespace SixLabors.ImageSharp.ColorSpaces.Conversion; - -/// -/// Converts from to . -/// -internal sealed class CieXyzToCieLabConverter -{ - /// - /// Initializes a new instance of the class. - /// - public CieXyzToCieLabConverter() - : this(CieLab.DefaultWhitePoint) - { - } - - /// - /// Initializes a new instance of the class. - /// - /// The target reference lab white point - public CieXyzToCieLabConverter(CieXyz labWhitePoint) => this.LabWhitePoint = labWhitePoint; - - /// - /// Gets the target reference whitepoint. When not set, is used. - /// - public CieXyz LabWhitePoint { get; } - - /// - /// Performs the conversion from the input to an instance of type. - /// - /// The input color instance. - /// The converted result - [MethodImpl(InliningOptions.ShortMethod)] - public CieLab Convert(in CieXyz input) - { - // Conversion algorithm described here: http://www.brucelindbloom.com/index.html?Eqn_XYZ_to_Lab.html - float wx = this.LabWhitePoint.X, wy = this.LabWhitePoint.Y, wz = this.LabWhitePoint.Z; - - float xr = input.X / wx, yr = input.Y / wy, zr = input.Z / wz; - - const float inv116 = 1 / 116F; - - float fx = xr > CieConstants.Epsilon ? MathF.Pow(xr, 0.3333333F) : ((CieConstants.Kappa * xr) + 16F) * inv116; - float fy = yr > CieConstants.Epsilon ? MathF.Pow(yr, 0.3333333F) : ((CieConstants.Kappa * yr) + 16F) * inv116; - float fz = zr > CieConstants.Epsilon ? MathF.Pow(zr, 0.3333333F) : ((CieConstants.Kappa * zr) + 16F) * inv116; - - float l = (116F * fy) - 16F; - float a = 500F * (fx - fy); - float b = 200F * (fy - fz); - - return new CieLab(l, a, b, this.LabWhitePoint); - } -} diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzToCieLuvConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzToCieLuvConverter.cs deleted file mode 100644 index 1e17ae54f0..0000000000 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzToCieLuvConverter.cs +++ /dev/null @@ -1,86 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using System.Runtime.CompilerServices; - -namespace SixLabors.ImageSharp.ColorSpaces.Conversion; - -/// -/// Converts from to . -/// -internal sealed class CieXyzToCieLuvConverter -{ - /// - /// Initializes a new instance of the class. - /// - public CieXyzToCieLuvConverter() - : this(CieLuv.DefaultWhitePoint) - { - } - - /// - /// Initializes a new instance of the class. - /// - /// The target reference luv white point - public CieXyzToCieLuvConverter(CieXyz luvWhitePoint) => this.LuvWhitePoint = luvWhitePoint; - - /// - /// Gets the target reference whitepoint. When not set, is used. - /// - public CieXyz LuvWhitePoint { get; } - - /// - /// Performs the conversion from the input to an instance of type. - /// - /// The input color instance. - /// The converted result - public CieLuv Convert(in CieXyz input) - { - // Conversion algorithm described here: http://www.brucelindbloom.com/index.html?Eqn_XYZ_to_Luv.html - float yr = input.Y / this.LuvWhitePoint.Y; - float up = ComputeUp(input); - float vp = ComputeVp(input); - float upr = ComputeUp(this.LuvWhitePoint); - float vpr = ComputeVp(this.LuvWhitePoint); - - float l = yr > CieConstants.Epsilon ? ((116 * MathF.Pow(yr, 0.3333333F)) - 16F) : (CieConstants.Kappa * yr); - - if (float.IsNaN(l) || l < 0) - { - l = 0; - } - - float u = 13 * l * (up - upr); - float v = 13 * l * (vp - vpr); - - if (float.IsNaN(u)) - { - u = 0; - } - - if (float.IsNaN(v)) - { - v = 0; - } - - return new CieLuv(l, u, v, this.LuvWhitePoint); - } - - /// - /// Calculates the blue-yellow chromacity based on the given whitepoint. - /// - /// The whitepoint - /// The - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static float ComputeUp(in CieXyz input) - => (4 * input.X) / (input.X + (15 * input.Y) + (3 * input.Z)); - - /// - /// Calculates the red-green chromacity based on the given whitepoint. - /// - /// The whitepoint - /// The - [MethodImpl(InliningOptions.ShortMethod)] - private static float ComputeVp(in CieXyz input) - => (9 * input.Y) / (input.X + (15 * input.Y) + (3 * input.Z)); -} diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzToHunterLabConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzToHunterLabConverter.cs deleted file mode 100644 index dab953a749..0000000000 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzToHunterLabConverter.cs +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using System.Runtime.CompilerServices; - -namespace SixLabors.ImageSharp.ColorSpaces.Conversion; - -/// -/// Color converter between and -/// -internal sealed class CieXyzToHunterLabConverter : CieXyzAndHunterLabConverterBase -{ - /// - /// Initializes a new instance of the class. - /// - public CieXyzToHunterLabConverter() - : this(HunterLab.DefaultWhitePoint) - { - } - - /// - /// Initializes a new instance of the class. - /// - /// The hunter Lab white point. - public CieXyzToHunterLabConverter(CieXyz labWhitePoint) => this.HunterLabWhitePoint = labWhitePoint; - - /// - /// Gets the target reference white. When not set, is used. - /// - public CieXyz HunterLabWhitePoint { get; } - - /// - /// Performs the conversion from the input to an instance of type. - /// - /// The input color instance. - /// The converted result - [MethodImpl(InliningOptions.ShortMethod)] - public HunterLab Convert(in CieXyz input) - { - // Conversion algorithm described here: http://en.wikipedia.org/wiki/Lab_color_space#Hunter_Lab - float x = input.X, y = input.Y, z = input.Z; - float xn = this.HunterLabWhitePoint.X, yn = this.HunterLabWhitePoint.Y, zn = this.HunterLabWhitePoint.Z; - - float ka = ComputeKa(this.HunterLabWhitePoint); - float kb = ComputeKb(this.HunterLabWhitePoint); - - float yByYn = y / yn; - float sqrtYbyYn = MathF.Sqrt(yByYn); - float l = 100 * sqrtYbyYn; - float a = ka * (((x / xn) - yByYn) / sqrtYbyYn); - float b = kb * ((yByYn - (z / zn)) / sqrtYbyYn); - - if (float.IsNaN(a)) - { - a = 0; - } - - if (float.IsNaN(b)) - { - b = 0; - } - - return new HunterLab(l, a, b, this.HunterLabWhitePoint); - } -} diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzToLinearRgbConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzToLinearRgbConverter.cs deleted file mode 100644 index 4d15cb5d56..0000000000 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzToLinearRgbConverter.cs +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using System.Numerics; -using System.Runtime.CompilerServices; - -namespace SixLabors.ImageSharp.ColorSpaces.Conversion; - -/// -/// Color converter between and -/// -internal sealed class CieXyzToLinearRgbConverter : LinearRgbAndCieXyzConverterBase -{ - private readonly Matrix4x4 conversionMatrix; - - /// - /// Initializes a new instance of the class. - /// - public CieXyzToLinearRgbConverter() - : this(Rgb.DefaultWorkingSpace) - { - } - - /// - /// Initializes a new instance of the class. - /// - /// The target working space. - public CieXyzToLinearRgbConverter(RgbWorkingSpace workingSpace) - { - this.TargetWorkingSpace = workingSpace; - - // Gets the inverted Rgb -> Xyz matrix - Matrix4x4.Invert(GetRgbToCieXyzMatrix(workingSpace), out Matrix4x4 inverted); - - this.conversionMatrix = inverted; - } - - /// - /// Gets the target working space. - /// - public RgbWorkingSpace TargetWorkingSpace { get; } - - /// - /// Performs the conversion from the input to an instance of type. - /// - /// The input color instance. - /// The converted result. - [MethodImpl(InliningOptions.ShortMethod)] - public LinearRgb Convert(in CieXyz input) - { - var vector = Vector3.Transform(input.ToVector3(), this.conversionMatrix); - - return new LinearRgb(vector, this.TargetWorkingSpace); - } -} diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CmykAndRgbConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CmykAndRgbConverter.cs deleted file mode 100644 index 07ca1c7e46..0000000000 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CmykAndRgbConverter.cs +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using System.Numerics; -using System.Runtime.CompilerServices; - -namespace SixLabors.ImageSharp.ColorSpaces.Conversion; - -/// -/// Color converter between and . -/// -internal static class CmykAndRgbConverter -{ - /// - /// Performs the conversion from the input to an instance of type. - /// - /// The input color instance. - /// The converted result - [MethodImpl(InliningOptions.ShortMethod)] - public static Rgb Convert(in Cmyk input) - { - Vector3 rgb = (Vector3.One - new Vector3(input.C, input.M, input.Y)) * (Vector3.One - new Vector3(input.K)); - return new Rgb(rgb); - } - - /// - /// Performs the conversion from the input to an instance of type. - /// - /// The input color instance. - /// The converted result. - [MethodImpl(InliningOptions.ShortMethod)] - public static Cmyk Convert(in Rgb input) - { - // To CMY - Vector3 cmy = Vector3.One - input.ToVector3(); - - // To CMYK - Vector3 k = new(MathF.Min(cmy.X, MathF.Min(cmy.Y, cmy.Z))); - - if (MathF.Abs(k.X - 1F) < Constants.Epsilon) - { - return new Cmyk(0, 0, 0, 1F); - } - - cmy = (cmy - k) / (Vector3.One - k); - - return new Cmyk(cmy.X, cmy.Y, cmy.Z, k.X); - } -} diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/HslAndRgbConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/HslAndRgbConverter.cs deleted file mode 100644 index 24aecc3c45..0000000000 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/HslAndRgbConverter.cs +++ /dev/null @@ -1,158 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using System.Runtime.CompilerServices; - -namespace SixLabors.ImageSharp.ColorSpaces.Conversion; - -/// -/// Color converter between HSL and Rgb -/// See for formulas. -/// -internal static class HslAndRgbConverter -{ - /// - /// Performs the conversion from the input to an instance of type. - /// - /// The input color instance. - /// The converted result - [MethodImpl(InliningOptions.ShortMethod)] - public static Rgb Convert(in Hsl input) - { - float rangedH = input.H / 360F; - float r = 0; - float g = 0; - float b = 0; - float s = input.S; - float l = input.L; - - if (MathF.Abs(l) > Constants.Epsilon) - { - if (MathF.Abs(s) < Constants.Epsilon) - { - r = g = b = l; - } - else - { - float temp2 = (l < .5F) ? l * (1F + s) : l + s - (l * s); - float temp1 = (2F * l) - temp2; - - r = GetColorComponent(temp1, temp2, rangedH + 0.3333333F); - g = GetColorComponent(temp1, temp2, rangedH); - b = GetColorComponent(temp1, temp2, rangedH - 0.3333333F); - } - } - - return new Rgb(r, g, b); - } - - /// - /// Performs the conversion from the input to an instance of type. - /// - /// The input color instance. - /// The converted result - [MethodImpl(InliningOptions.ShortMethod)] - public static Hsl Convert(in Rgb input) - { - float r = input.R; - float g = input.G; - float b = input.B; - - float max = MathF.Max(r, MathF.Max(g, b)); - float min = MathF.Min(r, MathF.Min(g, b)); - float chroma = max - min; - float h = 0F; - float s = 0F; - float l = (max + min) / 2F; - - if (MathF.Abs(chroma) < Constants.Epsilon) - { - return new Hsl(0F, s, l); - } - - if (MathF.Abs(r - max) < Constants.Epsilon) - { - h = (g - b) / chroma; - } - else if (MathF.Abs(g - max) < Constants.Epsilon) - { - h = 2F + ((b - r) / chroma); - } - else if (MathF.Abs(b - max) < Constants.Epsilon) - { - h = 4F + ((r - g) / chroma); - } - - h *= 60F; - if (h < 0F) - { - h += 360F; - } - - if (l <= .5F) - { - s = chroma / (max + min); - } - else - { - s = chroma / (2F - max - min); - } - - return new Hsl(h, s, l); - } - - /// - /// Gets the color component from the given values. - /// - /// The first value. - /// The second value. - /// The third value. - /// - /// The . - /// - [MethodImpl(InliningOptions.ShortMethod)] - private static float GetColorComponent(float first, float second, float third) - { - third = MoveIntoRange(third); - if (third < 0.1666667F) - { - return first + ((second - first) * 6F * third); - } - - if (third < .5F) - { - return second; - } - - if (third < 0.6666667F) - { - return first + ((second - first) * (0.6666667F - third) * 6F); - } - - return first; - } - - /// - /// Moves the specific value within the acceptable range for - /// conversion. - /// Used for converting colors to this type. - /// - /// The value to shift. - /// - /// The . - /// - [MethodImpl(InliningOptions.ShortMethod)] - private static float MoveIntoRange(float value) - { - if (value < 0F) - { - value++; - } - else if (value > 1F) - { - value--; - } - - return value; - } -} diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/HsvAndRgbConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/HsvAndRgbConverter.cs deleted file mode 100644 index 5273576175..0000000000 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/HsvAndRgbConverter.cs +++ /dev/null @@ -1,128 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using System.Runtime.CompilerServices; - -namespace SixLabors.ImageSharp.ColorSpaces.Conversion; - -/// -/// Color converter between HSV and Rgb -/// See for formulas. -/// -internal static class HsvAndRgbConverter -{ - /// - /// Performs the conversion from the input to an instance of type. - /// - /// The input color instance. - /// The converted result - [MethodImpl(InliningOptions.ShortMethod)] - public static Rgb Convert(in Hsv input) - { - float s = input.S; - float v = input.V; - - if (MathF.Abs(s) < Constants.Epsilon) - { - return new Rgb(v, v, v); - } - - float h = (MathF.Abs(input.H - 360) < Constants.Epsilon) ? 0 : input.H / 60; - int i = (int)Math.Truncate(h); - float f = h - i; - - float p = v * (1F - s); - float q = v * (1F - (s * f)); - float t = v * (1F - (s * (1F - f))); - - float r, g, b; - switch (i) - { - case 0: - r = v; - g = t; - b = p; - break; - - case 1: - r = q; - g = v; - b = p; - break; - - case 2: - r = p; - g = v; - b = t; - break; - - case 3: - r = p; - g = q; - b = v; - break; - - case 4: - r = t; - g = p; - b = v; - break; - - default: - r = v; - g = p; - b = q; - break; - } - - return new Rgb(r, g, b); - } - - /// - /// Performs the conversion from the input to an instance of type. - /// - /// The input color instance. - /// The converted result - [MethodImpl(InliningOptions.ShortMethod)] - public static Hsv Convert(in Rgb input) - { - float r = input.R; - float g = input.G; - float b = input.B; - - float max = MathF.Max(r, MathF.Max(g, b)); - float min = MathF.Min(r, MathF.Min(g, b)); - float chroma = max - min; - float h = 0; - float s = 0; - float v = max; - - if (MathF.Abs(chroma) < Constants.Epsilon) - { - return new Hsv(0, s, v); - } - - if (MathF.Abs(r - max) < Constants.Epsilon) - { - h = (g - b) / chroma; - } - else if (MathF.Abs(g - max) < Constants.Epsilon) - { - h = 2 + ((b - r) / chroma); - } - else if (MathF.Abs(b - max) < Constants.Epsilon) - { - h = 4 + ((r - g) / chroma); - } - - h *= 60; - if (h < 0.0) - { - h += 360; - } - - s = chroma / v; - - return new Hsv(h, s, v); - } -} diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/HunterLabToCieXyzConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/HunterLabToCieXyzConverter.cs deleted file mode 100644 index 3930e8dc2d..0000000000 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/HunterLabToCieXyzConverter.cs +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using System.Runtime.CompilerServices; - -namespace SixLabors.ImageSharp.ColorSpaces.Conversion; - -/// -/// Color converter between and -/// -internal sealed class HunterLabToCieXyzConverter : CieXyzAndHunterLabConverterBase -{ - /// - /// Performs the conversion from the input to an instance of type. - /// - /// The input color instance. - /// The converted result - [MethodImpl(InliningOptions.ShortMethod)] - public static CieXyz Convert(in HunterLab input) - { - // Conversion algorithm described here: http://en.wikipedia.org/wiki/Lab_color_space#Hunter_Lab - float l = input.L, a = input.A, b = input.B; - float xn = input.WhitePoint.X, yn = input.WhitePoint.Y, zn = input.WhitePoint.Z; - - float ka = ComputeKa(input.WhitePoint); - float kb = ComputeKb(input.WhitePoint); - - float pow = Numerics.Pow2(l / 100F); - float sqrtPow = MathF.Sqrt(pow); - float y = pow * yn; - - float x = (((a / ka) * sqrtPow) + pow) * xn; - float z = (((b / kb) * sqrtPow) - pow) * (-zn); - - return new CieXyz(x, y, z); - } -} diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/LinearRgbAndCieXyzConverterBase.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/LinearRgbAndCieXyzConverterBase.cs deleted file mode 100644 index 27391fc802..0000000000 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/LinearRgbAndCieXyzConverterBase.cs +++ /dev/null @@ -1,73 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using System.Numerics; - -namespace SixLabors.ImageSharp.ColorSpaces.Conversion; - -/// -/// Provides base methods for converting between and color spaces. -/// -internal abstract class LinearRgbAndCieXyzConverterBase -{ - /// - /// Returns the correct matrix to convert between the Rgb and CieXyz color space. - /// - /// The Rgb working space. - /// The based on the chromaticity and working space. - public static Matrix4x4 GetRgbToCieXyzMatrix(RgbWorkingSpace workingSpace) - { - DebugGuard.NotNull(workingSpace, nameof(workingSpace)); - RgbPrimariesChromaticityCoordinates chromaticity = workingSpace.ChromaticityCoordinates; - - float xr = chromaticity.R.X; - float xg = chromaticity.G.X; - float xb = chromaticity.B.X; - float yr = chromaticity.R.Y; - float yg = chromaticity.G.Y; - float yb = chromaticity.B.Y; - - float mXr = xr / yr; - float mZr = (1 - xr - yr) / yr; - - float mXg = xg / yg; - float mZg = (1 - xg - yg) / yg; - - float mXb = xb / yb; - float mZb = (1 - xb - yb) / yb; - - Matrix4x4 xyzMatrix = new() - { - M11 = mXr, - M21 = mXg, - M31 = mXb, - M12 = 1F, - M22 = 1F, - M32 = 1F, - M13 = mZr, - M23 = mZg, - M33 = mZb, - M44 = 1F - }; - - Matrix4x4.Invert(xyzMatrix, out Matrix4x4 inverseXyzMatrix); - - Vector3 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 * 1, - M22 = vector.Y * 1, - M32 = vector.Z * 1, - M13 = vector.X * mZr, - M23 = vector.Y * mZg, - M33 = vector.Z * mZb, - M44 = 1F - }; - } -} diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/LinearRgbToCieXyzConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/LinearRgbToCieXyzConverter.cs deleted file mode 100644 index 091cab9931..0000000000 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/LinearRgbToCieXyzConverter.cs +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using System.Numerics; -using System.Runtime.CompilerServices; - -namespace SixLabors.ImageSharp.ColorSpaces.Conversion; - -/// -/// Color converter between and -/// -internal sealed class LinearRgbToCieXyzConverter : LinearRgbAndCieXyzConverterBase -{ - private readonly Matrix4x4 conversionMatrix; - - /// - /// Initializes a new instance of the class. - /// - public LinearRgbToCieXyzConverter() - : this(Rgb.DefaultWorkingSpace) - { - } - - /// - /// Initializes a new instance of the class. - /// - /// The target working space. - public LinearRgbToCieXyzConverter(RgbWorkingSpace workingSpace) - { - this.SourceWorkingSpace = workingSpace; - this.conversionMatrix = GetRgbToCieXyzMatrix(workingSpace); - } - - /// - /// Gets the source working space - /// - public RgbWorkingSpace SourceWorkingSpace { get; } - - /// - /// Performs the conversion from the input to an instance of type. - /// - /// The input color instance. - /// The converted result - [MethodImpl(InliningOptions.ShortMethod)] - public CieXyz Convert(in LinearRgb input) - { - DebugGuard.IsTrue(input.WorkingSpace.Equals(this.SourceWorkingSpace), nameof(input.WorkingSpace), "Input and source working spaces must be equal."); - - Vector3 vector = Vector3.Transform(input.ToVector3(), this.conversionMatrix); - return new CieXyz(vector); - } -} diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/LinearRgbToRgbConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/LinearRgbToRgbConverter.cs deleted file mode 100644 index d41e7f74da..0000000000 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/LinearRgbToRgbConverter.cs +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using System.Runtime.CompilerServices; - -namespace SixLabors.ImageSharp.ColorSpaces.Conversion; - -/// -/// Color converter between and . -/// -internal static class LinearRgbToRgbConverter -{ - /// - /// Performs the conversion from the input to an instance of type. - /// - /// The input color instance. - /// The converted result. - [MethodImpl(InliningOptions.ShortMethod)] - public static Rgb Convert(in LinearRgb input) => - new( - r: input.WorkingSpace.Compress(input.R), - g: input.WorkingSpace.Compress(input.G), - b: input.WorkingSpace.Compress(input.B), - workingSpace: input.WorkingSpace); -} diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/RgbToLinearRgbConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/RgbToLinearRgbConverter.cs deleted file mode 100644 index c63bbae3da..0000000000 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/RgbToLinearRgbConverter.cs +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using System.Runtime.CompilerServices; - -namespace SixLabors.ImageSharp.ColorSpaces.Conversion; - -/// -/// Color converter between Rgb and LinearRgb. -/// -internal static class RgbToLinearRgbConverter -{ - /// - /// Performs the conversion from the input to an instance of type. - /// - /// The input color instance. - /// The converted result. - [MethodImpl(InliningOptions.ShortMethod)] - public static LinearRgb Convert(in Rgb input) - => new( - r: input.WorkingSpace.Expand(input.R), - g: input.WorkingSpace.Expand(input.G), - b: input.WorkingSpace.Expand(input.B), - workingSpace: input.WorkingSpace); -} diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/YCbCrAndRgbConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/YCbCrAndRgbConverter.cs deleted file mode 100644 index eda55ec4c5..0000000000 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/YCbCrAndRgbConverter.cs +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using System.Numerics; -using System.Runtime.CompilerServices; - -namespace SixLabors.ImageSharp.ColorSpaces.Conversion; - -/// -/// Color converter between and -/// See for formulas. -/// -internal static class YCbCrAndRgbConverter -{ - private static readonly Vector3 MaxBytes = new(255F); - - /// - /// Performs the conversion from the input to an instance of type. - /// - /// The input color instance. - /// The converted result. - [MethodImpl(InliningOptions.ShortMethod)] - public static Rgb Convert(in YCbCr input) - { - float y = input.Y; - float cb = input.Cb - 128F; - float cr = input.Cr - 128F; - - float r = MathF.Round(y + (1.402F * cr), MidpointRounding.AwayFromZero); - float g = MathF.Round(y - (0.344136F * cb) - (0.714136F * cr), MidpointRounding.AwayFromZero); - float b = MathF.Round(y + (1.772F * cb), MidpointRounding.AwayFromZero); - - return new Rgb(new Vector3(r, g, b) / MaxBytes); - } - - /// - /// Performs the conversion from the input to an instance of type. - /// - /// The input color instance. - /// The converted result. - [MethodImpl(InliningOptions.ShortMethod)] - public static YCbCr Convert(in Rgb input) - { - Vector3 rgb = input.ToVector3() * MaxBytes; - float r = rgb.X; - float g = rgb.Y; - float b = rgb.Z; - - float y = (0.299F * r) + (0.587F * g) + (0.114F * b); - float cb = 128F + ((-0.168736F * r) - (0.331264F * g) + (0.5F * b)); - float cr = 128F + ((0.5F * r) - (0.418688F * g) - (0.081312F * b)); - - return new YCbCr(y, cb, cr); - } -} diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/IChromaticAdaptation.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/IChromaticAdaptation.cs deleted file mode 100644 index 3b6abb041e..0000000000 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/IChromaticAdaptation.cs +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -namespace SixLabors.ImageSharp.ColorSpaces.Conversion; - -/// -/// Chromatic adaptation. -/// A linear transformation of a source color (XS, YS, ZS) into a destination color (XD, YD, ZD) by a linear transformation [M] -/// which is dependent on the source reference white (XWS, YWS, ZWS) and the destination reference white (XWD, YWD, ZWD). -/// -public interface IChromaticAdaptation -{ - /// - /// Performs a linear transformation of a source color in to the destination color. - /// - /// Doesn't crop the resulting color space coordinates (e. g. allows negative values for XYZ coordinates). - /// The source color. - /// The source white point. - /// The destination white point. - /// The - CieXyz Transform(in CieXyz source, in CieXyz sourceWhitePoint, in CieXyz destinationWhitePoint); - - /// - /// Performs a bulk linear transformation of a source color in to the destination color. - /// - /// Doesn't crop the resulting color space coordinates (e. g. allows negative values for XYZ coordinates). - /// The span to the source colors. - /// The span to the destination colors. - /// The source white point. - /// The destination white point. - void Transform( - ReadOnlySpan source, - Span destination, - CieXyz sourceWhitePoint, - in CieXyz destinationWhitePoint); -} diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/VonKriesChromaticAdaptation.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/VonKriesChromaticAdaptation.cs deleted file mode 100644 index 97e9cee813..0000000000 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/VonKriesChromaticAdaptation.cs +++ /dev/null @@ -1,99 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using System.Numerics; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -namespace SixLabors.ImageSharp.ColorSpaces.Conversion; - -/// -/// Implementation of the von Kries chromatic adaptation model. -/// -/// -/// Transformation described here: -/// http://www.brucelindbloom.com/index.html?Eqn_ChromAdapt.html -/// -public sealed class VonKriesChromaticAdaptation : IChromaticAdaptation -{ - private readonly CieXyzAndLmsConverter converter; - - /// - /// Initializes a new instance of the class. - /// - public VonKriesChromaticAdaptation() - : this(new CieXyzAndLmsConverter()) - { - } - - /// - /// Initializes a new instance of the class. - /// - /// - /// The transformation matrix used for the conversion (definition of the cone response domain). - /// - /// - public VonKriesChromaticAdaptation(Matrix4x4 transformationMatrix) - : this(new CieXyzAndLmsConverter(transformationMatrix)) - { - } - - /// - /// Initializes a new instance of the class. - /// - /// The color converter - internal VonKriesChromaticAdaptation(CieXyzAndLmsConverter converter) => this.converter = converter; - - /// - public CieXyz Transform(in CieXyz source, in CieXyz sourceWhitePoint, in CieXyz destinationWhitePoint) - { - if (sourceWhitePoint.Equals(destinationWhitePoint)) - { - return source; - } - - Lms sourceColorLms = this.converter.Convert(source); - Lms sourceWhitePointLms = this.converter.Convert(sourceWhitePoint); - Lms targetWhitePointLms = this.converter.Convert(destinationWhitePoint); - - Vector3 vector = targetWhitePointLms.ToVector3() / sourceWhitePointLms.ToVector3(); - var targetColorLms = new Lms(Vector3.Multiply(vector, sourceColorLms.ToVector3())); - - return this.converter.Convert(targetColorLms); - } - - /// - public void Transform( - ReadOnlySpan source, - Span destination, - CieXyz sourceWhitePoint, - in CieXyz destinationWhitePoint) - { - Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = source.Length; - - if (sourceWhitePoint.Equals(destinationWhitePoint)) - { - source.CopyTo(destination[..count]); - return; - } - - ref CieXyz sourceRef = ref MemoryMarshal.GetReference(source); - ref CieXyz destRef = ref MemoryMarshal.GetReference(destination); - - for (nuint i = 0; i < (uint)count; i++) - { - ref CieXyz sp = ref Unsafe.Add(ref sourceRef, i); - ref CieXyz dp = ref Unsafe.Add(ref destRef, i); - - Lms sourceColorLms = this.converter.Convert(sp); - Lms sourceWhitePointLms = this.converter.Convert(sourceWhitePoint); - Lms targetWhitePointLms = this.converter.Convert(destinationWhitePoint); - - Vector3 vector = targetWhitePointLms.ToVector3() / sourceWhitePointLms.ToVector3(); - var targetColorLms = new Lms(Vector3.Multiply(vector, sourceColorLms.ToVector3())); - - dp = this.converter.Convert(targetColorLms); - } - } -} diff --git a/src/ImageSharp/ColorSpaces/Hsl.cs b/src/ImageSharp/ColorSpaces/Hsl.cs deleted file mode 100644 index cf18c70c78..0000000000 --- a/src/ImageSharp/ColorSpaces/Hsl.cs +++ /dev/null @@ -1,100 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using System.Numerics; -using System.Runtime.CompilerServices; - -namespace SixLabors.ImageSharp.ColorSpaces; - -/// -/// Represents a Hsl (hue, saturation, lightness) color. -/// -public readonly struct Hsl : IEquatable -{ - private static readonly Vector3 Min = Vector3.Zero; - private static readonly Vector3 Max = new(360, 1, 1); - - /// - /// Initializes a new instance of the struct. - /// - /// The h hue component. - /// The s saturation component. - /// The l value (lightness) component. - [MethodImpl(InliningOptions.ShortMethod)] - public Hsl(float h, float s, float l) - : this(new Vector3(h, s, l)) - { - } - - /// - /// Initializes a new instance of the struct. - /// - /// The vector representing the h, s, l components. - [MethodImpl(InliningOptions.ShortMethod)] - public Hsl(Vector3 vector) - { - vector = Vector3.Clamp(vector, Min, Max); - this.H = vector.X; - this.S = vector.Y; - this.L = vector.Z; - } - - /// - /// Gets the hue component. - /// A value ranging between 0 and 360. - /// - public readonly float H { get; } - - /// - /// Gets the saturation component. - /// A value ranging between 0 and 1. - /// - public readonly float S { get; } - - /// - /// Gets the lightness component. - /// A value ranging between 0 and 1. - /// - public readonly float L { get; } - - /// - /// Compares two objects for equality. - /// - /// - /// 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(InliningOptions.ShortMethod)] - 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. - /// - /// True if the current left is unequal to the parameter; otherwise, false. - /// - [MethodImpl(InliningOptions.ShortMethod)] - public static bool operator !=(Hsl left, Hsl right) => !left.Equals(right); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public override int GetHashCode() => HashCode.Combine(this.H, this.S, this.L); - - /// - public override string ToString() => FormattableString.Invariant($"Hsl({this.H:#0.##}, {this.S:#0.##}, {this.L:#0.##})"); - - /// - public override bool Equals(object? obj) => obj is Hsl other && this.Equals(other); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public bool Equals(Hsl other) - => this.H.Equals(other.H) - && this.S.Equals(other.S) - && this.L.Equals(other.L); -} diff --git a/src/ImageSharp/ColorSpaces/Hsv.cs b/src/ImageSharp/ColorSpaces/Hsv.cs deleted file mode 100644 index 87c16c0b6a..0000000000 --- a/src/ImageSharp/ColorSpaces/Hsv.cs +++ /dev/null @@ -1,98 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using System.Numerics; -using System.Runtime.CompilerServices; - -namespace SixLabors.ImageSharp.ColorSpaces; - -/// -/// Represents a HSV (hue, saturation, value) color. Also known as HSB (hue, saturation, brightness). -/// -public readonly struct Hsv : IEquatable -{ - private static readonly Vector3 Min = Vector3.Zero; - private static readonly Vector3 Max = new(360, 1, 1); - - /// - /// Initializes a new instance of the struct. - /// - /// The h hue component. - /// The s saturation component. - /// The v value (brightness) component. - [MethodImpl(InliningOptions.ShortMethod)] - public Hsv(float h, float s, float v) - : this(new Vector3(h, s, v)) - { - } - - /// - /// Initializes a new instance of the struct. - /// - /// The vector representing the h, s, v components. - [MethodImpl(InliningOptions.ShortMethod)] - public Hsv(Vector3 vector) - { - vector = Vector3.Clamp(vector, Min, Max); - this.H = vector.X; - this.S = vector.Y; - this.V = vector.Z; - } - - /// - /// Gets the hue component. - /// A value ranging between 0 and 360. - /// - public readonly float H { get; } - - /// - /// Gets the saturation component. - /// A value ranging between 0 and 1. - /// - public readonly float S { get; } - - /// - /// Gets the value (brightness) component. - /// A value ranging between 0 and 1. - /// - public readonly float V { get; } - - /// - /// Compares two objects for equality. - /// - /// 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(InliningOptions.ShortMethod)] - 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. - /// - /// True if the current left is unequal to the parameter; otherwise, false. - /// - [MethodImpl(InliningOptions.ShortMethod)] - public static bool operator !=(Hsv left, Hsv right) => !left.Equals(right); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public override int GetHashCode() => HashCode.Combine(this.H, this.S, this.V); - - /// - public override string ToString() => FormattableString.Invariant($"Hsv({this.H:#0.##}, {this.S:#0.##}, {this.V:#0.##})"); - - /// - public override bool Equals(object? obj) => obj is Hsv other && this.Equals(other); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public bool Equals(Hsv other) - => this.H.Equals(other.H) - && this.S.Equals(other.S) - && this.V.Equals(other.V); -} diff --git a/src/ImageSharp/ColorSpaces/HunterLab.cs b/src/ImageSharp/ColorSpaces/HunterLab.cs deleted file mode 100644 index 516574b098..0000000000 --- a/src/ImageSharp/ColorSpaces/HunterLab.cs +++ /dev/null @@ -1,134 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using System.Numerics; -using System.Runtime.CompilerServices; - -namespace SixLabors.ImageSharp.ColorSpaces; - -/// -/// Represents an Hunter LAB color. -/// . -/// -public readonly struct HunterLab : IEquatable -{ - /// - /// D50 standard illuminant. - /// Used when reference white is not specified explicitly. - /// - public static readonly CieXyz DefaultWhitePoint = Illuminants.C; - - /// - /// Initializes a new instance of the struct. - /// - /// The lightness dimension. - /// The a (green - magenta) component. - /// The b (blue - yellow) component. - /// Uses as white point. - [MethodImpl(InliningOptions.ShortMethod)] - public HunterLab(float l, float a, float b) - : this(new Vector3(l, a, b), DefaultWhitePoint) - { - } - - /// - /// Initializes a new instance of the struct. - /// - /// The lightness dimension. - /// The a (green - magenta) component. - /// The b (blue - yellow) component. - /// The reference white point. - [MethodImpl(InliningOptions.ShortMethod)] - public HunterLab(float l, float a, float b, CieXyz whitePoint) - : this(new Vector3(l, a, b), whitePoint) - { - } - - /// - /// Initializes a new instance of the struct. - /// - /// The vector representing the l, a, b components. - /// Uses as white point. - [MethodImpl(InliningOptions.ShortMethod)] - public HunterLab(Vector3 vector) - : this(vector, DefaultWhitePoint) - { - } - - /// - /// Initializes a new instance of the struct. - /// - /// The vector representing the l a b components. - /// The reference white point. - [MethodImpl(InliningOptions.ShortMethod)] - public HunterLab(Vector3 vector, CieXyz whitePoint) - { - // Not clamping as documentation about this space only indicates "usual" ranges - this.L = vector.X; - this.A = vector.Y; - this.B = vector.Z; - this.WhitePoint = whitePoint; - } - - /// - /// Gets the lightness dimension. - /// A value usually ranging between 0 (black), 100 (diffuse white) or higher (specular white). - /// - public readonly float L { get; } - - /// - /// Gets the a color component. - /// A value usually ranging from -100 to 100. Negative is green, positive magenta. - /// - public readonly float A { get; } - - /// - /// Gets the b color component. - /// A value usually ranging from -100 to 100. Negative is blue, positive is yellow - /// - public readonly float B { get; } - - /// - /// Gets the reference white point of this color. - /// - public readonly CieXyz WhitePoint { get; } - - /// - /// Compares two objects for equality. - /// - /// 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) => left.Equals(right); - - /// - /// Compares two objects for inequality - /// - /// 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(InliningOptions.ShortMethod)] - public static bool operator !=(HunterLab left, HunterLab right) => !left.Equals(right); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public override int GetHashCode() => HashCode.Combine(this.L, this.A, this.B, this.WhitePoint); - - /// - public override string ToString() => FormattableString.Invariant($"HunterLab({this.L:#0.##}, {this.A:#0.##}, {this.B:#0.##})"); - - /// - public override bool Equals(object? obj) => obj is HunterLab other && this.Equals(other); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public bool Equals(HunterLab other) - => this.L.Equals(other.L) - && this.A.Equals(other.A) - && this.B.Equals(other.B) - && this.WhitePoint.Equals(other.WhitePoint); -} diff --git a/src/ImageSharp/ColorSpaces/Illuminants.cs b/src/ImageSharp/ColorSpaces/Illuminants.cs deleted file mode 100644 index 7c25305c2c..0000000000 --- a/src/ImageSharp/ColorSpaces/Illuminants.cs +++ /dev/null @@ -1,71 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -namespace SixLabors.ImageSharp.ColorSpaces; - -/// -/// The well known standard illuminants. -/// Standard illuminants provide a basis for comparing images or colors recorded under different lighting -/// -/// -/// Coefficients taken from: http://www.brucelindbloom.com/index.html?Eqn_ChromAdapt.html -///
-/// Descriptions taken from: http://en.wikipedia.org/wiki/Standard_illuminant -///
-public static class Illuminants -{ - /// - /// Incandescent / Tungsten - /// - public static readonly CieXyz A = new CieXyz(1.09850F, 1F, 0.35585F); - - /// - /// Direct sunlight at noon (obsoleteF) - /// - public static readonly CieXyz B = new CieXyz(0.99072F, 1F, 0.85223F); - - /// - /// Average / North sky Daylight (obsoleteF) - /// - public static readonly CieXyz C = new CieXyz(0.98074F, 1F, 1.18232F); - - /// - /// Horizon Light. ICC profile PCS - /// - public static readonly CieXyz D50 = new CieXyz(0.96422F, 1F, 0.82521F); - - /// - /// Mid-morning / Mid-afternoon Daylight - /// - public static readonly CieXyz D55 = new CieXyz(0.95682F, 1F, 0.92149F); - - /// - /// Noon Daylight: TelevisionF, sRGB color space - /// - public static readonly CieXyz D65 = new CieXyz(0.95047F, 1F, 1.08883F); - - /// - /// North sky Daylight - /// - public static readonly CieXyz D75 = new CieXyz(0.94972F, 1F, 1.22638F); - - /// - /// Equal energy - /// - public static readonly CieXyz E = new CieXyz(1F, 1F, 1F); - - /// - /// Cool White Fluorescent - /// - public static readonly CieXyz F2 = new CieXyz(0.99186F, 1F, 0.67393F); - - /// - /// D65 simulatorF, Daylight simulator - /// - public static readonly CieXyz F7 = new CieXyz(0.95041F, 1F, 1.08747F); - - /// - /// Philips TL84F, Ultralume 40 - /// - public static readonly CieXyz F11 = new CieXyz(1.00962F, 1F, 0.64350F); -} diff --git a/src/ImageSharp/ColorSpaces/LinearRgb.cs b/src/ImageSharp/ColorSpaces/LinearRgb.cs deleted file mode 100644 index 49c7814a0e..0000000000 --- a/src/ImageSharp/ColorSpaces/LinearRgb.cs +++ /dev/null @@ -1,142 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using System.Numerics; -using System.Runtime.CompilerServices; -using SixLabors.ImageSharp.ColorSpaces.Conversion; - -namespace SixLabors.ImageSharp.ColorSpaces; - -/// -/// Represents an linear Rgb color with specified working space -/// -public readonly struct LinearRgb : IEquatable -{ - private static readonly Vector3 Min = Vector3.Zero; - private static readonly Vector3 Max = Vector3.One; - - /// - /// The default LinearRgb working space. - /// - public static readonly RgbWorkingSpace DefaultWorkingSpace = RgbWorkingSpaces.SRgb; - - /// - /// Initializes a new instance of the struct. - /// - /// The red component ranging between 0 and 1. - /// The green component ranging between 0 and 1. - /// The blue component ranging between 0 and 1. - [MethodImpl(InliningOptions.ShortMethod)] - public LinearRgb(float r, float g, float b) - : this(r, g, b, DefaultWorkingSpace) - { - } - - /// - /// Initializes a new instance of the struct. - /// - /// The red component ranging between 0 and 1. - /// The green component ranging between 0 and 1. - /// The blue component ranging between 0 and 1. - /// The rgb working space. - [MethodImpl(InliningOptions.ShortMethod)] - public LinearRgb(float r, float g, float b, RgbWorkingSpace workingSpace) - : this(new Vector3(r, g, b), workingSpace) - { - } - - /// - /// Initializes a new instance of the struct. - /// - /// The vector representing the r, g, b components. - [MethodImpl(InliningOptions.ShortMethod)] - public LinearRgb(Vector3 vector) - : this(vector, DefaultWorkingSpace) - { - } - - /// - /// Initializes a new instance of the struct. - /// - /// The vector representing the r, g, b components. - /// The LinearRgb working space. - [MethodImpl(InliningOptions.ShortMethod)] - public LinearRgb(Vector3 vector, RgbWorkingSpace workingSpace) - { - // Clamp to 0-1 range. - vector = Vector3.Clamp(vector, Min, Max); - 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 readonly float R { get; } - - /// - /// Gets the green component. - /// A value usually ranging between 0 and 1. - /// - public readonly float G { get; } - - /// - /// Gets the blue component. - /// A value usually ranging between 0 and 1. - /// - public readonly float B { get; } - - /// - /// Gets the LinearRgb color space - /// - public readonly RgbWorkingSpace WorkingSpace { get; } - - /// - /// Compares two objects for equality. - /// - /// 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(InliningOptions.ShortMethod)] - 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. - /// - /// True if the current left is unequal to the parameter; otherwise, false. - /// - [MethodImpl(InliningOptions.ShortMethod)] - public static bool operator !=(LinearRgb left, LinearRgb right) => !left.Equals(right); - - /// - /// Returns a new representing this instance. - /// - /// The . - [MethodImpl(InliningOptions.ShortMethod)] - public Vector3 ToVector3() => new(this.R, this.G, this.B); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public override int GetHashCode() => HashCode.Combine(this.R, this.G, this.B); - - /// - public override string ToString() => FormattableString.Invariant($"LinearRgb({this.R:#0.##}, {this.G:#0.##}, {this.B:#0.##})"); - - /// - public override bool Equals(object? obj) => obj is LinearRgb other && this.Equals(other); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public bool Equals(LinearRgb other) - => this.R.Equals(other.R) - && this.G.Equals(other.G) - && this.B.Equals(other.B); -} diff --git a/src/ImageSharp/ColorSpaces/Rgb.cs b/src/ImageSharp/ColorSpaces/Rgb.cs deleted file mode 100644 index 55052a710e..0000000000 --- a/src/ImageSharp/ColorSpaces/Rgb.cs +++ /dev/null @@ -1,163 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using System.Numerics; -using System.Runtime.CompilerServices; -using SixLabors.ImageSharp.ColorSpaces.Conversion; -using SixLabors.ImageSharp.PixelFormats; - -namespace SixLabors.ImageSharp.ColorSpaces; - -/// -/// Represents an RGB color with specified working space. -/// -public readonly struct Rgb : IEquatable -{ - /// - /// The default rgb working space. - /// - public static readonly RgbWorkingSpace DefaultWorkingSpace = RgbWorkingSpaces.SRgb; - - private static readonly Vector3 Min = Vector3.Zero; - private static readonly Vector3 Max = Vector3.One; - - /// - /// Initializes a new instance of the struct. - /// - /// The red component ranging between 0 and 1. - /// The green component ranging between 0 and 1. - /// The blue component ranging between 0 and 1. - [MethodImpl(InliningOptions.ShortMethod)] - public Rgb(float r, float g, float b) - : this(r, g, b, DefaultWorkingSpace) - { - } - - /// - /// Initializes a new instance of the struct. - /// - /// The red component ranging between 0 and 1. - /// The green component ranging between 0 and 1. - /// The blue component ranging between 0 and 1. - /// The rgb working space. - [MethodImpl(InliningOptions.ShortMethod)] - public Rgb(float r, float g, float b, RgbWorkingSpace workingSpace) - : this(new Vector3(r, g, b), workingSpace) - { - } - - /// - /// Initializes a new instance of the struct. - /// - /// The vector representing the r, g, b components. - [MethodImpl(InliningOptions.ShortMethod)] - public Rgb(Vector3 vector) - : this(vector, DefaultWorkingSpace) - { - } - - /// - /// Initializes a new instance of the struct. - /// - /// The vector representing the r, g, b components. - /// The rgb working space. - [MethodImpl(InliningOptions.ShortMethod)] - public Rgb(Vector3 vector, RgbWorkingSpace workingSpace) - { - vector = Vector3.Clamp(vector, Min, Max); - 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 readonly float R { get; } - - /// - /// Gets the green component. - /// A value usually ranging between 0 and 1. - /// - public readonly float G { get; } - - /// - /// Gets the blue component. - /// A value usually ranging between 0 and 1. - /// - public readonly float B { get; } - - /// - /// Gets the Rgb color space - /// - public readonly RgbWorkingSpace WorkingSpace { get; } - - /// - /// Allows the implicit conversion of an instance of to a - /// . - /// - /// The instance of to convert. - /// An instance of . - [MethodImpl(InliningOptions.ShortMethod)] - public static implicit operator Rgb(Rgb24 color) => new(color.R / 255F, color.G / 255F, color.B / 255F); - - /// - /// Allows the implicit conversion of an instance of to a - /// . - /// - /// The instance of to convert. - /// An instance of . - [MethodImpl(InliningOptions.ShortMethod)] - public static implicit operator Rgb(Rgba32 color) => new(color.R / 255F, color.G / 255F, color.B / 255F); - - /// - /// Compares two objects for equality. - /// - /// - /// 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(InliningOptions.ShortMethod)] - 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. - /// - /// True if the current left is unequal to the parameter; otherwise, false. - /// - [MethodImpl(InliningOptions.ShortMethod)] - public static bool operator !=(Rgb left, Rgb right) => !left.Equals(right); - - /// - /// Returns a new representing this instance. - /// - /// The . - [MethodImpl(InliningOptions.ShortMethod)] - public Vector3 ToVector3() => new(this.R, this.G, this.B); - - /// - 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(InliningOptions.ShortMethod)] - public bool Equals(Rgb other) - => this.R.Equals(other.R) - && this.G.Equals(other.G) - && this.B.Equals(other.B); -} diff --git a/src/ImageSharp/ColorSpaces/RgbWorkingSpaces.cs b/src/ImageSharp/ColorSpaces/RgbWorkingSpaces.cs deleted file mode 100644 index 53c8c2cf08..0000000000 --- a/src/ImageSharp/ColorSpaces/RgbWorkingSpaces.cs +++ /dev/null @@ -1,114 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using SixLabors.ImageSharp.ColorSpaces.Companding; -using SixLabors.ImageSharp.ColorSpaces.Conversion; - -// ReSharper disable InconsistentNaming -namespace SixLabors.ImageSharp.ColorSpaces; - -/// -/// Chromaticity coordinates based on: -/// -public static class RgbWorkingSpaces -{ - /// - /// sRgb working space. - /// - /// - /// Uses proper companding function, according to: - /// - /// - public static readonly RgbWorkingSpace SRgb = new SRgbWorkingSpace(Illuminants.D65, new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.6400F, 0.3300F), new CieXyChromaticityCoordinates(0.3000F, 0.6000F), new CieXyChromaticityCoordinates(0.1500F, 0.0600F))); - - /// - /// Simplified sRgb working space (uses gamma companding instead of ). - /// See also . - /// - public static readonly RgbWorkingSpace SRgbSimplified = new GammaWorkingSpace(2.2F, Illuminants.D65, new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.6400F, 0.3300F), new CieXyChromaticityCoordinates(0.3000F, 0.6000F), new CieXyChromaticityCoordinates(0.1500F, 0.0600F))); - - /// - /// Rec. 709 (ITU-R Recommendation BT.709) working space. - /// - public static readonly RgbWorkingSpace Rec709 = new Rec709WorkingSpace(Illuminants.D65, new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.64F, 0.33F), new CieXyChromaticityCoordinates(0.30F, 0.60F), new CieXyChromaticityCoordinates(0.15F, 0.06F))); - - /// - /// Rec. 2020 (ITU-R Recommendation BT.2020F) working space. - /// - public static readonly RgbWorkingSpace Rec2020 = new Rec2020WorkingSpace(Illuminants.D65, new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.708F, 0.292F), new CieXyChromaticityCoordinates(0.170F, 0.797F), new CieXyChromaticityCoordinates(0.131F, 0.046F))); - - /// - /// ECI Rgb v2 working space. - /// - public static readonly RgbWorkingSpace ECIRgbv2 = new LWorkingSpace(Illuminants.D50, new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.6700F, 0.3300F), new CieXyChromaticityCoordinates(0.2100F, 0.7100F), new CieXyChromaticityCoordinates(0.1400F, 0.0800F))); - - /// - /// Adobe Rgb (1998) working space. - /// - public static readonly RgbWorkingSpace AdobeRgb1998 = new GammaWorkingSpace(2.2F, Illuminants.D65, new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.6400F, 0.3300F), new CieXyChromaticityCoordinates(0.2100F, 0.7100F), new CieXyChromaticityCoordinates(0.1500F, 0.0600F))); - - /// - /// Apple sRgb working space. - /// - public static readonly RgbWorkingSpace ApplesRgb = new GammaWorkingSpace(1.8F, Illuminants.D65, new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.6250F, 0.3400F), new CieXyChromaticityCoordinates(0.2800F, 0.5950F), new CieXyChromaticityCoordinates(0.1550F, 0.0700F))); - - /// - /// Best Rgb working space. - /// - public static readonly RgbWorkingSpace BestRgb = new GammaWorkingSpace(2.2F, Illuminants.D50, new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.7347F, 0.2653F), new CieXyChromaticityCoordinates(0.2150F, 0.7750F), new CieXyChromaticityCoordinates(0.1300F, 0.0350F))); - - /// - /// Beta Rgb working space. - /// - public static readonly RgbWorkingSpace BetaRgb = new GammaWorkingSpace(2.2F, Illuminants.D50, new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.6888F, 0.3112F), new CieXyChromaticityCoordinates(0.1986F, 0.7551F), new CieXyChromaticityCoordinates(0.1265F, 0.0352F))); - - /// - /// Bruce Rgb working space. - /// - public static readonly RgbWorkingSpace BruceRgb = new GammaWorkingSpace(2.2F, Illuminants.D65, new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.6400F, 0.3300F), new CieXyChromaticityCoordinates(0.2800F, 0.6500F), new CieXyChromaticityCoordinates(0.1500F, 0.0600F))); - - /// - /// CIE Rgb working space. - /// - public static readonly RgbWorkingSpace CIERgb = new GammaWorkingSpace(2.2F, Illuminants.E, new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.7350F, 0.2650F), new CieXyChromaticityCoordinates(0.2740F, 0.7170F), new CieXyChromaticityCoordinates(0.1670F, 0.0090F))); - - /// - /// ColorMatch Rgb working space. - /// - public static readonly RgbWorkingSpace ColorMatchRgb = new GammaWorkingSpace(1.8F, Illuminants.D50, new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.6300F, 0.3400F), new CieXyChromaticityCoordinates(0.2950F, 0.6050F), new CieXyChromaticityCoordinates(0.1500F, 0.0750F))); - - /// - /// Don Rgb 4 working space. - /// - public static readonly RgbWorkingSpace DonRgb4 = new GammaWorkingSpace(2.2F, Illuminants.D50, new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.6960F, 0.3000F), new CieXyChromaticityCoordinates(0.2150F, 0.7650F), new CieXyChromaticityCoordinates(0.1300F, 0.0350F))); - - /// - /// Ekta Space PS5 working space. - /// - public static readonly RgbWorkingSpace EktaSpacePS5 = new GammaWorkingSpace(2.2F, Illuminants.D50, new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.6950F, 0.3050F), new CieXyChromaticityCoordinates(0.2600F, 0.7000F), new CieXyChromaticityCoordinates(0.1100F, 0.0050F))); - - /// - /// NTSC Rgb working space. - /// - public static readonly RgbWorkingSpace NTSCRgb = new GammaWorkingSpace(2.2F, Illuminants.C, new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.6700F, 0.3300F), new CieXyChromaticityCoordinates(0.2100F, 0.7100F), new CieXyChromaticityCoordinates(0.1400F, 0.0800F))); - - /// - /// PAL/SECAM Rgb working space. - /// - public static readonly RgbWorkingSpace PALSECAMRgb = new GammaWorkingSpace(2.2F, Illuminants.D65, new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.6400F, 0.3300F), new CieXyChromaticityCoordinates(0.2900F, 0.6000F), new CieXyChromaticityCoordinates(0.1500F, 0.0600F))); - - /// - /// ProPhoto Rgb working space. - /// - public static readonly RgbWorkingSpace ProPhotoRgb = new GammaWorkingSpace(1.8F, Illuminants.D50, new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.7347F, 0.2653F), new CieXyChromaticityCoordinates(0.1596F, 0.8404F), new CieXyChromaticityCoordinates(0.0366F, 0.0001F))); - - /// - /// SMPTE-C Rgb working space. - /// - public static readonly RgbWorkingSpace SMPTECRgb = new GammaWorkingSpace(2.2F, Illuminants.D65, new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.6300F, 0.3400F), new CieXyChromaticityCoordinates(0.3100F, 0.5950F), new CieXyChromaticityCoordinates(0.1550F, 0.0700F))); - - /// - /// Wide Gamut Rgb working space. - /// - public static readonly RgbWorkingSpace WideGamutRgb = new GammaWorkingSpace(2.2F, Illuminants.D50, new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.7350F, 0.2650F), new CieXyChromaticityCoordinates(0.1150F, 0.8260F), new CieXyChromaticityCoordinates(0.1570F, 0.0180F))); -} diff --git a/src/ImageSharp/Common/Helpers/Numerics.cs b/src/ImageSharp/Common/Helpers/Numerics.cs index 777de2dc9f..ca14ae4c38 100644 --- a/src/ImageSharp/Common/Helpers/Numerics.cs +++ b/src/ImageSharp/Common/Helpers/Numerics.cs @@ -141,6 +141,14 @@ internal static class Numerics [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Pow3(float x) => x * x * x; + /// + /// Returns a specified number raised to the power of 3 + /// + /// A double-precision floating-point number + /// The number raised to the power of 3. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static double Pow3(double x) => x * x * x; + /// /// Implementation of 1D Gaussian G(x) function /// diff --git a/src/ImageSharp/Formats/Gif/GifDecoderCore.cs b/src/ImageSharp/Formats/Gif/GifDecoderCore.cs index d64792eba7..982dbdc780 100644 --- a/src/ImageSharp/Formats/Gif/GifDecoderCore.cs +++ b/src/ImageSharp/Formats/Gif/GifDecoderCore.cs @@ -427,68 +427,49 @@ internal sealed class GifDecoderCore : IImageDecoderInternals { this.ReadImageDescriptor(stream); - Buffer2D? indices = null; - try - { - // Determine the color table for this frame. If there is a local one, use it otherwise use the global color table. - bool hasLocalColorTable = this.imageDescriptor.LocalColorTableFlag; - - if (hasLocalColorTable) - { - // Read and store the local color table. We allocate the maximum possible size and slice to match. - int length = this.currentLocalColorTableSize = this.imageDescriptor.LocalColorTableSize * 3; - this.currentLocalColorTable ??= this.configuration.MemoryAllocator.Allocate(768, AllocationOptions.Clean); - stream.Read(this.currentLocalColorTable.GetSpan()[..length]); - } - - indices = this.configuration.MemoryAllocator.Allocate2D(this.imageDescriptor.Width, this.imageDescriptor.Height, AllocationOptions.Clean); - this.ReadFrameIndices(stream, indices); + // Determine the color table for this frame. If there is a local one, use it otherwise use the global color table. + bool hasLocalColorTable = this.imageDescriptor.LocalColorTableFlag; - Span rawColorTable = default; - if (hasLocalColorTable) - { - rawColorTable = this.currentLocalColorTable!.GetSpan()[..this.currentLocalColorTableSize]; - } - else if (this.globalColorTable != null) - { - rawColorTable = this.globalColorTable.GetSpan(); - } - - ReadOnlySpan colorTable = MemoryMarshal.Cast(rawColorTable); - this.ReadFrameColors(ref image, ref previousFrame, indices, colorTable, this.imageDescriptor); + if (hasLocalColorTable) + { + // Read and store the local color table. We allocate the maximum possible size and slice to match. + int length = this.currentLocalColorTableSize = this.imageDescriptor.LocalColorTableSize * 3; + this.currentLocalColorTable ??= this.configuration.MemoryAllocator.Allocate(768, AllocationOptions.Clean); + stream.Read(this.currentLocalColorTable.GetSpan()[..length]); + } - // Skip any remaining blocks - SkipBlock(stream); + Span rawColorTable = default; + if (hasLocalColorTable) + { + rawColorTable = this.currentLocalColorTable!.GetSpan()[..this.currentLocalColorTableSize]; } - finally + else if (this.globalColorTable != null) { - indices?.Dispose(); + rawColorTable = this.globalColorTable.GetSpan(); } - } - /// - /// Reads the frame indices marking the color to use for each pixel. - /// - /// The containing image data. - /// The 2D pixel buffer to write to. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private void ReadFrameIndices(BufferedReadStream stream, Buffer2D indices) - { - int minCodeSize = stream.ReadByte(); - using LzwDecoder lzwDecoder = new(this.configuration.MemoryAllocator, stream); - lzwDecoder.DecodePixels(minCodeSize, indices); + ReadOnlySpan colorTable = MemoryMarshal.Cast(rawColorTable); + this.ReadFrameColors(stream, ref image, ref previousFrame, colorTable, this.imageDescriptor); + + // Skip any remaining blocks + SkipBlock(stream); } /// /// Reads the frames colors, mapping indices to colors. /// /// The pixel format. + /// The containing image data. /// The image to decode the information to. /// The previous frame. - /// The indexed pixels. /// The color table containing the available colors. /// The - private void ReadFrameColors(ref Image? image, ref ImageFrame? previousFrame, Buffer2D indices, ReadOnlySpan colorTable, in GifImageDescriptor descriptor) + private void ReadFrameColors( + BufferedReadStream stream, + ref Image? image, + ref ImageFrame? previousFrame, + ReadOnlySpan colorTable, + in GifImageDescriptor descriptor) where TPixel : unmanaged, IPixel { int imageWidth = this.logicalScreenDescriptor.Width; @@ -549,69 +530,79 @@ internal sealed class GifDecoderCore : IImageDecoderInternals byte transIndex = this.graphicsControlExtension.TransparencyIndex; int colorTableMaxIdx = colorTable.Length - 1; - for (int y = descriptorTop; y < descriptorBottom && y < imageHeight; y++) + // For a properly encoded gif the descriptor dimensions will never exceed the logical screen dimensions. + // However we have images that exceed this that can be decoded by other libraries. #1530 + using IMemoryOwner indicesRowOwner = this.memoryAllocator.Allocate(descriptor.Width); + Span indicesRow = indicesRowOwner.Memory.Span; + ref byte indicesRowRef = ref MemoryMarshal.GetReference(indicesRow); + + int minCodeSize = stream.ReadByte(); + if (LzwDecoder.IsValidMinCodeSize(minCodeSize)) { - ref byte indicesRowRef = ref MemoryMarshal.GetReference(indices.DangerousGetRowSpan(y - descriptorTop)); + using LzwDecoder lzwDecoder = new(this.configuration.MemoryAllocator, stream, minCodeSize); - // Check if this image is interlaced. - int writeY; // the target y offset to write to - if (descriptor.InterlaceFlag) + for (int y = descriptorTop; y < descriptorBottom && y < imageHeight; y++) { - // If so then we read lines at predetermined offsets. - // When an entire image height worth of offset lines has been read we consider this a pass. - // With each pass the number of offset lines changes and the starting line changes. - if (interlaceY >= descriptor.Height) + // Check if this image is interlaced. + int writeY; // the target y offset to write to + if (descriptor.InterlaceFlag) { - interlacePass++; - switch (interlacePass) + // If so then we read lines at predetermined offsets. + // When an entire image height worth of offset lines has been read we consider this a pass. + // With each pass the number of offset lines changes and the starting line changes. + if (interlaceY >= descriptor.Height) { - case 1: - interlaceY = 4; - break; - case 2: - interlaceY = 2; - interlaceIncrement = 4; - break; - case 3: - interlaceY = 1; - interlaceIncrement = 2; - break; + interlacePass++; + switch (interlacePass) + { + case 1: + interlaceY = 4; + break; + case 2: + interlaceY = 2; + interlaceIncrement = 4; + break; + case 3: + interlaceY = 1; + interlaceIncrement = 2; + break; + } } - } - writeY = interlaceY + descriptor.Top; - interlaceY += interlaceIncrement; - } - else - { - writeY = y; - } + writeY = Math.Min(interlaceY + descriptor.Top, image.Height); + interlaceY += interlaceIncrement; + } + else + { + writeY = y; + } - ref TPixel rowRef = ref MemoryMarshal.GetReference(imageFrame.PixelBuffer.DangerousGetRowSpan(writeY)); + lzwDecoder.DecodePixelRow(indicesRow); + ref TPixel rowRef = ref MemoryMarshal.GetReference(imageFrame.PixelBuffer.DangerousGetRowSpan(writeY)); - if (!transFlag) - { - // #403 The left + width value can be larger than the image width - for (int x = descriptorLeft; x < descriptorRight && x < imageWidth; x++) + if (!transFlag) { - int index = Numerics.Clamp(Unsafe.Add(ref indicesRowRef, (uint)(x - descriptorLeft)), 0, colorTableMaxIdx); - Unsafe.Add(ref rowRef, (uint)x) = TPixel.FromRgb24(colorTable[index]); + // #403 The left + width value can be larger than the image width + for (int x = descriptorLeft; x < descriptorRight && x < imageWidth; x++) + { + int index = Numerics.Clamp(Unsafe.Add(ref indicesRowRef, (uint)(x - descriptorLeft)), 0, colorTableMaxIdx); + Unsafe.Add(ref rowRef, (uint)x) = TPixel.FromRgb24(colorTable[index]); + } } - } - else - { - for (int x = descriptorLeft; x < descriptorRight && x < imageWidth; x++) + else { - int rawIndex = Unsafe.Add(ref indicesRowRef, (uint)(x - descriptorLeft)); - - // Treat any out of bounds values as transparent. - if (rawIndex > colorTableMaxIdx || rawIndex == transIndex) + for (int x = descriptorLeft; x < descriptorRight && x < imageWidth; x++) { - continue; - } + int index = Unsafe.Add(ref indicesRowRef, (uint)(x - descriptorLeft)); + + // Treat any out of bounds values as transparent. + if (index > colorTableMaxIdx || index == transIndex) + { + continue; + } - int index = Numerics.Clamp(rawIndex, 0, colorTableMaxIdx); - Unsafe.Add(ref rowRef, (uint)x) = TPixel.FromRgb24(colorTable[index]); + Unsafe.Add(ref rowRef, (uint)x) = TPixel.FromRgb24(colorTable[index]); + } } } } @@ -652,8 +643,11 @@ internal sealed class GifDecoderCore : IImageDecoderInternals // Skip the frame indices. Pixels length + mincode size. // The gif format does not tell us the length of the compressed data beforehand. int minCodeSize = stream.ReadByte(); - using LzwDecoder lzwDecoder = new(this.configuration.MemoryAllocator, stream); - lzwDecoder.SkipIndices(minCodeSize, this.imageDescriptor.Width * this.imageDescriptor.Height); + if (LzwDecoder.IsValidMinCodeSize(minCodeSize)) + { + using LzwDecoder lzwDecoder = new(this.configuration.MemoryAllocator, stream, minCodeSize); + lzwDecoder.SkipIndices(this.imageDescriptor.Width * this.imageDescriptor.Height); + } ImageFrameMetadata currentFrame = new(); frameMetadata.Add(currentFrame); diff --git a/src/ImageSharp/Formats/Gif/LzwDecoder.cs b/src/ImageSharp/Formats/Gif/LzwDecoder.cs index 19f646b597..ec33f2b3ed 100644 --- a/src/ImageSharp/Formats/Gif/LzwDecoder.cs +++ b/src/ImageSharp/Formats/Gif/LzwDecoder.cs @@ -44,10 +44,29 @@ internal sealed class LzwDecoder : IDisposable ///
private readonly IMemoryOwner suffix; + /// + /// The scratch buffer for reading data blocks. + /// + private readonly IMemoryOwner scratchBuffer; + /// /// The pixel stack buffer. /// private readonly IMemoryOwner pixelStack; + private readonly int minCodeSize; + private readonly int clearCode; + private readonly int endCode; + private int code; + private int codeSize; + private int codeMask; + private int availableCode; + private int oldCode = NullCode; + private int bits; + private int top; + private int count; + private int bufferIndex; + private int data; + private int first; /// /// Initializes a new instance of the class @@ -55,335 +74,277 @@ internal sealed class LzwDecoder : IDisposable /// /// The to use for buffer allocations. /// The stream to read from. + /// The minimum code size. /// is null. - public LzwDecoder(MemoryAllocator memoryAllocator, BufferedReadStream stream) + public LzwDecoder(MemoryAllocator memoryAllocator, BufferedReadStream stream, int minCodeSize) { this.stream = stream ?? throw new ArgumentNullException(nameof(stream)); this.prefix = memoryAllocator.Allocate(MaxStackSize, AllocationOptions.Clean); this.suffix = memoryAllocator.Allocate(MaxStackSize, AllocationOptions.Clean); this.pixelStack = memoryAllocator.Allocate(MaxStackSize + 1, AllocationOptions.Clean); + this.scratchBuffer = memoryAllocator.Allocate(byte.MaxValue, AllocationOptions.None); + this.minCodeSize = minCodeSize; + + // Calculate the clear code. The value of the clear code is 2 ^ minCodeSize + this.clearCode = 1 << minCodeSize; + this.codeSize = minCodeSize + 1; + this.codeMask = (1 << this.codeSize) - 1; + this.endCode = this.clearCode + 1; + this.availableCode = this.clearCode + 2; + + ref int suffixRef = ref MemoryMarshal.GetReference(this.suffix.GetSpan()); + for (this.code = 0; this.code < this.clearCode; this.code++) + { + Unsafe.Add(ref suffixRef, (uint)this.code) = (byte)this.code; + } } /// - /// Decodes and decompresses all pixel indices from the stream, assigning the pixel values to the buffer. + /// Gets a value indicating whether the minimum code size is valid. /// - /// Minimum code size of the data. - /// The pixel array to decode to. - public void DecodePixels(int minCodeSize, Buffer2D pixels) + /// The minimum code size. + /// + /// if the minimum code size is valid; otherwise, . + /// + public static bool IsValidMinCodeSize(int minCodeSize) { - // Calculate the clear code. The value of the clear code is 2 ^ minCodeSize - int clearCode = 1 << minCodeSize; - // It is possible to specify a larger LZW minimum code size than the palette length in bits // which may leave a gap in the codes where no colors are assigned. // http://www.matthewflickinger.com/lab/whatsinagif/lzw_image_data.asp#lzw_compression + int clearCode = 1 << minCodeSize; if (minCodeSize < 2 || minCodeSize > MaximumLzwBits || clearCode > MaxStackSize) { // Don't attempt to decode the frame indices. // Theoretically we could determine a min code size from the length of the provided // color palette but we won't bother since the image is most likely corrupted. - return; + return false; } - // The resulting index table length. - int width = pixels.Width; - int height = pixels.Height; - int length = width * height; - - int codeSize = minCodeSize + 1; - - // Calculate the end code - int endCode = clearCode + 1; - - // Calculate the available code. - int availableCode = clearCode + 2; - - // Jillzhangs Code see: http://giflib.codeplex.com/ - // Adapted from John Cristy's ImageMagick. - int code; - int oldCode = NullCode; - int codeMask = (1 << codeSize) - 1; - int bits = 0; - - int top = 0; - int count = 0; - int bi = 0; - int xyz = 0; + return true; + } - int data = 0; - int first = 0; + /// + /// Decodes and decompresses all pixel indices for a single row from the stream, assigning the pixel values to the buffer. + /// + /// The pixel indices array to decode to. + public void DecodePixelRow(Span indices) + { + indices.Clear(); + ref byte pixelsRowRef = ref MemoryMarshal.GetReference(indices); ref int prefixRef = ref MemoryMarshal.GetReference(this.prefix.GetSpan()); ref int suffixRef = ref MemoryMarshal.GetReference(this.suffix.GetSpan()); ref int pixelStackRef = ref MemoryMarshal.GetReference(this.pixelStack.GetSpan()); + Span buffer = this.scratchBuffer.GetSpan(); - for (code = 0; code < clearCode; code++) - { - Unsafe.Add(ref suffixRef, (uint)code) = (byte)code; - } - - Span buffer = stackalloc byte[byte.MaxValue]; - - int y = 0; int x = 0; - int rowMax = width; - ref byte pixelsRowRef = ref MemoryMarshal.GetReference(pixels.DangerousGetRowSpan(y)); - while (xyz < length) + int xyz = 0; + while (xyz < indices.Length) { - // Reset row reference. - if (xyz == rowMax) - { - x = 0; - pixelsRowRef = ref MemoryMarshal.GetReference(pixels.DangerousGetRowSpan(++y)); - rowMax = (y * width) + width; - } - - if (top == 0) + if (this.top == 0) { - if (bits < codeSize) + if (this.bits < this.codeSize) { // Load bytes until there are enough bits for a code. - if (count == 0) + if (this.count == 0) { // Read a new data block. - count = this.ReadBlock(buffer); - if (count == 0) + this.count = this.ReadBlock(buffer); + if (this.count == 0) { break; } - bi = 0; + this.bufferIndex = 0; } - data += buffer[bi] << bits; + this.data += buffer[this.bufferIndex] << this.bits; - bits += 8; - bi++; - count--; + this.bits += 8; + this.bufferIndex++; + this.count--; continue; } // Get the next code - code = data & codeMask; - data >>= codeSize; - bits -= codeSize; + this.code = this.data & this.codeMask; + this.data >>= this.codeSize; + this.bits -= this.codeSize; // Interpret the code - if (code > availableCode || code == endCode) + if (this.code > this.availableCode || this.code == this.endCode) { break; } - if (code == clearCode) + if (this.code == this.clearCode) { // Reset the decoder - codeSize = minCodeSize + 1; - codeMask = (1 << codeSize) - 1; - availableCode = clearCode + 2; - oldCode = NullCode; + this.codeSize = this.minCodeSize + 1; + this.codeMask = (1 << this.codeSize) - 1; + this.availableCode = this.clearCode + 2; + this.oldCode = NullCode; continue; } - if (oldCode == NullCode) + if (this.oldCode == NullCode) { - Unsafe.Add(ref pixelStackRef, (uint)top++) = Unsafe.Add(ref suffixRef, (uint)code); - oldCode = code; - first = code; + Unsafe.Add(ref pixelStackRef, (uint)this.top++) = Unsafe.Add(ref suffixRef, (uint)this.code); + this.oldCode = this.code; + this.first = this.code; continue; } - int inCode = code; - if (code == availableCode) + int inCode = this.code; + if (this.code == this.availableCode) { - Unsafe.Add(ref pixelStackRef, (uint)top++) = (byte)first; + Unsafe.Add(ref pixelStackRef, (uint)this.top++) = (byte)this.first; - code = oldCode; + this.code = this.oldCode; } - while (code > clearCode) + while (this.code > this.clearCode) { - Unsafe.Add(ref pixelStackRef, (uint)top++) = Unsafe.Add(ref suffixRef, (uint)code); - code = Unsafe.Add(ref prefixRef, (uint)code); + Unsafe.Add(ref pixelStackRef, (uint)this.top++) = Unsafe.Add(ref suffixRef, (uint)this.code); + this.code = Unsafe.Add(ref prefixRef, (uint)this.code); } - int suffixCode = Unsafe.Add(ref suffixRef, (uint)code); - first = suffixCode; - Unsafe.Add(ref pixelStackRef, (uint)top++) = suffixCode; + int suffixCode = Unsafe.Add(ref suffixRef, (uint)this.code); + this.first = suffixCode; + Unsafe.Add(ref pixelStackRef, (uint)this.top++) = suffixCode; // Fix for Gifs that have "deferred clear code" as per here : // https://bugzilla.mozilla.org/show_bug.cgi?id=55918 - if (availableCode < MaxStackSize) + if (this.availableCode < MaxStackSize) { - Unsafe.Add(ref prefixRef, (uint)availableCode) = oldCode; - Unsafe.Add(ref suffixRef, (uint)availableCode) = first; - availableCode++; - if (availableCode == codeMask + 1 && availableCode < MaxStackSize) + Unsafe.Add(ref prefixRef, (uint)this.availableCode) = this.oldCode; + Unsafe.Add(ref suffixRef, (uint)this.availableCode) = this.first; + this.availableCode++; + if (this.availableCode == this.codeMask + 1 && this.availableCode < MaxStackSize) { - codeSize++; - codeMask = (1 << codeSize) - 1; + this.codeSize++; + this.codeMask = (1 << this.codeSize) - 1; } } - oldCode = inCode; + this.oldCode = inCode; } // Pop a pixel off the pixel stack. - top--; + this.top--; // Clear missing pixels xyz++; - Unsafe.Add(ref pixelsRowRef, (uint)x++) = (byte)Unsafe.Add(ref pixelStackRef, (uint)top); + Unsafe.Add(ref pixelsRowRef, (uint)x++) = (byte)Unsafe.Add(ref pixelStackRef, (uint)this.top); } } /// /// Decodes and decompresses all pixel indices from the stream allowing skipping of the data. /// - /// Minimum code size of the data. /// The resulting index table length. - public void SkipIndices(int minCodeSize, int length) + public void SkipIndices(int length) { - // Calculate the clear code. The value of the clear code is 2 ^ minCodeSize - int clearCode = 1 << minCodeSize; - - // It is possible to specify a larger LZW minimum code size than the palette length in bits - // which may leave a gap in the codes where no colors are assigned. - // http://www.matthewflickinger.com/lab/whatsinagif/lzw_image_data.asp#lzw_compression - if (minCodeSize < 2 || minCodeSize > MaximumLzwBits || clearCode > MaxStackSize) - { - // Don't attempt to decode the frame indices. - // Theoretically we could determine a min code size from the length of the provided - // color palette but we won't bother since the image is most likely corrupted. - return; - } - - int codeSize = minCodeSize + 1; - - // Calculate the end code - int endCode = clearCode + 1; - - // Calculate the available code. - int availableCode = clearCode + 2; - - // Jillzhangs Code see: http://giflib.codeplex.com/ - // Adapted from John Cristy's ImageMagick. - int code; - int oldCode = NullCode; - int codeMask = (1 << codeSize) - 1; - int bits = 0; - - int top = 0; - int count = 0; - int bi = 0; - int xyz = 0; - - int data = 0; - int first = 0; - ref int prefixRef = ref MemoryMarshal.GetReference(this.prefix.GetSpan()); ref int suffixRef = ref MemoryMarshal.GetReference(this.suffix.GetSpan()); ref int pixelStackRef = ref MemoryMarshal.GetReference(this.pixelStack.GetSpan()); + Span buffer = this.scratchBuffer.GetSpan(); - for (code = 0; code < clearCode; code++) - { - Unsafe.Add(ref suffixRef, (uint)code) = (byte)code; - } - - Span buffer = stackalloc byte[byte.MaxValue]; + int xyz = 0; while (xyz < length) { - if (top == 0) + if (this.top == 0) { - if (bits < codeSize) + if (this.bits < this.codeSize) { // Load bytes until there are enough bits for a code. - if (count == 0) + if (this.count == 0) { // Read a new data block. - count = this.ReadBlock(buffer); - if (count == 0) + this.count = this.ReadBlock(buffer); + if (this.count == 0) { break; } - bi = 0; + this.bufferIndex = 0; } - data += buffer[bi] << bits; + this.data += buffer[this.bufferIndex] << this.bits; - bits += 8; - bi++; - count--; + this.bits += 8; + this.bufferIndex++; + this.count--; continue; } // Get the next code - code = data & codeMask; - data >>= codeSize; - bits -= codeSize; + this.code = this.data & this.codeMask; + this.data >>= this.codeSize; + this.bits -= this.codeSize; // Interpret the code - if (code > availableCode || code == endCode) + if (this.code > this.availableCode || this.code == this.endCode) { break; } - if (code == clearCode) + if (this.code == this.clearCode) { // Reset the decoder - codeSize = minCodeSize + 1; - codeMask = (1 << codeSize) - 1; - availableCode = clearCode + 2; - oldCode = NullCode; + this.codeSize = this.minCodeSize + 1; + this.codeMask = (1 << this.codeSize) - 1; + this.availableCode = this.clearCode + 2; + this.oldCode = NullCode; continue; } - if (oldCode == NullCode) + if (this.oldCode == NullCode) { - Unsafe.Add(ref pixelStackRef, (uint)top++) = Unsafe.Add(ref suffixRef, (uint)code); - oldCode = code; - first = code; + Unsafe.Add(ref pixelStackRef, (uint)this.top++) = Unsafe.Add(ref suffixRef, (uint)this.code); + this.oldCode = this.code; + this.first = this.code; continue; } - int inCode = code; - if (code == availableCode) + int inCode = this.code; + if (this.code == this.availableCode) { - Unsafe.Add(ref pixelStackRef, (uint)top++) = (byte)first; + Unsafe.Add(ref pixelStackRef, (uint)this.top++) = (byte)this.first; - code = oldCode; + this.code = this.oldCode; } - while (code > clearCode) + while (this.code > this.clearCode) { - Unsafe.Add(ref pixelStackRef, (uint)top++) = Unsafe.Add(ref suffixRef, (uint)code); - code = Unsafe.Add(ref prefixRef, (uint)code); + Unsafe.Add(ref pixelStackRef, (uint)this.top++) = Unsafe.Add(ref suffixRef, (uint)this.code); + this.code = Unsafe.Add(ref prefixRef, (uint)this.code); } - int suffixCode = Unsafe.Add(ref suffixRef, (uint)code); - first = suffixCode; - Unsafe.Add(ref pixelStackRef, (uint)top++) = suffixCode; + int suffixCode = Unsafe.Add(ref suffixRef, (uint)this.code); + this.first = suffixCode; + Unsafe.Add(ref pixelStackRef, (uint)this.top++) = suffixCode; // Fix for Gifs that have "deferred clear code" as per here : // https://bugzilla.mozilla.org/show_bug.cgi?id=55918 - if (availableCode < MaxStackSize) + if (this.availableCode < MaxStackSize) { - Unsafe.Add(ref prefixRef, (uint)availableCode) = oldCode; - Unsafe.Add(ref suffixRef, (uint)availableCode) = first; - availableCode++; - if (availableCode == codeMask + 1 && availableCode < MaxStackSize) + Unsafe.Add(ref prefixRef, (uint)this.availableCode) = this.oldCode; + Unsafe.Add(ref suffixRef, (uint)this.availableCode) = this.first; + this.availableCode++; + if (this.availableCode == this.codeMask + 1 && this.availableCode < MaxStackSize) { - codeSize++; - codeMask = (1 << codeSize) - 1; + this.codeSize++; + this.codeMask = (1 << this.codeSize) - 1; } } - oldCode = inCode; + this.oldCode = inCode; } // Pop a pixel off the pixel stack. - top--; + this.top--; // Clear missing pixels xyz++; @@ -419,5 +380,6 @@ internal sealed class LzwDecoder : IDisposable this.prefix.Dispose(); this.suffix.Dispose(); this.pixelStack.Dispose(); + this.scratchBuffer.Dispose(); } } diff --git a/src/ImageSharp/Formats/Jpeg/Components/Quantization.cs b/src/ImageSharp/Formats/Jpeg/Components/Quantization.cs index 3d53d5bfe8..7dca1cf5ea 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Quantization.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Quantization.cs @@ -146,7 +146,7 @@ internal static class Quantization quality = (int)Math.Round(5000.0 / sumPercent); } - return quality; + return Numerics.Clamp(quality, MinQualityFactor, MaxQualityFactor); } /// diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/CieLabPlanarTiffColor{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/CieLabPlanarTiffColor{TPixel}.cs index 6be584581f..d6fc7c4870 100644 --- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/CieLabPlanarTiffColor{TPixel}.cs +++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/CieLabPlanarTiffColor{TPixel}.cs @@ -2,8 +2,7 @@ // Licensed under the Six Labors Split License. using System.Buffers; -using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion; +using SixLabors.ImageSharp.ColorProfiles; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.PixelFormats; @@ -16,7 +15,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation; internal class CieLabPlanarTiffColor : TiffBasePlanarColorDecoder where TPixel : unmanaged, IPixel { - private static readonly ColorSpaceConverter ColorSpaceConverter = new(); + private static readonly ColorProfileConverter ColorProfileConverter = new(); private const float Inv255 = 1.0f / 255.0f; @@ -34,7 +33,7 @@ internal class CieLabPlanarTiffColor : TiffBasePlanarColorDecoder(in lab); pixelRow[x] = TPixel.FromScaledVector4(new(rgb.R, rgb.G, rgb.B, 1.0f)); offset++; diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/CieLabTiffColor{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/CieLabTiffColor{TPixel}.cs index e5dc574f7f..b0236022b3 100644 --- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/CieLabTiffColor{TPixel}.cs +++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/CieLabTiffColor{TPixel}.cs @@ -1,8 +1,7 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion; +using SixLabors.ImageSharp.ColorProfiles; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.PixelFormats; @@ -15,7 +14,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation; internal class CieLabTiffColor : TiffBaseColorDecoder where TPixel : unmanaged, IPixel { - private static readonly ColorSpaceConverter ColorSpaceConverter = new(); + private static readonly ColorProfileConverter ColorProfileConverter = new(); private const float Inv255 = 1f / 255f; /// @@ -30,7 +29,7 @@ internal class CieLabTiffColor : TiffBaseColorDecoder { float l = (data[offset] & 0xFF) * 100f * Inv255; CieLab lab = new(l, (sbyte)data[offset + 1], (sbyte)data[offset + 2]); - Rgb rgb = ColorSpaceConverter.ToRgb(lab); + Rgb rgb = ColorProfileConverter.Convert(in lab); pixelRow[x] = TPixel.FromScaledVector4(new(rgb.R, rgb.G, rgb.B, 1f)); offset += 3; diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/CmykTiffColor{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/CmykTiffColor{TPixel}.cs index 77baa5351a..c7fe2ed075 100644 --- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/CmykTiffColor{TPixel}.cs +++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/CmykTiffColor{TPixel}.cs @@ -1,8 +1,7 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion; +using SixLabors.ImageSharp.ColorProfiles; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.PixelFormats; @@ -11,6 +10,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation; internal class CmykTiffColor : TiffBaseColorDecoder where TPixel : unmanaged, IPixel { + private static readonly ColorProfileConverter ColorProfileConverter = new(); private const float Inv255 = 1f / 255f; /// @@ -23,7 +23,7 @@ internal class CmykTiffColor : TiffBaseColorDecoder for (int x = 0; x < pixelRow.Length; x++) { Cmyk cmyk = new(data[offset] * Inv255, data[offset + 1] * Inv255, data[offset + 2] * Inv255, data[offset + 3] * Inv255); - Rgb rgb = ColorSpaceConverter.ToRgb(in cmyk); + Rgb rgb = ColorProfileConverter.Convert(in cmyk); pixelRow[x] = TPixel.FromScaledVector4(new(rgb.R, rgb.G, rgb.B, 1.0f)); offset += 4; diff --git a/src/ImageSharp/PixelFormats/PixelConversionModifiers.cs b/src/ImageSharp/PixelFormats/PixelConversionModifiers.cs index 25fc74e08f..edc04fa7ce 100644 --- a/src/ImageSharp/PixelFormats/PixelConversionModifiers.cs +++ b/src/ImageSharp/PixelFormats/PixelConversionModifiers.cs @@ -1,7 +1,7 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -using SixLabors.ImageSharp.ColorSpaces.Companding; +using SixLabors.ImageSharp.ColorProfiles.Companding; namespace SixLabors.ImageSharp.PixelFormats; diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Rgb24.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Rgb24.cs index ac855d47dc..0aa7bad237 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Rgb24.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Rgb24.cs @@ -5,6 +5,7 @@ using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Intrinsics; +using SixLabors.ImageSharp.ColorProfiles; namespace SixLabors.ImageSharp.PixelFormats; @@ -54,13 +55,13 @@ public partial struct Rgb24 : IPixel } /// - /// Allows the implicit conversion of an instance of to a + /// Allows the implicit conversion of an instance of to a /// . /// - /// The instance of to convert. + /// The instance of to convert. /// An instance of . [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static implicit operator Rgb24(ColorSpaces.Rgb color) => FromScaledVector4(new Vector4(color.ToVector3(), 1f)); + public static implicit operator Rgb24(Rgb color) => FromScaledVector4(new Vector4(color.ToVector3(), 1f)); /// /// Compares two objects for equality. diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.cs index fc347c1665..0491553430 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.cs @@ -7,6 +7,7 @@ using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Intrinsics; +using SixLabors.ImageSharp.ColorProfiles; namespace SixLabors.ImageSharp.PixelFormats; @@ -180,13 +181,13 @@ public partial struct Rgba32 : IPixel, IPackedVector } /// - /// Allows the implicit conversion of an instance of to a + /// Allows the implicit conversion of an instance of to a /// . /// - /// The instance of to convert. + /// The instance of to convert. /// An instance of . [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static implicit operator Rgba32(ColorSpaces.Rgb color) => FromScaledVector4(new Vector4(color.ToVector3(), 1F)); + public static implicit operator Rgba32(Rgb color) => FromScaledVector4(new Vector4(color.ToVector3(), 1F)); /// /// Compares two objects for equality. diff --git a/src/ImageSharp/PixelFormats/Utils/Vector4Converters.cs b/src/ImageSharp/PixelFormats/Utils/Vector4Converters.cs index 8f682ae8f6..0a0b5660d2 100644 --- a/src/ImageSharp/PixelFormats/Utils/Vector4Converters.cs +++ b/src/ImageSharp/PixelFormats/Utils/Vector4Converters.cs @@ -3,7 +3,7 @@ using System.Numerics; using System.Runtime.CompilerServices; -using SixLabors.ImageSharp.ColorSpaces.Companding; +using SixLabors.ImageSharp.ColorProfiles.Companding; namespace SixLabors.ImageSharp.PixelFormats.Utils; @@ -12,6 +12,8 @@ internal static partial class Vector4Converters /// /// Apply modifiers used requested by ToVector4() conversion. /// + /// The span of vectors. + /// The modifier rule. [MethodImpl(InliningOptions.ShortMethod)] internal static void ApplyForwardConversionModifiers(Span vectors, PixelConversionModifiers modifiers) { @@ -29,6 +31,8 @@ internal static partial class Vector4Converters /// /// Apply modifiers used requested by FromVector4() conversion. /// + /// The span of vectors. + /// The modifier rule. [MethodImpl(InliningOptions.ShortMethod)] internal static void ApplyBackwardConversionModifiers(Span vectors, PixelConversionModifiers modifiers) { diff --git a/src/ImageSharp/Processing/AffineTransformBuilder.cs b/src/ImageSharp/Processing/AffineTransformBuilder.cs index d16b2fe55a..59264698bd 100644 --- a/src/ImageSharp/Processing/AffineTransformBuilder.cs +++ b/src/ImageSharp/Processing/AffineTransformBuilder.cs @@ -11,7 +11,8 @@ namespace SixLabors.ImageSharp.Processing; /// public class AffineTransformBuilder { - private readonly List> matrixFactories = new List>(); + private readonly List> transformMatrixFactories = new(); + private readonly List> boundsMatrixFactories = new(); /// /// Prepends a rotation matrix using the given rotation angle in degrees @@ -29,7 +30,9 @@ public class AffineTransformBuilder /// The amount of rotation, in radians. /// The . public AffineTransformBuilder PrependRotationRadians(float radians) - => this.Prepend(size => TransformUtils.CreateRotationMatrixRadians(radians, size)); + => this.Prepend( + size => TransformUtils.CreateRotationTransformMatrixRadians(radians, size), + size => TransformUtils.CreateRotationBoundsMatrixRadians(radians, size)); /// /// Prepends a rotation matrix using the given rotation in degrees at the given origin. @@ -65,7 +68,9 @@ public class AffineTransformBuilder /// The amount of rotation, in radians. /// The . public AffineTransformBuilder AppendRotationRadians(float radians) - => this.Append(size => TransformUtils.CreateRotationMatrixRadians(radians, size)); + => this.Append( + size => TransformUtils.CreateRotationTransformMatrixRadians(radians, size), + size => TransformUtils.CreateRotationBoundsMatrixRadians(radians, size)); /// /// Appends a rotation matrix using the given rotation in degrees at the given origin. @@ -140,7 +145,9 @@ public class AffineTransformBuilder /// The Y angle, in degrees. /// The . public AffineTransformBuilder PrependSkewDegrees(float degreesX, float degreesY) - => this.Prepend(size => TransformUtils.CreateSkewMatrixDegrees(degreesX, degreesY, size)); + => this.Prepend( + size => TransformUtils.CreateSkewTransformMatrixDegrees(degreesX, degreesY, size), + size => TransformUtils.CreateSkewBoundsMatrixDegrees(degreesX, degreesY, size)); /// /// Prepends a centered skew matrix from the give angles in radians. @@ -149,7 +156,9 @@ public class AffineTransformBuilder /// The Y angle, in radians. /// The . public AffineTransformBuilder PrependSkewRadians(float radiansX, float radiansY) - => this.Prepend(size => TransformUtils.CreateSkewMatrixRadians(radiansX, radiansY, size)); + => this.Prepend( + size => TransformUtils.CreateSkewTransformMatrixRadians(radiansX, radiansY, size), + size => TransformUtils.CreateSkewBoundsMatrixRadians(radiansX, radiansY, size)); /// /// Prepends a skew matrix using the given angles in degrees at the given origin. @@ -178,7 +187,9 @@ public class AffineTransformBuilder /// The Y angle, in degrees. /// The . public AffineTransformBuilder AppendSkewDegrees(float degreesX, float degreesY) - => this.Append(size => TransformUtils.CreateSkewMatrixDegrees(degreesX, degreesY, size)); + => this.Append( + size => TransformUtils.CreateSkewTransformMatrixDegrees(degreesX, degreesY, size), + size => TransformUtils.CreateSkewBoundsMatrixDegrees(degreesX, degreesY, size)); /// /// Appends a centered skew matrix from the give angles in radians. @@ -187,7 +198,9 @@ public class AffineTransformBuilder /// The Y angle, in radians. /// The . public AffineTransformBuilder AppendSkewRadians(float radiansX, float radiansY) - => this.Append(size => TransformUtils.CreateSkewMatrixRadians(radiansX, radiansY, size)); + => this.Append( + size => TransformUtils.CreateSkewTransformMatrixRadians(radiansX, radiansY, size), + size => TransformUtils.CreateSkewBoundsMatrixRadians(radiansX, radiansY, size)); /// /// Appends a skew matrix using the given angles in degrees at the given origin. @@ -254,7 +267,7 @@ public class AffineTransformBuilder public AffineTransformBuilder PrependMatrix(Matrix3x2 matrix) { CheckDegenerate(matrix); - return this.Prepend(_ => matrix); + return this.Prepend(_ => matrix, _ => matrix); } /// @@ -270,7 +283,7 @@ public class AffineTransformBuilder public AffineTransformBuilder AppendMatrix(Matrix3x2 matrix) { CheckDegenerate(matrix); - return this.Append(_ => matrix); + return this.Append(_ => matrix, _ => matrix); } /// @@ -281,7 +294,7 @@ public class AffineTransformBuilder public Matrix3x2 BuildMatrix(Size sourceSize) => this.BuildMatrix(new Rectangle(Point.Empty, sourceSize)); /// - /// Returns the combined matrix for a given source rectangle. + /// Returns the combined transform matrix for a given source rectangle. /// /// The rectangle in the source image. /// @@ -296,11 +309,11 @@ public class AffineTransformBuilder Guard.MustBeGreaterThan(sourceRectangle.Height, 0, nameof(sourceRectangle)); // Translate the origin matrix to cater for source rectangle offsets. - var matrix = Matrix3x2.CreateTranslation(-sourceRectangle.Location); + Matrix3x2 matrix = Matrix3x2.CreateTranslation(-sourceRectangle.Location); Size size = sourceRectangle.Size; - foreach (Func factory in this.matrixFactories) + foreach (Func factory in this.transformMatrixFactories) { matrix *= factory(size); } @@ -310,6 +323,32 @@ public class AffineTransformBuilder return matrix; } + /// + /// Returns the size of a rectangle large enough to contain the transformed source rectangle. + /// + /// The rectangle in the source image. + /// + /// The resultant matrix is degenerate containing one or more values equivalent + /// to or a zero determinant and therefore cannot be used + /// for linear transforms. + /// + /// The . + public Size GetTransformedSize(Rectangle sourceRectangle) + { + Size size = sourceRectangle.Size; + + // Translate the origin matrix to cater for source rectangle offsets. + Matrix3x2 matrix = Matrix3x2.CreateTranslation(-sourceRectangle.Location); + + foreach (Func factory in this.boundsMatrixFactories) + { + matrix *= factory(size); + CheckDegenerate(matrix); + } + + return TransformUtils.GetTransformedSize(size, matrix); + } + private static void CheckDegenerate(Matrix3x2 matrix) { if (TransformUtils.IsDegenerate(matrix)) @@ -318,15 +357,17 @@ public class AffineTransformBuilder } } - private AffineTransformBuilder Prepend(Func factory) + private AffineTransformBuilder Prepend(Func transformFactory, Func boundsFactory) { - this.matrixFactories.Insert(0, factory); + this.transformMatrixFactories.Insert(0, transformFactory); + this.boundsMatrixFactories.Insert(0, boundsFactory); return this; } - private AffineTransformBuilder Append(Func factory) + private AffineTransformBuilder Append(Func transformFactory, Func boundsFactory) { - this.matrixFactories.Add(factory); + this.transformMatrixFactories.Add(transformFactory); + this.boundsMatrixFactories.Add(boundsFactory); return this; } } diff --git a/src/ImageSharp/Processing/Extensions/Transforms/TransformExtensions.cs b/src/ImageSharp/Processing/Extensions/Transforms/TransformExtensions.cs index e88f000a7c..60f90b10f2 100644 --- a/src/ImageSharp/Processing/Extensions/Transforms/TransformExtensions.cs +++ b/src/ImageSharp/Processing/Extensions/Transforms/TransformExtensions.cs @@ -51,7 +51,7 @@ public static class TransformExtensions IResampler sampler) { Matrix3x2 transform = builder.BuildMatrix(sourceRectangle); - Size targetDimensions = TransformUtils.GetTransformedSize(sourceRectangle.Size, transform); + Size targetDimensions = builder.GetTransformedSize(sourceRectangle); return source.Transform(sourceRectangle, transform, targetDimensions, sampler); } @@ -113,7 +113,7 @@ public static class TransformExtensions IResampler sampler) { Matrix4x4 transform = builder.BuildMatrix(sourceRectangle); - Size targetDimensions = TransformUtils.GetTransformedSize(sourceRectangle.Size, transform); + Size targetDimensions = builder.GetTransformedSize(sourceRectangle); return source.Transform(sourceRectangle, transform, targetDimensions, sampler); } diff --git a/src/ImageSharp/Processing/Processors/Transforms/Linear/LinearTransformUtility.cs b/src/ImageSharp/Processing/Processors/Transforms/Linear/LinearTransformUtility.cs index c92f424290..b5eb202c18 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/Linear/LinearTransformUtility.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/Linear/LinearTransformUtility.cs @@ -38,8 +38,8 @@ internal static class LinearTransformUtility /// /// The radius. /// The center position. - /// The min allowed amouunt. - /// The max allowed amouunt. + /// The min allowed amount. + /// The max allowed amount. /// The . [MethodImpl(InliningOptions.ShortMethod)] public static int GetRangeStart(float radius, float center, int min, int max) @@ -51,8 +51,8 @@ internal static class LinearTransformUtility /// /// The radius. /// The center position. - /// The min allowed amouunt. - /// The max allowed amouunt. + /// The min allowed amount. + /// The max allowed amount. /// The . [MethodImpl(InliningOptions.ShortMethod)] public static int GetRangeEnd(float radius, float center, int min, int max) diff --git a/src/ImageSharp/Processing/Processors/Transforms/Linear/RotateProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/Linear/RotateProcessor.cs index b8a8f424ba..6580636a24 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/Linear/RotateProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/Linear/RotateProcessor.cs @@ -28,14 +28,15 @@ public sealed class RotateProcessor : AffineTransformProcessor /// The source image size public RotateProcessor(float degrees, IResampler sampler, Size sourceSize) : this( - TransformUtils.CreateRotationMatrixDegrees(degrees, sourceSize), + TransformUtils.CreateRotationTransformMatrixDegrees(degrees, sourceSize), + TransformUtils.CreateRotationBoundsMatrixDegrees(degrees, sourceSize), sampler, sourceSize) => this.Degrees = degrees; // Helper constructor - private RotateProcessor(Matrix3x2 rotationMatrix, IResampler sampler, Size sourceSize) - : base(rotationMatrix, sampler, TransformUtils.GetTransformedSize(sourceSize, rotationMatrix)) + private RotateProcessor(Matrix3x2 rotationMatrix, Matrix3x2 boundsMatrix, IResampler sampler, Size sourceSize) + : base(rotationMatrix, sampler, TransformUtils.GetTransformedSize(sourceSize, boundsMatrix)) { } diff --git a/src/ImageSharp/Processing/Processors/Transforms/Linear/SkewProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/Linear/SkewProcessor.cs index 5f16ec530b..97b18de6c8 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/Linear/SkewProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/Linear/SkewProcessor.cs @@ -30,7 +30,8 @@ public sealed class SkewProcessor : AffineTransformProcessor /// The source image size public SkewProcessor(float degreesX, float degreesY, IResampler sampler, Size sourceSize) : this( - TransformUtils.CreateSkewMatrixDegrees(degreesX, degreesY, sourceSize), + TransformUtils.CreateSkewTransformMatrixDegrees(degreesX, degreesY, sourceSize), + TransformUtils.CreateSkewBoundsMatrixDegrees(degreesX, degreesY, sourceSize), sampler, sourceSize) { @@ -39,8 +40,8 @@ public sealed class SkewProcessor : AffineTransformProcessor } // Helper constructor: - private SkewProcessor(Matrix3x2 skewMatrix, IResampler sampler, Size sourceSize) - : base(skewMatrix, sampler, TransformUtils.GetTransformedSize(sourceSize, skewMatrix)) + private SkewProcessor(Matrix3x2 skewMatrix, Matrix3x2 boundsMatrix, IResampler sampler, Size sourceSize) + : base(skewMatrix, sampler, TransformUtils.GetTransformedSize(sourceSize, boundsMatrix)) { } diff --git a/src/ImageSharp/Processing/Processors/Transforms/TransformUtils.cs b/src/ImageSharp/Processing/Processors/Transforms/TransformUtils.cs index 6ae0bbbdb0..70112ab5a8 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/TransformUtils.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/TransformUtils.cs @@ -29,7 +29,7 @@ internal static class TransformUtils public static bool IsDegenerate(Matrix4x4 matrix) => IsNaN(matrix) || IsZero(matrix.GetDeterminant()); - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] private static bool IsZero(float a) => a > -Constants.EpsilonSquared && a < Constants.EpsilonSquared; @@ -39,13 +39,11 @@ internal static class TransformUtils /// /// The transform matrix. /// The . - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsNaN(Matrix3x2 matrix) - { - return float.IsNaN(matrix.M11) || float.IsNaN(matrix.M12) - || float.IsNaN(matrix.M21) || float.IsNaN(matrix.M22) - || float.IsNaN(matrix.M31) || float.IsNaN(matrix.M32); - } + => float.IsNaN(matrix.M11) || float.IsNaN(matrix.M12) + || float.IsNaN(matrix.M21) || float.IsNaN(matrix.M22) + || float.IsNaN(matrix.M31) || float.IsNaN(matrix.M32); /// /// Returns a value that indicates whether the specified matrix contains any values @@ -53,14 +51,12 @@ internal static class TransformUtils /// /// The transform matrix. /// The . - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsNaN(Matrix4x4 matrix) - { - return float.IsNaN(matrix.M11) || float.IsNaN(matrix.M12) || float.IsNaN(matrix.M13) || float.IsNaN(matrix.M14) - || float.IsNaN(matrix.M21) || float.IsNaN(matrix.M22) || float.IsNaN(matrix.M23) || float.IsNaN(matrix.M24) - || float.IsNaN(matrix.M31) || float.IsNaN(matrix.M32) || float.IsNaN(matrix.M33) || float.IsNaN(matrix.M34) - || float.IsNaN(matrix.M41) || float.IsNaN(matrix.M42) || float.IsNaN(matrix.M43) || float.IsNaN(matrix.M44); - } + => float.IsNaN(matrix.M11) || float.IsNaN(matrix.M12) || float.IsNaN(matrix.M13) || float.IsNaN(matrix.M14) + || float.IsNaN(matrix.M21) || float.IsNaN(matrix.M22) || float.IsNaN(matrix.M23) || float.IsNaN(matrix.M24) + || float.IsNaN(matrix.M31) || float.IsNaN(matrix.M32) || float.IsNaN(matrix.M33) || float.IsNaN(matrix.M34) + || float.IsNaN(matrix.M41) || float.IsNaN(matrix.M42) || float.IsNaN(matrix.M43) || float.IsNaN(matrix.M44); /// /// Applies the projective transform against the given coordinates flattened into the 2D space. @@ -69,71 +65,121 @@ internal static class TransformUtils /// The "y" vector coordinate. /// The transform matrix. /// The . - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector2 ProjectiveTransform2D(float x, float y, Matrix4x4 matrix) { - const float Epsilon = 0.0000001F; - var v4 = Vector4.Transform(new Vector4(x, y, 0, 1F), matrix); - return new Vector2(v4.X, v4.Y) / MathF.Max(v4.W, Epsilon); + const float epsilon = 0.0000001F; + Vector4 v4 = Vector4.Transform(new Vector4(x, y, 0, 1F), matrix); + return new Vector2(v4.X, v4.Y) / MathF.Max(v4.W, epsilon); } /// - /// Creates a centered rotation matrix using the given rotation in degrees and the source size. + /// Creates a centered rotation transform matrix using the given rotation in degrees and the source size. /// /// The amount of rotation, in degrees. /// The source image size. /// The . - [MethodImpl(InliningOptions.ShortMethod)] - public static Matrix3x2 CreateRotationMatrixDegrees(float degrees, Size size) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Matrix3x2 CreateRotationTransformMatrixDegrees(float degrees, Size size) => CreateCenteredTransformMatrix( new Rectangle(Point.Empty, size), Matrix3x2Extensions.CreateRotationDegrees(degrees, PointF.Empty)); /// - /// Creates a centered rotation matrix using the given rotation in radians and the source size. + /// Creates a centered rotation transform matrix using the given rotation in radians and the source size. /// /// The amount of rotation, in radians. /// The source image size. /// The . - [MethodImpl(InliningOptions.ShortMethod)] - public static Matrix3x2 CreateRotationMatrixRadians(float radians, Size size) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Matrix3x2 CreateRotationTransformMatrixRadians(float radians, Size size) => CreateCenteredTransformMatrix( new Rectangle(Point.Empty, size), Matrix3x2Extensions.CreateRotation(radians, PointF.Empty)); /// - /// Creates a centered skew matrix from the give angles in degrees and the source size. + /// Creates a centered rotation bounds matrix using the given rotation in degrees and the source size. + /// + /// The amount of rotation, in degrees. + /// The source image size. + /// The . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Matrix3x2 CreateRotationBoundsMatrixDegrees(float degrees, Size size) + => CreateCenteredBoundsMatrix( + new Rectangle(Point.Empty, size), + Matrix3x2Extensions.CreateRotationDegrees(degrees, PointF.Empty)); + + /// + /// Creates a centered rotation bounds matrix using the given rotation in radians and the source size. + /// + /// The amount of rotation, in radians. + /// The source image size. + /// The . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Matrix3x2 CreateRotationBoundsMatrixRadians(float radians, Size size) + => CreateCenteredBoundsMatrix( + new Rectangle(Point.Empty, size), + Matrix3x2Extensions.CreateRotation(radians, PointF.Empty)); + + /// + /// Creates a centered skew transform matrix from the give angles in degrees and the source size. /// /// The X angle, in degrees. /// The Y angle, in degrees. /// The source image size. /// The . - [MethodImpl(InliningOptions.ShortMethod)] - public static Matrix3x2 CreateSkewMatrixDegrees(float degreesX, float degreesY, Size size) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Matrix3x2 CreateSkewTransformMatrixDegrees(float degreesX, float degreesY, Size size) => CreateCenteredTransformMatrix( new Rectangle(Point.Empty, size), Matrix3x2Extensions.CreateSkewDegrees(degreesX, degreesY, PointF.Empty)); /// - /// Creates a centered skew matrix from the give angles in radians and the source size. + /// Creates a centered skew transform matrix from the give angles in radians and the source size. /// /// The X angle, in radians. /// The Y angle, in radians. /// The source image size. /// The . - [MethodImpl(InliningOptions.ShortMethod)] - public static Matrix3x2 CreateSkewMatrixRadians(float radiansX, float radiansY, Size size) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Matrix3x2 CreateSkewTransformMatrixRadians(float radiansX, float radiansY, Size size) => CreateCenteredTransformMatrix( new Rectangle(Point.Empty, size), Matrix3x2Extensions.CreateSkew(radiansX, radiansY, PointF.Empty)); /// - /// Gets the centered transform matrix based upon the source and destination rectangles. + /// Creates a centered skew bounds matrix from the give angles in degrees and the source size. + /// + /// The X angle, in degrees. + /// The Y angle, in degrees. + /// The source image size. + /// The . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Matrix3x2 CreateSkewBoundsMatrixDegrees(float degreesX, float degreesY, Size size) + => CreateCenteredBoundsMatrix( + new Rectangle(Point.Empty, size), + Matrix3x2Extensions.CreateSkewDegrees(degreesX, degreesY, PointF.Empty)); + + /// + /// Creates a centered skew bounds matrix from the give angles in radians and the source size. + /// + /// The X angle, in radians. + /// The Y angle, in radians. + /// The source image size. + /// The . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Matrix3x2 CreateSkewBoundsMatrixRadians(float radiansX, float radiansY, Size size) + => CreateCenteredBoundsMatrix( + new Rectangle(Point.Empty, size), + Matrix3x2Extensions.CreateSkew(radiansX, radiansY, PointF.Empty)); + + /// + /// Gets the centered transform matrix based upon the source rectangle. /// /// The source image bounds. /// The transformation matrix. /// The - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Matrix3x2 CreateCenteredTransformMatrix(Rectangle sourceRectangle, Matrix3x2 matrix) { Rectangle destinationRectangle = GetTransformedBoundingRectangle(sourceRectangle, matrix); @@ -142,8 +188,33 @@ internal static class TransformUtils // This ensures scaling matrices are correct. Matrix3x2.Invert(matrix, out Matrix3x2 inverted); - var translationToTargetCenter = Matrix3x2.CreateTranslation(new Vector2(-destinationRectangle.Width, -destinationRectangle.Height) * .5F); - var translateToSourceCenter = Matrix3x2.CreateTranslation(new Vector2(sourceRectangle.Width, sourceRectangle.Height) * .5F); + // Centered transforms must be 0 based so we offset the bounds width and height. + Matrix3x2 translationToTargetCenter = Matrix3x2.CreateTranslation(new Vector2(-(destinationRectangle.Width - 1), -(destinationRectangle.Height - 1)) * .5F); + Matrix3x2 translateToSourceCenter = Matrix3x2.CreateTranslation(new Vector2(sourceRectangle.Width - 1, sourceRectangle.Height - 1) * .5F); + + // Translate back to world space. + Matrix3x2.Invert(translationToTargetCenter * inverted * translateToSourceCenter, out Matrix3x2 centered); + + return centered; + } + + /// + /// Gets the centered bounds matrix based upon the source rectangle. + /// + /// The source image bounds. + /// The transformation matrix. + /// The + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Matrix3x2 CreateCenteredBoundsMatrix(Rectangle sourceRectangle, Matrix3x2 matrix) + { + Rectangle destinationRectangle = GetTransformedBoundingRectangle(sourceRectangle, matrix); + + // We invert the matrix to handle the transformation from screen to world space. + // This ensures scaling matrices are correct. + Matrix3x2.Invert(matrix, out Matrix3x2 inverted); + + Matrix3x2 translationToTargetCenter = Matrix3x2.CreateTranslation(new Vector2(-destinationRectangle.Width, -destinationRectangle.Height) * .5F); + Matrix3x2 translateToSourceCenter = Matrix3x2.CreateTranslation(new Vector2(sourceRectangle.Width, sourceRectangle.Height) * .5F); // Translate back to world space. Matrix3x2.Invert(translationToTargetCenter * inverted * translateToSourceCenter, out Matrix3x2 centered); @@ -160,7 +231,7 @@ internal static class TransformUtils /// An enumeration that indicates on which corners to taper the rectangle. /// The amount to taper. /// The - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Matrix4x4 CreateTaperMatrix(Size size, TaperSide side, TaperCorner corner, float fraction) { Matrix4x4 matrix = Matrix4x4.Identity; @@ -281,7 +352,7 @@ internal static class TransformUtils /// /// The . /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Rectangle GetTransformedBoundingRectangle(Rectangle rectangle, Matrix3x2 matrix) { Rectangle transformed = GetTransformedRectangle(rectangle, matrix); @@ -303,10 +374,10 @@ internal static class TransformUtils return rectangle; } - var tl = Vector2.Transform(new Vector2(rectangle.Left, rectangle.Top), matrix); - var tr = Vector2.Transform(new Vector2(rectangle.Right, rectangle.Top), matrix); - var bl = Vector2.Transform(new Vector2(rectangle.Left, rectangle.Bottom), matrix); - var br = Vector2.Transform(new Vector2(rectangle.Right, rectangle.Bottom), matrix); + Vector2 tl = Vector2.Transform(new Vector2(rectangle.Left, rectangle.Top), matrix); + Vector2 tr = Vector2.Transform(new Vector2(rectangle.Right, rectangle.Top), matrix); + Vector2 bl = Vector2.Transform(new Vector2(rectangle.Left, rectangle.Bottom), matrix); + Vector2 br = Vector2.Transform(new Vector2(rectangle.Right, rectangle.Bottom), matrix); return GetBoundingRectangle(tl, tr, bl, br); } @@ -341,7 +412,7 @@ internal static class TransformUtils /// /// The . /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Rectangle GetTransformedRectangle(Rectangle rectangle, Matrix4x4 matrix) { if (rectangle.Equals(default) || Matrix4x4.Identity.Equals(matrix)) @@ -365,7 +436,7 @@ internal static class TransformUtils /// /// The . /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Size GetTransformedSize(Size size, Matrix4x4 matrix) { Guard.IsTrue(size.Width > 0 && size.Height > 0, nameof(size), "Source size dimensions cannot be 0!"); @@ -380,7 +451,7 @@ internal static class TransformUtils return ConstrainSize(rectangle); } - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] private static Size ConstrainSize(Rectangle rectangle) { // We want to resize the canvas here taking into account any translations. @@ -402,7 +473,7 @@ internal static class TransformUtils return new Size(width, height); } - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] private static Rectangle GetBoundingRectangle(Vector2 tl, Vector2 tr, Vector2 bl, Vector2 br) { // Find the minimum and maximum "corners" based on the given vectors diff --git a/src/ImageSharp/Processing/ProjectiveTransformBuilder.cs b/src/ImageSharp/Processing/ProjectiveTransformBuilder.cs index ad0888ad77..0387adebb9 100644 --- a/src/ImageSharp/Processing/ProjectiveTransformBuilder.cs +++ b/src/ImageSharp/Processing/ProjectiveTransformBuilder.cs @@ -11,7 +11,8 @@ namespace SixLabors.ImageSharp.Processing; /// public class ProjectiveTransformBuilder { - private readonly List> matrixFactories = new(); + private readonly List> transformMatrixFactories = new(); + private readonly List> boundsMatrixFactories = new(); /// /// Prepends a matrix that performs a tapering projective transform. @@ -21,7 +22,9 @@ public class ProjectiveTransformBuilder /// The amount to taper. /// The . public ProjectiveTransformBuilder PrependTaper(TaperSide side, TaperCorner corner, float fraction) - => this.Prepend(size => TransformUtils.CreateTaperMatrix(size, side, corner, fraction)); + => this.Prepend( + size => TransformUtils.CreateTaperMatrix(size, side, corner, fraction), + size => TransformUtils.CreateTaperMatrix(size, side, corner, fraction)); /// /// Appends a matrix that performs a tapering projective transform. @@ -31,7 +34,9 @@ public class ProjectiveTransformBuilder /// The amount to taper. /// The . public ProjectiveTransformBuilder AppendTaper(TaperSide side, TaperCorner corner, float fraction) - => this.Append(size => TransformUtils.CreateTaperMatrix(size, side, corner, fraction)); + => this.Append( + size => TransformUtils.CreateTaperMatrix(size, side, corner, fraction), + size => TransformUtils.CreateTaperMatrix(size, side, corner, fraction)); /// /// Prepends a centered rotation matrix using the given rotation in degrees. @@ -47,7 +52,9 @@ public class ProjectiveTransformBuilder /// The amount of rotation, in radians. /// The . public ProjectiveTransformBuilder PrependRotationRadians(float radians) - => this.Prepend(size => new Matrix4x4(TransformUtils.CreateRotationMatrixRadians(radians, size))); + => this.Prepend( + size => new Matrix4x4(TransformUtils.CreateRotationTransformMatrixRadians(radians, size)), + size => new Matrix4x4(TransformUtils.CreateRotationBoundsMatrixRadians(radians, size))); /// /// Prepends a centered rotation matrix using the given rotation in degrees at the given origin. @@ -81,7 +88,9 @@ public class ProjectiveTransformBuilder /// The amount of rotation, in radians. /// The . public ProjectiveTransformBuilder AppendRotationRadians(float radians) - => this.Append(size => new Matrix4x4(TransformUtils.CreateRotationMatrixRadians(radians, size))); + => this.Append( + size => new Matrix4x4(TransformUtils.CreateRotationTransformMatrixRadians(radians, size)), + size => new Matrix4x4(TransformUtils.CreateRotationBoundsMatrixRadians(radians, size))); /// /// Appends a centered rotation matrix using the given rotation in degrees at the given origin. @@ -165,7 +174,9 @@ public class ProjectiveTransformBuilder /// The Y angle, in radians. /// The . public ProjectiveTransformBuilder PrependSkewRadians(float radiansX, float radiansY) - => this.Prepend(size => new Matrix4x4(TransformUtils.CreateSkewMatrixRadians(radiansX, radiansY, size))); + => this.Prepend( + size => new Matrix4x4(TransformUtils.CreateSkewTransformMatrixRadians(radiansX, radiansY, size)), + size => new Matrix4x4(TransformUtils.CreateSkewBoundsMatrixRadians(radiansX, radiansY, size))); /// /// Prepends a skew matrix using the given angles in degrees at the given origin. @@ -203,7 +214,9 @@ public class ProjectiveTransformBuilder /// The Y angle, in radians. /// The . public ProjectiveTransformBuilder AppendSkewRadians(float radiansX, float radiansY) - => this.Append(size => new Matrix4x4(TransformUtils.CreateSkewMatrixRadians(radiansX, radiansY, size))); + => this.Append( + size => new Matrix4x4(TransformUtils.CreateSkewTransformMatrixRadians(radiansX, radiansY, size)), + size => new Matrix4x4(TransformUtils.CreateSkewBoundsMatrixRadians(radiansX, radiansY, size))); /// /// Appends a skew matrix using the given angles in degrees at the given origin. @@ -270,7 +283,7 @@ public class ProjectiveTransformBuilder public ProjectiveTransformBuilder PrependMatrix(Matrix4x4 matrix) { CheckDegenerate(matrix); - return this.Prepend(_ => matrix); + return this.Prepend(_ => matrix, _ => matrix); } /// @@ -286,7 +299,7 @@ public class ProjectiveTransformBuilder public ProjectiveTransformBuilder AppendMatrix(Matrix4x4 matrix) { CheckDegenerate(matrix); - return this.Append(_ => matrix); + return this.Append(_ => matrix, _ => matrix); } /// @@ -317,7 +330,7 @@ public class ProjectiveTransformBuilder Size size = sourceRectangle.Size; - foreach (Func factory in this.matrixFactories) + foreach (Func factory in this.transformMatrixFactories) { matrix *= factory(size); } @@ -327,6 +340,32 @@ public class ProjectiveTransformBuilder return matrix; } + /// + /// Returns the size of a rectangle large enough to contain the transformed source rectangle. + /// + /// The rectangle in the source image. + /// + /// The resultant matrix is degenerate containing one or more values equivalent + /// to or a zero determinant and therefore cannot be used + /// for linear transforms. + /// + /// The . + public Size GetTransformedSize(Rectangle sourceRectangle) + { + Size size = sourceRectangle.Size; + + // Translate the origin matrix to cater for source rectangle offsets. + Matrix4x4 matrix = Matrix4x4.CreateTranslation(new Vector3(-sourceRectangle.Location, 0)); + + foreach (Func factory in this.boundsMatrixFactories) + { + matrix *= factory(size); + CheckDegenerate(matrix); + } + + return TransformUtils.GetTransformedSize(size, matrix); + } + private static void CheckDegenerate(Matrix4x4 matrix) { if (TransformUtils.IsDegenerate(matrix)) @@ -335,15 +374,17 @@ public class ProjectiveTransformBuilder } } - private ProjectiveTransformBuilder Prepend(Func factory) + private ProjectiveTransformBuilder Prepend(Func transformFactory, Func boundsFactory) { - this.matrixFactories.Insert(0, factory); + this.transformMatrixFactories.Insert(0, transformFactory); + this.boundsMatrixFactories.Insert(0, boundsFactory); return this; } - private ProjectiveTransformBuilder Append(Func factory) + private ProjectiveTransformBuilder Append(Func transformFactory, Func boundsFactory) { - this.matrixFactories.Add(factory); + this.transformMatrixFactories.Add(transformFactory); + this.boundsMatrixFactories.Add(boundsFactory); return this; } } diff --git a/tests/ImageSharp.Benchmarks/Color/ColorEquality.cs b/tests/ImageSharp.Benchmarks/Color/ColorEquality.cs index 1ff8013b28..5166c89a93 100644 --- a/tests/ImageSharp.Benchmarks/Color/ColorEquality.cs +++ b/tests/ImageSharp.Benchmarks/Color/ColorEquality.cs @@ -1,25 +1,19 @@ -// Copyright (c) Six Labors. +// Copyright (c) Six Labors. // Licensed under the Six Labors Split License. using BenchmarkDotNet.Attributes; - using SixLabors.ImageSharp.PixelFormats; +using SystemColor = System.Drawing.Color; namespace SixLabors.ImageSharp.Benchmarks; -using SystemColor = System.Drawing.Color; - public class ColorEquality { [Benchmark(Baseline = true, Description = "System.Drawing Color Equals")] public bool SystemDrawingColorEqual() - { - return SystemColor.FromArgb(128, 128, 128, 128).Equals(SystemColor.FromArgb(128, 128, 128, 128)); - } + => SystemColor.FromArgb(128, 128, 128, 128).Equals(SystemColor.FromArgb(128, 128, 128, 128)); [Benchmark(Description = "ImageSharp Color Equals")] public bool ColorEqual() - { - return new Rgba32(128, 128, 128, 128).Equals(new Rgba32(128, 128, 128, 128)); - } + => new Rgba32(128, 128, 128, 128).Equals(new Rgba32(128, 128, 128, 128)); } diff --git a/tests/ImageSharp.Benchmarks/Color/ColorspaceCieXyzToCieLabConvert.cs b/tests/ImageSharp.Benchmarks/Color/ColorspaceCieXyzToCieLabConvert.cs index da09a85232..1f8a6b1933 100644 --- a/tests/ImageSharp.Benchmarks/Color/ColorspaceCieXyzToCieLabConvert.cs +++ b/tests/ImageSharp.Benchmarks/Color/ColorspaceCieXyzToCieLabConvert.cs @@ -2,34 +2,25 @@ // Licensed under the Six Labors Split License. using BenchmarkDotNet.Attributes; - using Colourful; - -using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion; +using SixLabors.ImageSharp.ColorProfiles; using Illuminants = Colourful.Illuminants; -namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces; +namespace SixLabors.ImageSharp.Benchmarks.ColorProfiles; public class ColorspaceCieXyzToCieLabConvert { - private static readonly CieXyz CieXyz = new CieXyz(0.95047F, 1, 1.08883F); + private static readonly CieXyz CieXyz = new(0.95047F, 1, 1.08883F); - private static readonly XYZColor XYZColor = new XYZColor(0.95047, 1, 1.08883); + private static readonly XYZColor XYZColor = new(0.95047, 1, 1.08883); - private static readonly ColorSpaceConverter ColorSpaceConverter = new ColorSpaceConverter(); + private static readonly ColorProfileConverter ColorProfileConverter = new(); private static readonly IColorConverter ColourfulConverter = new ConverterBuilder().FromXYZ(Illuminants.D50).ToLab(Illuminants.D50).Build(); [Benchmark(Baseline = true, Description = "Colourful Convert")] - public double ColourfulConvert() - { - return ColourfulConverter.Convert(XYZColor).L; - } + public double ColourfulConvert() => ColourfulConverter.Convert(XYZColor).L; [Benchmark(Description = "ImageSharp Convert")] - public float ColorSpaceConvert() - { - return ColorSpaceConverter.ToCieLab(CieXyz).L; - } + public float ColorSpaceConvert() => ColorProfileConverter.Convert(CieXyz).L; } diff --git a/tests/ImageSharp.Benchmarks/Color/ColorspaceCieXyzToHunterLabConvert.cs b/tests/ImageSharp.Benchmarks/Color/ColorspaceCieXyzToHunterLabConvert.cs index c3317c5d94..b11e788193 100644 --- a/tests/ImageSharp.Benchmarks/Color/ColorspaceCieXyzToHunterLabConvert.cs +++ b/tests/ImageSharp.Benchmarks/Color/ColorspaceCieXyzToHunterLabConvert.cs @@ -2,34 +2,25 @@ // Licensed under the Six Labors Split License. using BenchmarkDotNet.Attributes; - using Colourful; - -using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion; +using SixLabors.ImageSharp.ColorProfiles; using Illuminants = Colourful.Illuminants; -namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces; +namespace SixLabors.ImageSharp.Benchmarks.ColorProfiles; public class ColorspaceCieXyzToHunterLabConvert { - private static readonly CieXyz CieXyz = new CieXyz(0.95047F, 1, 1.08883F); + private static readonly CieXyz CieXyz = new(0.95047F, 1, 1.08883F); - private static readonly XYZColor XYZColor = new XYZColor(0.95047, 1, 1.08883); + private static readonly XYZColor XYZColor = new(0.95047, 1, 1.08883); - private static readonly ColorSpaceConverter ColorSpaceConverter = new ColorSpaceConverter(); + private static readonly ColorProfileConverter ColorProfileConverter = new(); private static readonly IColorConverter ColourfulConverter = new ConverterBuilder().FromXYZ(Illuminants.C).ToHunterLab(Illuminants.C).Build(); [Benchmark(Baseline = true, Description = "Colourful Convert")] - public double ColourfulConvert() - { - return ColourfulConverter.Convert(XYZColor).L; - } + public double ColourfulConvert() => ColourfulConverter.Convert(XYZColor).L; [Benchmark(Description = "ImageSharp Convert")] - public float ColorSpaceConvert() - { - return ColorSpaceConverter.ToHunterLab(CieXyz).L; - } + public float ColorSpaceConvert() => ColorProfileConverter.Convert(CieXyz).L; } diff --git a/tests/ImageSharp.Benchmarks/Color/ColorspaceCieXyzToLmsConvert.cs b/tests/ImageSharp.Benchmarks/Color/ColorspaceCieXyzToLmsConvert.cs index ba213e5b0a..a2c7966d41 100644 --- a/tests/ImageSharp.Benchmarks/Color/ColorspaceCieXyzToLmsConvert.cs +++ b/tests/ImageSharp.Benchmarks/Color/ColorspaceCieXyzToLmsConvert.cs @@ -2,33 +2,24 @@ // Licensed under the Six Labors Split License. using BenchmarkDotNet.Attributes; - using Colourful; +using SixLabors.ImageSharp.ColorProfiles; -using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion; - -namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces; +namespace SixLabors.ImageSharp.Benchmarks.ColorProfiles; public class ColorspaceCieXyzToLmsConvert { - private static readonly CieXyz CieXyz = new CieXyz(0.95047F, 1, 1.08883F); + private static readonly CieXyz CieXyz = new(0.95047F, 1, 1.08883F); - private static readonly XYZColor XYZColor = new XYZColor(0.95047, 1, 1.08883); + private static readonly XYZColor XYZColor = new(0.95047, 1, 1.08883); - private static readonly ColorSpaceConverter ColorSpaceConverter = new ColorSpaceConverter(); + private static readonly ColorProfileConverter ColorProfileConverter = new(); private static readonly IColorConverter ColourfulConverter = new ConverterBuilder().FromXYZ().ToLMS().Build(); [Benchmark(Baseline = true, Description = "Colourful Convert")] - public double ColourfulConvert() - { - return ColourfulConverter.Convert(XYZColor).L; - } + public double ColourfulConvert() => ColourfulConverter.Convert(XYZColor).L; [Benchmark(Description = "ImageSharp Convert")] - public float ColorSpaceConvert() - { - return ColorSpaceConverter.ToLms(CieXyz).L; - } + public float ColorSpaceConvert() => ColorProfileConverter.Convert(CieXyz).L; } diff --git a/tests/ImageSharp.Benchmarks/Color/ColorspaceCieXyzToRgbConvert.cs b/tests/ImageSharp.Benchmarks/Color/ColorspaceCieXyzToRgbConvert.cs index d7a5deafa7..b63f925046 100644 --- a/tests/ImageSharp.Benchmarks/Color/ColorspaceCieXyzToRgbConvert.cs +++ b/tests/ImageSharp.Benchmarks/Color/ColorspaceCieXyzToRgbConvert.cs @@ -2,33 +2,24 @@ // Licensed under the Six Labors Split License. using BenchmarkDotNet.Attributes; - using Colourful; +using SixLabors.ImageSharp.ColorProfiles; -using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion; - -namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces; +namespace SixLabors.ImageSharp.Benchmarks.ColorProfiles; public class ColorspaceCieXyzToRgbConvert { - private static readonly CieXyz CieXyz = new CieXyz(0.95047F, 1, 1.08883F); + private static readonly CieXyz CieXyz = new(0.95047F, 1, 1.08883F); - private static readonly XYZColor XYZColor = new XYZColor(0.95047, 1, 1.08883); + private static readonly XYZColor XYZColor = new(0.95047, 1, 1.08883); - private static readonly ColorSpaceConverter ColorSpaceConverter = new ColorSpaceConverter(); + private static readonly ColorProfileConverter ColorProfileConverter = new(); private static readonly IColorConverter ColourfulConverter = new ConverterBuilder().FromXYZ(RGBWorkingSpaces.sRGB.WhitePoint).ToRGB(RGBWorkingSpaces.sRGB).Build(); [Benchmark(Baseline = true, Description = "Colourful Convert")] - public double ColourfulConvert() - { - return ColourfulConverter.Convert(XYZColor).R; - } + public double ColourfulConvert() => ColourfulConverter.Convert(XYZColor).R; [Benchmark(Description = "ImageSharp Convert")] - public float ColorSpaceConvert() - { - return ColorSpaceConverter.ToRgb(CieXyz).R; - } + public float ColorSpaceConvert() => ColorProfileConverter.Convert(CieXyz).R; } diff --git a/tests/ImageSharp.Benchmarks/Color/RgbWorkingSpaceAdapt.cs b/tests/ImageSharp.Benchmarks/Color/RgbWorkingSpaceAdapt.cs index 48b4880d94..6cd8df3fc7 100644 --- a/tests/ImageSharp.Benchmarks/Color/RgbWorkingSpaceAdapt.cs +++ b/tests/ImageSharp.Benchmarks/Color/RgbWorkingSpaceAdapt.cs @@ -2,33 +2,24 @@ // Licensed under the Six Labors Split License. using BenchmarkDotNet.Attributes; - using Colourful; +using SixLabors.ImageSharp.ColorProfiles; -using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion; - -namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces; +namespace SixLabors.ImageSharp.Benchmarks.ColorProfiles; public class RgbWorkingSpaceAdapt { - private static readonly Rgb Rgb = new Rgb(0.206162F, 0.260277F, 0.746717F, RgbWorkingSpaces.WideGamutRgb); + private static readonly Rgb Rgb = new(0.206162F, 0.260277F, 0.746717F); - private static readonly RGBColor RGBColor = new RGBColor(0.206162, 0.260277, 0.746717); + private static readonly RGBColor RGBColor = new(0.206162, 0.260277, 0.746717); - private static readonly ColorSpaceConverter ColorSpaceConverter = new ColorSpaceConverter(new ColorSpaceConverterOptions { TargetRgbWorkingSpace = RgbWorkingSpaces.SRgb }); + private static readonly ColorProfileConverter ColorProfileConverter = new(new ColorConversionOptions { RgbWorkingSpace = KnownRgbWorkingSpaces.WideGamutRgb, TargetRgbWorkingSpace = KnownRgbWorkingSpaces.SRgb }); private static readonly IColorConverter ColourfulConverter = new ConverterBuilder().FromRGB(RGBWorkingSpaces.WideGamutRGB).ToRGB(RGBWorkingSpaces.sRGB).Build(); [Benchmark(Baseline = true, Description = "Colourful Adapt")] - public RGBColor ColourfulConvert() - { - return ColourfulConverter.Convert(RGBColor); - } + public RGBColor ColourfulConvert() => ColourfulConverter.Convert(RGBColor); [Benchmark(Description = "ImageSharp Adapt")] - public Rgb ColorSpaceConvert() - { - return ColorSpaceConverter.Adapt(Rgb); - } + public Rgb ColorSpaceConvert() => ColorProfileConverter.Convert(Rgb); } diff --git a/tests/ImageSharp.Benchmarks/Color/YcbCrToRgb.cs b/tests/ImageSharp.Benchmarks/Color/YcbCrToRgb.cs index 14d848bcb7..093397ad5f 100644 --- a/tests/ImageSharp.Benchmarks/Color/YcbCrToRgb.cs +++ b/tests/ImageSharp.Benchmarks/Color/YcbCrToRgb.cs @@ -11,9 +11,9 @@ public class YcbCrToRgb [Benchmark(Baseline = true, Description = "Floating Point Conversion")] public Vector3 YcbCrToRgba() { - int y = 255; - int cb = 128; - int cr = 128; + const int y = 255; + const int cb = 128; + const int cr = 128; int ccb = cb - 128; int ccr = cr - 128; @@ -28,9 +28,9 @@ public class YcbCrToRgb [Benchmark(Description = "Scaled Integer Conversion")] public Vector3 YcbCrToRgbaScaled() { - int y = 255; - int cb = 128; - int cr = 128; + const int y = 255; + const int cb = 128; + const int cr = 128; int ccb = cb - 128; int ccr = cr - 128; diff --git a/tests/ImageSharp.Tests/ColorProfiles/ApproximateColorProfileComparer.cs b/tests/ImageSharp.Tests/ColorProfiles/ApproximateColorProfileComparer.cs new file mode 100644 index 0000000000..56d495a87a --- /dev/null +++ b/tests/ImageSharp.Tests/ColorProfiles/ApproximateColorProfileComparer.cs @@ -0,0 +1,92 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using System.Diagnostics.CodeAnalysis; +using SixLabors.ImageSharp.ColorProfiles; + +namespace SixLabors.ImageSharp.Tests.ColorProfiles; + +/// +/// Allows the approximate comparison of color profile component values. +/// +internal readonly struct ApproximateColorProfileComparer : + IEqualityComparer, + IEqualityComparer, + IEqualityComparer, + IEqualityComparer, + IEqualityComparer, + IEqualityComparer, + IEqualityComparer, + IEqualityComparer, + IEqualityComparer, + IEqualityComparer, + IEqualityComparer, + IEqualityComparer, + IEqualityComparer +{ + private readonly float epsilon; + + /// + /// Initializes a new instance of the struct. + /// + /// The comparison error difference epsilon to use. + public ApproximateColorProfileComparer(float epsilon = 1f) => this.epsilon = epsilon; + + public bool Equals(CieLab x, CieLab y) => this.Equals(x.L, y.L) && this.Equals(x.A, y.A) && this.Equals(x.B, y.B); + + public bool Equals(CieXyz x, CieXyz y) => this.Equals(x.X, y.X) && this.Equals(x.Y, y.Y) && this.Equals(x.Z, y.Z); + + public bool Equals(Lms x, Lms y) => this.Equals(x.L, y.L) && this.Equals(x.M, y.M) && this.Equals(x.S, y.S); + + public bool Equals(CieLch x, CieLch y) => this.Equals(x.L, y.L) && this.Equals(x.C, y.C) && this.Equals(x.H, y.H); + + public bool Equals(Rgb x, Rgb y) => this.Equals(x.R, y.R) && this.Equals(x.G, y.G) && this.Equals(x.B, y.B); + + public bool Equals(YCbCr x, YCbCr y) => this.Equals(x.Y, y.Y) && this.Equals(x.Cb, y.Cb) && this.Equals(x.Cr, y.Cr); + + public bool Equals(CieLchuv x, CieLchuv y) => this.Equals(x.L, y.L) && this.Equals(x.C, y.C) && this.Equals(x.H, y.H); + + public bool Equals(CieLuv x, CieLuv y) => this.Equals(x.L, y.L) && this.Equals(x.U, y.U) && this.Equals(x.V, y.V); + + public bool Equals(CieXyy x, CieXyy y) => this.Equals(x.X, y.X) && this.Equals(x.Y, y.Y) && this.Equals(x.Yl, y.Yl); + + public bool Equals(Cmyk x, Cmyk y) => this.Equals(x.C, y.C) && this.Equals(x.M, y.M) && this.Equals(x.Y, y.Y) && this.Equals(x.K, y.K); + + public bool Equals(Hsl x, Hsl y) => this.Equals(x.H, y.H) && this.Equals(x.S, y.S) && this.Equals(x.L, y.L); + + public bool Equals(Hsv x, Hsv y) => this.Equals(x.H, y.H) && this.Equals(x.S, y.S) && this.Equals(x.V, y.V); + + public bool Equals(HunterLab x, HunterLab y) => this.Equals(x.L, y.L) && this.Equals(x.A, y.A) && this.Equals(x.B, y.B); + + public int GetHashCode([DisallowNull] CieLab obj) => obj.GetHashCode(); + + public int GetHashCode([DisallowNull] CieXyz obj) => obj.GetHashCode(); + + public int GetHashCode([DisallowNull] Lms obj) => obj.GetHashCode(); + + public int GetHashCode([DisallowNull] CieLch obj) => obj.GetHashCode(); + + public int GetHashCode([DisallowNull] Rgb obj) => obj.GetHashCode(); + + public int GetHashCode([DisallowNull] YCbCr obj) => obj.GetHashCode(); + + public int GetHashCode([DisallowNull] CieLchuv obj) => obj.GetHashCode(); + + public int GetHashCode([DisallowNull] CieLuv obj) => obj.GetHashCode(); + + public int GetHashCode([DisallowNull] CieXyy obj) => obj.GetHashCode(); + + public int GetHashCode([DisallowNull] Cmyk obj) => obj.GetHashCode(); + + public int GetHashCode([DisallowNull] Hsl obj) => obj.GetHashCode(); + + public int GetHashCode([DisallowNull] Hsv obj) => obj.GetHashCode(); + + public int GetHashCode([DisallowNull] HunterLab obj) => obj.GetHashCode(); + + private bool Equals(float x, float y) + { + float d = x - y; + return d >= -this.epsilon && d <= this.epsilon; + } +} diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndCieLchConversionTests.cs b/tests/ImageSharp.Tests/ColorProfiles/CieLabAndCieLchConversionTests.cs similarity index 61% rename from tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndCieLchConversionTests.cs rename to tests/ImageSharp.Tests/ColorProfiles/CieLabAndCieLchConversionTests.cs index d71f0fa5e0..9a894c7760 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndCieLchConversionTests.cs +++ b/tests/ImageSharp.Tests/ColorProfiles/CieLabAndCieLchConversionTests.cs @@ -1,10 +1,9 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion; +using SixLabors.ImageSharp.ColorProfiles; -namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion; +namespace SixLabors.ImageSharp.Tests.ColorProfiles; /// /// Tests - conversions. @@ -15,12 +14,8 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion; /// public class CieLabAndCieLchConversionTests { - private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0001F); - private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); + private static readonly ApproximateColorProfileComparer Comparer = new(.0001f); - /// - /// Tests conversion from to . - /// [Theory] [InlineData(0, 0, 0, 0, 0, 0)] [InlineData(54.2917, 106.8391, 40.8526, 54.2917, 80.8125, 69.8851)] @@ -33,8 +28,10 @@ public class CieLabAndCieLchConversionTests public void Convert_Lch_to_Lab(float l, float c, float h, float l2, float a, float b) { // Arrange - var input = new CieLch(l, c, h); - var expected = new CieLab(l2, a, b); + CieLch input = new(l, c, h); + CieLab expected = new(l2, a, b); + ColorConversionOptions options = new() { WhitePoint = KnownIlluminants.D50, TargetWhitePoint = KnownIlluminants.D50 }; + ColorProfileConverter converter = new(options); Span inputSpan = new CieLch[5]; inputSpan.Fill(input); @@ -42,21 +39,18 @@ public class CieLabAndCieLchConversionTests Span actualSpan = new CieLab[5]; // Act - var actual = Converter.ToCieLab(input); - Converter.Convert(inputSpan, actualSpan); + CieLab actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); + Assert.Equal(expected, actual, Comparer); for (int i = 0; i < actualSpan.Length; i++) { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); + Assert.Equal(expected, actualSpan[i], Comparer); } } - /// - /// Tests conversion from to . - /// [Theory] [InlineData(0, 0, 0, 0, 0, 0)] [InlineData(54.2917, 80.8125, 69.8851, 54.2917, 106.8391, 40.8526)] @@ -69,8 +63,10 @@ public class CieLabAndCieLchConversionTests public void Convert_Lab_to_Lch(float l, float a, float b, float l2, float c, float h) { // Arrange - var input = new CieLab(l, a, b); - var expected = new CieLch(l2, c, h); + CieLab input = new(l, a, b); + CieLch expected = new(l2, c, h); + ColorConversionOptions options = new() { WhitePoint = KnownIlluminants.D50, TargetWhitePoint = KnownIlluminants.D50 }; + ColorProfileConverter converter = new(options); Span inputSpan = new CieLab[5]; inputSpan.Fill(input); @@ -78,15 +74,15 @@ public class CieLabAndCieLchConversionTests Span actualSpan = new CieLch[5]; // Act - var actual = Converter.ToCieLch(input); - Converter.Convert(inputSpan, actualSpan); + CieLch actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); + Assert.Equal(expected, actual, Comparer); for (int i = 0; i < actualSpan.Length; i++) { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); + Assert.Equal(expected, actualSpan[i], Comparer); } } } diff --git a/tests/ImageSharp.Tests/ColorProfiles/CieLabAndCieLchuvConversionTests.cs b/tests/ImageSharp.Tests/ColorProfiles/CieLabAndCieLchuvConversionTests.cs new file mode 100644 index 0000000000..4b1b5e1a56 --- /dev/null +++ b/tests/ImageSharp.Tests/ColorProfiles/CieLabAndCieLchuvConversionTests.cs @@ -0,0 +1,76 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using SixLabors.ImageSharp.ColorProfiles; + +namespace SixLabors.ImageSharp.Tests.ColorProfiles; + +/// +/// Tests - conversions. +/// +/// +/// Test data generated using: +/// +/// +public class CieLabAndCieLchuvConversionTests +{ + private static readonly ApproximateColorProfileComparer Comparer = new(.0002F); + + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(30.66194, 200, 352.7564, 31.95653, 116.8745, 2.388602)] + public void Convert_Lchuv_To_Lab(float l, float c, float h, float l2, float a, float b) + { + // Arrange + CieLchuv input = new(l, c, h); + CieLab expected = new(l2, a, b); + ColorConversionOptions options = new() { WhitePoint = KnownIlluminants.D65, TargetWhitePoint = KnownIlluminants.D50 }; + ColorProfileConverter converter = new(options); + + Span inputSpan = new CieLchuv[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieLab[5]; + + // Act + CieLab actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } + + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(36.0555, 303.6901, 10.01514, 29.4713573, 200, 352.6346)] + public void Convert_Lab_To_Lchuv(float l, float a, float b, float l2, float c, float h) + { + // Arrange + CieLab input = new(l, a, b); + CieLchuv expected = new(l2, c, h); + ColorConversionOptions options = new() { WhitePoint = KnownIlluminants.D50, TargetWhitePoint = KnownIlluminants.D65 }; + ColorProfileConverter converter = new(options); + + Span inputSpan = new CieLab[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieLchuv[5]; + + // Act + CieLchuv actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } +} diff --git a/tests/ImageSharp.Tests/ColorProfiles/CieLabAndCieLuvConversionTests.cs b/tests/ImageSharp.Tests/ColorProfiles/CieLabAndCieLuvConversionTests.cs new file mode 100644 index 0000000000..44756c779a --- /dev/null +++ b/tests/ImageSharp.Tests/ColorProfiles/CieLabAndCieLuvConversionTests.cs @@ -0,0 +1,76 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using SixLabors.ImageSharp.ColorProfiles; + +namespace SixLabors.ImageSharp.Tests.ColorProfiles; + +/// +/// Tests - conversions. +/// +/// +/// Test data generated using: +/// +/// +public class CieLabAndCieLuvConversionTests +{ + private static readonly ApproximateColorProfileComparer Comparer = new(.0002F); + + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(10, 36.0555, 303.6901, 10.6006718, -17.24077, 82.8835)] + public void Convert_CieLuv_To_CieLab(float l, float u, float v, float l2, float a, float b) + { + // Arrange + CieLuv input = new(l, u, v); + CieLab expected = new(l2, a, b); + ColorConversionOptions options = new() { WhitePoint = KnownIlluminants.D65, TargetWhitePoint = KnownIlluminants.D50 }; + ColorProfileConverter converter = new(options); + + Span inputSpan = new CieLuv[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieLab[5]; + + // Act + CieLab actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } + + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(10.0151367, -23.9644356, 17.0226, 10.0000038, -12.830183, 15.1829338)] + public void Convert_CieLab_To_CieLuv(float l, float a, float b, float l2, float u, float v) + { + // Arrange + CieLab input = new(l, a, b); + CieLuv expected = new(l2, u, v); + ColorConversionOptions options = new() { WhitePoint = KnownIlluminants.D50, TargetWhitePoint = KnownIlluminants.D65 }; + ColorProfileConverter converter = new(options); + + Span inputSpan = new CieLab[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieLuv[5]; + + // Act + CieLuv actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } +} diff --git a/tests/ImageSharp.Tests/ColorProfiles/CieLabAndCieXyyConversionTests.cs b/tests/ImageSharp.Tests/ColorProfiles/CieLabAndCieXyyConversionTests.cs new file mode 100644 index 0000000000..a464eeca11 --- /dev/null +++ b/tests/ImageSharp.Tests/ColorProfiles/CieLabAndCieXyyConversionTests.cs @@ -0,0 +1,70 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using SixLabors.ImageSharp.ColorProfiles; + +namespace SixLabors.ImageSharp.Tests.ColorProfiles; + +/// +/// Tests - conversions. +/// +public class CieLabAndCieXyyConversionTests +{ + private static readonly ApproximateColorProfileComparer Comparer = new(.0002F); + + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(0.8644734, 0.06098868, 0.06509002, 30.6619, 291.5721, -11.2526)] + public void Convert_CieXyy_To_CieLab(float x, float y, float yl, float l, float a, float b) + { + // Arrange + CieXyy input = new(x, y, yl); + CieLab expected = new(l, a, b); + ColorProfileConverter converter = new(); + + Span inputSpan = new CieXyy[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieLab[5]; + + // Act + CieLab actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } + + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(30.6619, 291.5721, -11.2526, 0.8644734, 0.06098868, 0.06509002)] + public void Convert_CieLab_To_CieXyy(float l, float a, float b, float x, float y, float yl) + { + // Arrange + CieLab input = new(l, a, b); + CieXyy expected = new(x, y, yl); + ColorProfileConverter converter = new(); + + Span inputSpan = new CieLab[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieXyy[5]; + + // Act + CieXyy actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } +} diff --git a/tests/ImageSharp.Tests/ColorProfiles/CieLabAndCmykConversionTests.cs b/tests/ImageSharp.Tests/ColorProfiles/CieLabAndCmykConversionTests.cs new file mode 100644 index 0000000000..746671c4a7 --- /dev/null +++ b/tests/ImageSharp.Tests/ColorProfiles/CieLabAndCmykConversionTests.cs @@ -0,0 +1,70 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using SixLabors.ImageSharp.ColorProfiles; + +namespace SixLabors.ImageSharp.Tests.ColorProfiles; + +/// +/// Tests - conversions. +/// +public class CieLabAndCmykConversionTests +{ + private static readonly ApproximateColorProfileComparer Comparer = new(.0002F); + + [Theory] + [InlineData(0, 0, 0, 1, 0, 0, 0)] + [InlineData(0, 1, 0.6156551, 5.960464E-08, 55.063, 82.54871, 23.16506)] + public void Convert_Cmyk_to_CieLab(float c, float m, float y, float k, float l, float a, float b) + { + // Arrange + Cmyk input = new(c, m, y, k); + CieLab expected = new(l, a, b); + ColorProfileConverter converter = new(); + + Span inputSpan = new Cmyk[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieLab[5]; + + // Act + CieLab actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } + + [Theory] + [InlineData(0, 0, 0, 0, 0, 0, 1)] + [InlineData(36.0555, 303.6901, 10.01514, 0, 1, 0.597665966, 0)] + public void Convert_CieLab_to_Cmyk(float l, float a, float b, float c, float m, float y, float k) + { + // Arrange + CieLab input = new(l, a, b); + Cmyk expected = new(c, m, y, k); + ColorProfileConverter converter = new(); + + Span inputSpan = new CieLab[5]; + inputSpan.Fill(input); + + Span actualSpan = new Cmyk[5]; + + // Act + Cmyk actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } +} diff --git a/tests/ImageSharp.Tests/ColorProfiles/CieLabAndHslConversionTests.cs b/tests/ImageSharp.Tests/ColorProfiles/CieLabAndHslConversionTests.cs new file mode 100644 index 0000000000..96779f1896 --- /dev/null +++ b/tests/ImageSharp.Tests/ColorProfiles/CieLabAndHslConversionTests.cs @@ -0,0 +1,70 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using SixLabors.ImageSharp.ColorProfiles; + +namespace SixLabors.ImageSharp.Tests.ColorProfiles; + +/// +/// Tests - conversions. +/// +public class CieLabAndHslConversionTests +{ + private static readonly ApproximateColorProfileComparer Comparer = new(.0002f); + + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(336.9393, 1, 0.5, 55.063, 82.54868, 23.16508)] + public void Convert_Hsl_to_CieLab(float h, float s, float ll, float l, float a, float b) + { + // Arrange + Hsl input = new(h, s, ll); + CieLab expected = new(l, a, b); + ColorProfileConverter converter = new(); + + Span inputSpan = new Hsl[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieLab[5]; + + // Act + CieLab actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } + + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(55.063, 82.54868, 23.16508, 336.9393, 1, 0.5)] + public void Convert_CieLab_to_Hsl(float l, float a, float b, float h, float s, float ll) + { + // Arrange + CieLab input = new(l, a, b); + Hsl expected = new(h, s, ll); + ColorProfileConverter converter = new(); + + Span inputSpan = new CieLab[5]; + inputSpan.Fill(input); + + Span actualSpan = new Hsl[5]; + + // Act + Hsl actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } +} diff --git a/tests/ImageSharp.Tests/ColorProfiles/CieLabAndHsvConversionTests.cs b/tests/ImageSharp.Tests/ColorProfiles/CieLabAndHsvConversionTests.cs new file mode 100644 index 0000000000..3389da9815 --- /dev/null +++ b/tests/ImageSharp.Tests/ColorProfiles/CieLabAndHsvConversionTests.cs @@ -0,0 +1,70 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using SixLabors.ImageSharp.ColorProfiles; + +namespace SixLabors.ImageSharp.Tests.ColorProfiles; + +/// +/// Tests - conversions. +/// +public class CieLabAndHsvConversionTests +{ + private static readonly ApproximateColorProfileComparer Comparer = new(.0002f); + + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(336.9393, 1, 0.9999999, 55.063, 82.54871, 23.16504)] + public void Convert_Hsv_to_CieLab(float h, float s, float v, float l, float a, float b) + { + // Arrange + Hsv input = new(h, s, v); + CieLab expected = new(l, a, b); + ColorProfileConverter converter = new(); + + Span inputSpan = new Hsv[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieLab[5]; + + // Act + CieLab actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } + + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(55.063, 82.54871, 23.16504, 336.9393, 1, 0.9999999)] + public void Convert_CieLab_to_Hsv(float l, float a, float b, float h, float s, float v) + { + // Arrange + CieLab input = new(l, a, b); + Hsv expected = new(h, s, v); + ColorProfileConverter converter = new(); + + Span inputSpan = new CieLab[5]; + inputSpan.Fill(input); + + Span actualSpan = new Hsv[5]; + + // Act + Hsv actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } +} diff --git a/tests/ImageSharp.Tests/ColorProfiles/CieLabAndHunterLabConversionTests.cs b/tests/ImageSharp.Tests/ColorProfiles/CieLabAndHunterLabConversionTests.cs new file mode 100644 index 0000000000..1054d537ac --- /dev/null +++ b/tests/ImageSharp.Tests/ColorProfiles/CieLabAndHunterLabConversionTests.cs @@ -0,0 +1,70 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using SixLabors.ImageSharp.ColorProfiles; + +namespace SixLabors.ImageSharp.Tests.ColorProfiles; + +/// +/// Tests - conversions. +/// +public class CieLabAndHunterLabConversionTests +{ + private static readonly ApproximateColorProfileComparer Comparer = new(.0002f); + + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(27.51646, 556.9392, -0.03974226, 33.074177, 281.48329, -0.06948)] + public void Convert_HunterLab_to_CieLab(float l2, float a2, float b2, float l, float a, float b) + { + // Arrange + HunterLab input = new(l2, a2, b2); + CieLab expected = new(l, a, b); + ColorProfileConverter converter = new(); + + Span inputSpan = new HunterLab[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieLab[5]; + + // Act + CieLab actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } + + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(33.074177, 281.48329, -0.06948, 27.51646, 556.9392, -0.03974226)] + public void Convert_CieLab_to_HunterLab(float l, float a, float b, float l2, float a2, float b2) + { + // Arrange + CieLab input = new(l, a, b); + HunterLab expected = new(l2, a2, b2); + ColorProfileConverter converter = new(); + + Span inputSpan = new CieLab[5]; + inputSpan.Fill(input); + + Span actualSpan = new HunterLab[5]; + + // Act + HunterLab actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } +} diff --git a/tests/ImageSharp.Tests/ColorProfiles/CieLabAndLmsConversionTests.cs b/tests/ImageSharp.Tests/ColorProfiles/CieLabAndLmsConversionTests.cs new file mode 100644 index 0000000000..77243268fd --- /dev/null +++ b/tests/ImageSharp.Tests/ColorProfiles/CieLabAndLmsConversionTests.cs @@ -0,0 +1,70 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using SixLabors.ImageSharp.ColorProfiles; + +namespace SixLabors.ImageSharp.Tests.ColorProfiles; + +/// +/// Tests - conversions. +/// +public class CieLabAndLmsConversionTests +{ + private static readonly ApproximateColorProfileComparer Comparer = new(.0002f); + + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(0.8303261, -0.5776886, 0.1133359, 30.66193, 291.57209, -11.25262)] + public void Convert_Lms_to_CieLab(float l2, float m, float s, float l, float a, float b) + { + // Arrange + Lms input = new(l2, m, s); + CieLab expected = new(l, a, b); + ColorProfileConverter converter = new(); + + Span inputSpan = new Lms[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieLab[5]; + + // Act + CieLab actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } + + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(30.66193, 291.57209, -11.25262, 0.8303261, -0.5776886, 0.1133359)] + public void Convert_CieLab_to_Lms(float l, float a, float b, float l2, float m, float s) + { + // Arrange + CieLab input = new(l, a, b); + Lms expected = new(l2, m, s); + ColorProfileConverter converter = new(); + + Span inputSpan = new CieLab[5]; + inputSpan.Fill(input); + + Span actualSpan = new Lms[5]; + + // Act + Lms actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } +} diff --git a/tests/ImageSharp.Tests/ColorProfiles/CieLabAndRgbConversionTests.cs b/tests/ImageSharp.Tests/ColorProfiles/CieLabAndRgbConversionTests.cs new file mode 100644 index 0000000000..0a0453bc62 --- /dev/null +++ b/tests/ImageSharp.Tests/ColorProfiles/CieLabAndRgbConversionTests.cs @@ -0,0 +1,71 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using SixLabors.ImageSharp.ColorProfiles; + +namespace SixLabors.ImageSharp.Tests.ColorProfiles; + +/// +/// Tests - conversions. +/// +public class CieLabAndRgbConversionTests +{ + private static readonly ApproximateColorProfileComparer Comparer = new(.0002F); + private static readonly ColorProfileConverter Converter = new(); + + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(0.9999999, 0, 0.384345, 55.063, 82.54871, 23.16505)] + public void Convert_Rgb_to_CieLab(float r, float g, float b2, float l, float a, float b) + { + // Arrange + Rgb input = new(r, g, b2); + CieLab expected = new(l, a, b); + ColorProfileConverter converter = new(); + + Span inputSpan = new Rgb[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieLab[5]; + + // Act + CieLab actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } + + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(55.063, 82.54871, 23.16505, 0.9999999, 0, 0.384345)] + public void Convert_CieLab_to_Rgb(float l, float a, float b, float r, float g, float b2) + { + // Arrange + CieLab input = new(l, a, b); + Rgb expected = new(r, g, b2); + ColorProfileConverter converter = new(); + + Span inputSpan = new CieLab[5]; + inputSpan.Fill(input); + + Span actualSpan = new Rgb[5]; + + // Act + Rgb actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } +} diff --git a/tests/ImageSharp.Tests/ColorProfiles/CieLabAndYCbCrConversionTests.cs b/tests/ImageSharp.Tests/ColorProfiles/CieLabAndYCbCrConversionTests.cs new file mode 100644 index 0000000000..9a29b15398 --- /dev/null +++ b/tests/ImageSharp.Tests/ColorProfiles/CieLabAndYCbCrConversionTests.cs @@ -0,0 +1,70 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using SixLabors.ImageSharp.ColorProfiles; + +namespace SixLabors.ImageSharp.Tests.ColorProfiles; + +/// +/// Tests - conversions. +/// +public class CieLabAndYCbCrConversionTests +{ + private static readonly ApproximateColorProfileComparer Comparer = new(.0002F); + + [Theory] + [InlineData(0, 128, 128, 0, 0, 0)] + [InlineData(87.4179, 133.9763, 247.5308, 55.06287, 82.54838, 23.1697)] + public void Convert_YCbCr_to_CieLab(float y, float cb, float cr, float l, float a, float b) + { + // Arrange + YCbCr input = new(y, cb, cr); + CieLab expected = new(l, a, b); + ColorProfileConverter converter = new(); + + Span inputSpan = new YCbCr[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieLab[5]; + + // Act + CieLab actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } + + [Theory] + [InlineData(0, 0, 0, 0, 128, 128)] + [InlineData(55.06287, 82.54838, 23.1697, 87.41701, 133.97232, 247.5314)] + public void Convert_CieLab_to_YCbCr(float l, float a, float b, float y, float cb, float cr) + { + // Arrange + CieLab input = new(l, a, b); + YCbCr expected = new(y, cb, cr); + ColorProfileConverter converter = new(); + + Span inputSpan = new CieLab[5]; + inputSpan.Fill(input); + + Span actualSpan = new YCbCr[5]; + + // Act + YCbCr actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } +} diff --git a/tests/ImageSharp.Tests/Colorspaces/CieLabTests.cs b/tests/ImageSharp.Tests/ColorProfiles/CieLabTests.cs similarity index 61% rename from tests/ImageSharp.Tests/Colorspaces/CieLabTests.cs rename to tests/ImageSharp.Tests/ColorProfiles/CieLabTests.cs index 52cb63d217..3c015259b1 100644 --- a/tests/ImageSharp.Tests/Colorspaces/CieLabTests.cs +++ b/tests/ImageSharp.Tests/ColorProfiles/CieLabTests.cs @@ -2,9 +2,9 @@ // Licensed under the Six Labors Split License. using System.Numerics; -using SixLabors.ImageSharp.ColorSpaces; +using SixLabors.ImageSharp.ColorProfiles; -namespace SixLabors.ImageSharp.Tests.Colorspaces; +namespace SixLabors.ImageSharp.Tests.ColorProfiles; /// /// Tests the struct. @@ -17,7 +17,7 @@ public class CieLabTests const float l = 75F; const float a = -64F; const float b = 87F; - var cieLab = new CieLab(l, a, b); + CieLab cieLab = new(l, a, b); Assert.Equal(l, cieLab.L); Assert.Equal(a, cieLab.A); @@ -27,17 +27,17 @@ public class CieLabTests [Fact] public void CieLabEquality() { - var x = default(CieLab); - var y = new CieLab(Vector3.One); + CieLab x = default; + CieLab y = new(Vector3.One); - Assert.True(default(CieLab) == default(CieLab)); - Assert.True(new CieLab(1, 0, 1) != default(CieLab)); - Assert.False(new CieLab(1, 0, 1) == default(CieLab)); - Assert.Equal(default(CieLab), default(CieLab)); + Assert.True(default == default(CieLab)); + Assert.True(new CieLab(1, 0, 1) != default); + Assert.False(new CieLab(1, 0, 1) == default); + Assert.Equal(default, default(CieLab)); Assert.Equal(new CieLab(1, 0, 1), new CieLab(1, 0, 1)); Assert.Equal(new CieLab(Vector3.One), new CieLab(Vector3.One)); Assert.False(x.Equals(y)); - Assert.False(new CieLab(1, 0, 1) == default(CieLab)); + Assert.False(new CieLab(1, 0, 1) == default); Assert.False(x.Equals((object)y)); Assert.False(x.GetHashCode().Equals(y.GetHashCode())); } diff --git a/tests/ImageSharp.Tests/ColorProfiles/CieLchAndCieLuvConversionTests.cs b/tests/ImageSharp.Tests/ColorProfiles/CieLchAndCieLuvConversionTests.cs new file mode 100644 index 0000000000..598d4af335 --- /dev/null +++ b/tests/ImageSharp.Tests/ColorProfiles/CieLchAndCieLuvConversionTests.cs @@ -0,0 +1,71 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using SixLabors.ImageSharp.ColorProfiles; + +namespace SixLabors.ImageSharp.Tests.ColorProfiles; + +/// +/// Tests - conversions. +/// +public class CieLchAndCieLuvConversionTests +{ + private static readonly ApproximateColorProfileComparer Comparer = new(.0002f); + + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(36.0555, 103.6901, 10.01514, 34.89777, 187.6642, -7.181467)] + public void Convert_CieLch_to_CieLuv(float l, float c, float h, float l2, float u, float v) + { + // Arrange + CieLch input = new(l, c, h); + CieLuv expected = new(l2, u, v); + ColorConversionOptions options = new() { WhitePoint = KnownIlluminants.D50, TargetWhitePoint = KnownIlluminants.D65 }; + ColorProfileConverter converter = new(options); + + Span inputSpan = new CieLch[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieLuv[5]; + + // Act + CieLuv actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } + + [Theory] + [InlineData(34.89777, 187.6642, -7.181467, 36.0555, 103.6901, 10.01514)] + public void Convert_CieLuv_to_CieLch(float l2, float u, float v, float l, float c, float h) + { + // Arrange + CieLuv input = new(l2, u, v); + CieLch expected = new(l, c, h); + ColorConversionOptions options = new() { WhitePoint = KnownIlluminants.D65, TargetWhitePoint = KnownIlluminants.D50 }; + ColorProfileConverter converter = new(options); + + Span inputSpan = new CieLuv[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieLch[5]; + + // Act + CieLch actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } +} diff --git a/tests/ImageSharp.Tests/ColorProfiles/CieLchAndCieXyyConversionTests.cs b/tests/ImageSharp.Tests/ColorProfiles/CieLchAndCieXyyConversionTests.cs new file mode 100644 index 0000000000..94f5515bff --- /dev/null +++ b/tests/ImageSharp.Tests/ColorProfiles/CieLchAndCieXyyConversionTests.cs @@ -0,0 +1,70 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using SixLabors.ImageSharp.ColorProfiles; + +namespace SixLabors.ImageSharp.Tests.ColorProfiles; + +/// +/// Tests - conversions. +/// +public class CieLchAndCieXyyConversionTests +{ + private static readonly ApproximateColorProfileComparer Comparer = new(.0003f); + + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(36.0555, 103.6901, 10.01514, 0.67641, 0.22770, 0.09037)] + public void Convert_CieLch_to_CieXyy(float l, float c, float h, float x, float y, float yl) + { + // Arrange + CieLch input = new(l, c, h); + CieXyy expected = new(x, y, yl); + ColorProfileConverter converter = new(); + + Span inputSpan = new CieLch[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieXyy[5]; + + // Act + CieXyy actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } + + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(0.67641, 0.22770, 0.09037, 36.05544, 103.691315, 10.012783)] + public void Convert_CieXyy_to_CieLch(float x, float y, float yl, float l, float c, float h) + { + // Arrange + CieXyy input = new(x, y, yl); + CieLch expected = new(l, c, h); + ColorProfileConverter converter = new(); + + Span inputSpan = new CieXyy[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieLch[5]; + + // Act + CieLch actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } +} diff --git a/tests/ImageSharp.Tests/Colorspaces/CieLchTests.cs b/tests/ImageSharp.Tests/ColorProfiles/CieLchTests.cs similarity index 65% rename from tests/ImageSharp.Tests/Colorspaces/CieLchTests.cs rename to tests/ImageSharp.Tests/ColorProfiles/CieLchTests.cs index 83e4d8a59a..484db3e8cf 100644 --- a/tests/ImageSharp.Tests/Colorspaces/CieLchTests.cs +++ b/tests/ImageSharp.Tests/ColorProfiles/CieLchTests.cs @@ -1,10 +1,10 @@ -// Copyright (c) Six Labors. +// Copyright (c) Six Labors. // Licensed under the Six Labors Split License. using System.Numerics; -using SixLabors.ImageSharp.ColorSpaces; +using SixLabors.ImageSharp.ColorProfiles; -namespace SixLabors.ImageSharp.Tests.Colorspaces; +namespace SixLabors.ImageSharp.Tests.ColorProfiles; /// /// Tests the struct. @@ -17,7 +17,7 @@ public class CieLchTests const float l = 75F; const float c = 64F; const float h = 287F; - var cieLch = new CieLch(l, c, h); + CieLch cieLch = new(l, c, h); Assert.Equal(l, cieLch.L); Assert.Equal(c, cieLch.C); @@ -27,12 +27,12 @@ public class CieLchTests [Fact] public void CieLchEquality() { - var x = default(CieLch); - var y = new CieLch(Vector3.One); + CieLch x = default; + CieLch y = new(Vector3.One); - Assert.True(default(CieLch) == default(CieLch)); - Assert.False(default(CieLch) != default(CieLch)); - Assert.Equal(default(CieLch), default(CieLch)); + Assert.True(default == default(CieLch)); + Assert.False(default != default(CieLch)); + Assert.Equal(default, default(CieLch)); Assert.Equal(new CieLch(1, 0, 1), new CieLch(1, 0, 1)); Assert.Equal(new CieLch(Vector3.One), new CieLch(Vector3.One)); Assert.False(x.Equals(y)); diff --git a/tests/ImageSharp.Tests/ColorProfiles/CieLchuvAndCieLchConversionTests.cs b/tests/ImageSharp.Tests/ColorProfiles/CieLchuvAndCieLchConversionTests.cs new file mode 100644 index 0000000000..a3e0b45e0d --- /dev/null +++ b/tests/ImageSharp.Tests/ColorProfiles/CieLchuvAndCieLchConversionTests.cs @@ -0,0 +1,71 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using SixLabors.ImageSharp.ColorProfiles; + +namespace SixLabors.ImageSharp.Tests.ColorProfiles; + +/// +/// Tests - conversions. +/// +public class CieLchuvAndCieLchConversionTests +{ + private static readonly ApproximateColorProfileComparer Comparer = new(.0002F); + + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(36.73742, 64.79149, 30.1786, 36.0555, 103.6901, 10.01513)] + public void Convert_CieLch_To_CieLchuv(float l2, float c2, float h2, float l, float c, float h) + { + // Arrange + CieLch input = new(l2, c2, h2); + CieLchuv expected = new(l, c, h); + ColorConversionOptions options = new() { WhitePoint = KnownIlluminants.D50, TargetWhitePoint = KnownIlluminants.D65 }; + ColorProfileConverter converter = new(options); + + Span inputSpan = new CieLch[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieLchuv[5]; + + // Act + CieLchuv actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } + + [Theory] + [InlineData(36.0555, 103.6901, 10.01514, 36.73742, 64.79149, 30.1786)] + public void Convert_CieLchuv_To_CieLch(float l, float c, float h, float l2, float c2, float h2) + { + // Arrange + CieLchuv input = new(l, c, h); + CieLch expected = new(l2, c2, h2); + ColorConversionOptions options = new() { WhitePoint = KnownIlluminants.D65, TargetWhitePoint = KnownIlluminants.D50 }; + ColorProfileConverter converter = new(options); + + Span inputSpan = new CieLchuv[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieLch[5]; + + // Act + CieLch actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } +} diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchuvAndCieLuvConversionTests.cs b/tests/ImageSharp.Tests/ColorProfiles/CieLchuvAndCieLuvConversionTests.cs similarity index 62% rename from tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchuvAndCieLuvConversionTests.cs rename to tests/ImageSharp.Tests/ColorProfiles/CieLchuvAndCieLuvConversionTests.cs index ba3bc9e799..465237490d 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchuvAndCieLuvConversionTests.cs +++ b/tests/ImageSharp.Tests/ColorProfiles/CieLchuvAndCieLuvConversionTests.cs @@ -1,10 +1,9 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion; +using SixLabors.ImageSharp.ColorProfiles; -namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion; +namespace SixLabors.ImageSharp.Tests.ColorProfiles; /// /// Tests - conversions. @@ -15,12 +14,8 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion; /// public class CieLchuvAndCieLuvConversionTests { - private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0001F); - private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); + private static readonly ApproximateColorProfileComparer Comparer = new(.0001F); - /// - /// Tests conversion from to . - /// [Theory] [InlineData(0, 0, 0, 0, 0, 0)] [InlineData(54.2917, 106.8391, 40.8526, 54.2917, 80.8125, 69.8851)] @@ -33,8 +28,10 @@ public class CieLchuvAndCieLuvConversionTests public void Convert_CieLchuv_to_CieLuv(float l, float c, float h, float l2, float u, float v) { // Arrange - var input = new CieLchuv(l, c, h); - var expected = new CieLuv(l2, u, v); + CieLchuv input = new(l, c, h); + CieLuv expected = new(l2, u, v); + ColorConversionOptions options = new() { WhitePoint = KnownIlluminants.D65, TargetWhitePoint = KnownIlluminants.D65 }; + ColorProfileConverter converter = new(options); Span inputSpan = new CieLchuv[5]; inputSpan.Fill(input); @@ -42,21 +39,18 @@ public class CieLchuvAndCieLuvConversionTests Span actualSpan = new CieLuv[5]; // Act - var actual = Converter.ToCieLuv(input); - Converter.Convert(inputSpan, actualSpan); + CieLuv actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); + Assert.Equal(expected, actual, Comparer); for (int i = 0; i < actualSpan.Length; i++) { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); + Assert.Equal(expected, actualSpan[i], Comparer); } } - /// - /// Tests conversion from to . - /// [Theory] [InlineData(0, 0, 0, 0, 0, 0)] [InlineData(54.2917, 80.8125, 69.8851, 54.2917, 106.8391, 40.8526)] @@ -70,8 +64,10 @@ public class CieLchuvAndCieLuvConversionTests public void Convert_CieLuv_to_CieLchuv(float l, float u, float v, float l2, float c, float h) { // Arrange - var input = new CieLuv(l, u, v); - var expected = new CieLchuv(l2, c, h); + CieLuv input = new(l, u, v); + CieLchuv expected = new(l2, c, h); + ColorConversionOptions options = new() { WhitePoint = KnownIlluminants.D65, TargetWhitePoint = KnownIlluminants.D65 }; + ColorProfileConverter converter = new(options); Span inputSpan = new CieLuv[5]; inputSpan.Fill(input); @@ -79,15 +75,15 @@ public class CieLchuvAndCieLuvConversionTests Span actualSpan = new CieLchuv[5]; // Act - var actual = Converter.ToCieLchuv(input); - Converter.Convert(inputSpan, actualSpan); + CieLchuv actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); + Assert.Equal(expected, actual, Comparer); for (int i = 0; i < actualSpan.Length; i++) { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); + Assert.Equal(expected, actualSpan[i], Comparer); } } } diff --git a/tests/ImageSharp.Tests/ColorProfiles/CieLchuvAndCmykConversionTests.cs b/tests/ImageSharp.Tests/ColorProfiles/CieLchuvAndCmykConversionTests.cs new file mode 100644 index 0000000000..60ac3da16e --- /dev/null +++ b/tests/ImageSharp.Tests/ColorProfiles/CieLchuvAndCmykConversionTests.cs @@ -0,0 +1,72 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using SixLabors.ImageSharp.ColorProfiles; + +namespace SixLabors.ImageSharp.Tests.ColorProfiles; + +/// +/// Tests - conversions. +/// +public class CieLchuvAndCmykConversionTests +{ + private static readonly ApproximateColorProfileComparer Comparer = new(.0001F); + + [Theory] + [InlineData(0, 0, 0, 1, 0, 0, 0)] + [InlineData(0, 0.8576171, 0.7693201, 0.3440427, 36.0555, 103.6901, 10.01514)] + public void Convert_Cmyk_to_CieLchuv(float c2, float m, float y, float k, float l, float c, float h) + { + // Arrange + Cmyk input = new(c2, m, y, k); + CieLchuv expected = new(l, c, h); + ColorConversionOptions options = new() { WhitePoint = KnownIlluminants.D65, TargetWhitePoint = KnownIlluminants.D65 }; + ColorProfileConverter converter = new(options); + + Span inputSpan = new Cmyk[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieLchuv[5]; + + // Act + CieLchuv actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } + + [Theory] + [InlineData(0, 0, 0, 0, 0, 0, 1)] + [InlineData(36.0555, 103.6901, 10.01514, 0, 0.8576171, 0.7693201, 0.3440427)] + public void Convert_CieLchuv_to_Cmyk(float l, float c, float h, float c2, float m, float y, float k) + { + // Arrange + CieLchuv input = new(l, c, h); + Cmyk expected = new(c2, m, y, k); + ColorConversionOptions options = new() { WhitePoint = KnownIlluminants.D65, TargetWhitePoint = KnownIlluminants.D65 }; + ColorProfileConverter converter = new(options); + + Span inputSpan = new CieLchuv[5]; + inputSpan.Fill(input); + + Span actualSpan = new Cmyk[5]; + + // Act + Cmyk actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } +} diff --git a/tests/ImageSharp.Tests/Colorspaces/CieLchuvTests.cs b/tests/ImageSharp.Tests/ColorProfiles/CieLchuvTests.cs similarity index 65% rename from tests/ImageSharp.Tests/Colorspaces/CieLchuvTests.cs rename to tests/ImageSharp.Tests/ColorProfiles/CieLchuvTests.cs index f6c68aae91..0b737cdfca 100644 --- a/tests/ImageSharp.Tests/Colorspaces/CieLchuvTests.cs +++ b/tests/ImageSharp.Tests/ColorProfiles/CieLchuvTests.cs @@ -1,10 +1,10 @@ -// Copyright (c) Six Labors. +// Copyright (c) Six Labors. // Licensed under the Six Labors Split License. using System.Numerics; -using SixLabors.ImageSharp.ColorSpaces; +using SixLabors.ImageSharp.ColorProfiles; -namespace SixLabors.ImageSharp.Tests.Colorspaces; +namespace SixLabors.ImageSharp.Tests.ColorProfiles; /// /// Tests the struct. @@ -17,7 +17,7 @@ public class CieLchuvTests const float l = 75F; const float c = 64F; const float h = 287F; - var cieLchuv = new CieLchuv(l, c, h); + CieLchuv cieLchuv = new(l, c, h); Assert.Equal(l, cieLchuv.L); Assert.Equal(c, cieLchuv.C); @@ -27,12 +27,12 @@ public class CieLchuvTests [Fact] public void CieLchuvEquality() { - var x = default(CieLchuv); - var y = new CieLchuv(Vector3.One); + CieLchuv x = default; + CieLchuv y = new(Vector3.One); - Assert.True(default(CieLchuv) == default(CieLchuv)); - Assert.False(default(CieLchuv) != default(CieLchuv)); - Assert.Equal(default(CieLchuv), default(CieLchuv)); + Assert.True(default == default(CieLchuv)); + Assert.False(default != default(CieLchuv)); + Assert.Equal(default, default(CieLchuv)); Assert.Equal(new CieLchuv(1, 0, 1), new CieLchuv(1, 0, 1)); Assert.Equal(new CieLchuv(Vector3.One), new CieLchuv(Vector3.One)); Assert.False(x.Equals(y)); diff --git a/tests/ImageSharp.Tests/ColorProfiles/CieLuvAndCieXyyConversionTests.cs b/tests/ImageSharp.Tests/ColorProfiles/CieLuvAndCieXyyConversionTests.cs new file mode 100644 index 0000000000..e73edcda7c --- /dev/null +++ b/tests/ImageSharp.Tests/ColorProfiles/CieLuvAndCieXyyConversionTests.cs @@ -0,0 +1,72 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using SixLabors.ImageSharp.ColorProfiles; + +namespace SixLabors.ImageSharp.Tests.ColorProfiles; + +/// +/// Tests - conversions. +/// +public class CieLuvAndCieXyyConversionTests +{ + private static readonly ApproximateColorProfileComparer Comparer = new(.0002F); + + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(36.0555, 103.6901, 10.01514, 0.5646762, 0.2932749, 0.09037033)] + public void Convert_CieLuv_to_CieXyy(float l, float u, float v, float x, float y, float yl) + { + // Arrange + CieLuv input = new(l, u, v); + CieXyy expected = new(x, y, yl); + ColorConversionOptions options = new() { WhitePoint = KnownIlluminants.D65, TargetWhitePoint = KnownIlluminants.D65 }; + ColorProfileConverter converter = new(options); + + Span inputSpan = new CieLuv[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieXyy[5]; + + // Act + CieXyy actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } + + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(0.5646762, 0.2932749, 0.09037033, 36.0555, 103.6901, 10.01514)] + public void Convert_CieXyy_to_CieLuv(float x, float y, float yl, float l, float u, float v) + { + // Arrange + CieXyy input = new(x, y, yl); + CieLuv expected = new(l, u, v); + ColorConversionOptions options = new() { WhitePoint = KnownIlluminants.D65, TargetWhitePoint = KnownIlluminants.D65 }; + ColorProfileConverter converter = new(options); + + Span inputSpan = new CieXyy[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieLuv[5]; + + // Act + CieLuv actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } +} diff --git a/tests/ImageSharp.Tests/ColorProfiles/CieLuvAndHslConversionTests.cs b/tests/ImageSharp.Tests/ColorProfiles/CieLuvAndHslConversionTests.cs new file mode 100644 index 0000000000..b178b22b20 --- /dev/null +++ b/tests/ImageSharp.Tests/ColorProfiles/CieLuvAndHslConversionTests.cs @@ -0,0 +1,72 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using SixLabors.ImageSharp.ColorProfiles; + +namespace SixLabors.ImageSharp.Tests.ColorProfiles; + +/// +/// Tests - conversions. +/// +public class CieLuvAndHslConversionTests +{ + private static readonly ApproximateColorProfileComparer Comparer = new(.0002F); + + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(36.0555, 93.6901, 10.01514, 347.3767, 0.7115612, 0.3765343)] + public void Convert_CieLuv_to_Hsl(float l, float u, float v, float h, float s, float l2) + { + // Arrange + CieLuv input = new(l, u, v); + Hsl expected = new(h, s, l2); + ColorConversionOptions options = new() { WhitePoint = KnownIlluminants.D65, TargetWhitePoint = KnownIlluminants.D65 }; + ColorProfileConverter converter = new(options); + + Span inputSpan = new CieLuv[5]; + inputSpan.Fill(input); + + Span actualSpan = new Hsl[5]; + + // Act + Hsl actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } + + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(347.3767, 0.7115612, 0.3765343, 36.0555, 93.69012, 10.01514)] + public void Convert_Hsl_to_CieLuv(float h, float s, float l2, float l, float u, float v) + { + // Arrange + Hsl input = new(h, s, l2); + CieLuv expected = new(l, u, v); + ColorConversionOptions options = new() { WhitePoint = KnownIlluminants.D65, TargetWhitePoint = KnownIlluminants.D65 }; + ColorProfileConverter converter = new(options); + + Span inputSpan = new Hsl[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieLuv[5]; + + // Act + CieLuv actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } +} diff --git a/tests/ImageSharp.Tests/ColorProfiles/CieLuvAndHsvConversionTests.cs b/tests/ImageSharp.Tests/ColorProfiles/CieLuvAndHsvConversionTests.cs new file mode 100644 index 0000000000..2866093377 --- /dev/null +++ b/tests/ImageSharp.Tests/ColorProfiles/CieLuvAndHsvConversionTests.cs @@ -0,0 +1,72 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using SixLabors.ImageSharp.ColorProfiles; + +namespace SixLabors.ImageSharp.Tests.ColorProfiles; + +/// +/// Tests - conversions. +/// +public class CieLuvAndHsvConversionTests +{ + private static readonly ApproximateColorProfileComparer Comparer = new(.0002F); + + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(36.0555, 93.6901, 10.01514, 347.3767, 0.8314762, 0.6444615)] + public void Convert_CieLuv_to_Hsv(float l, float u, float v, float h, float s, float v2) + { + // Arrange + CieLuv input = new(l, u, v); + Hsv expected = new(h, s, v2); + ColorConversionOptions options = new() { WhitePoint = KnownIlluminants.D65, TargetWhitePoint = KnownIlluminants.D65 }; + ColorProfileConverter converter = new(options); + + Span inputSpan = new CieLuv[5]; + inputSpan.Fill(input); + + Span actualSpan = new Hsv[5]; + + // Act + Hsv actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } + + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(347.3767, 0.8314762, 0.6444615, 36.0555, 93.69012, 10.01514)] + public void Convert_Hsv_to_CieLuv(float h, float s, float v2, float l, float u, float v) + { + // Arrange + Hsv input = new(h, s, v2); + CieLuv expected = new(l, u, v); + ColorConversionOptions options = new() { WhitePoint = KnownIlluminants.D65, TargetWhitePoint = KnownIlluminants.D65 }; + ColorProfileConverter converter = new(options); + + Span inputSpan = new Hsv[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieLuv[5]; + + // Act + CieLuv actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } +} diff --git a/tests/ImageSharp.Tests/ColorProfiles/CieLuvAndHunterLabConversionTests.cs b/tests/ImageSharp.Tests/ColorProfiles/CieLuvAndHunterLabConversionTests.cs new file mode 100644 index 0000000000..73b605fb62 --- /dev/null +++ b/tests/ImageSharp.Tests/ColorProfiles/CieLuvAndHunterLabConversionTests.cs @@ -0,0 +1,72 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using SixLabors.ImageSharp.ColorProfiles; + +namespace SixLabors.ImageSharp.Tests.ColorProfiles; + +/// +/// Tests - conversions. +/// +public class CieLuvAndHunterLabConversionTests +{ + private static readonly ApproximateColorProfileComparer Comparer = new(.0002F); + + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(36.0555, 93.6901, 10.01514, 30.59289, 48.55542, 9.80487)] + public void Convert_CieLuv_To_HunterLab(float l, float u, float v, float l2, float a, float b) + { + // Arrange + CieLuv input = new(l, u, v); + HunterLab expected = new(l2, a, b); + ColorConversionOptions options = new() { WhitePoint = KnownIlluminants.D65, TargetWhitePoint = KnownIlluminants.D50 }; + ColorProfileConverter converter = new(options); + + Span inputSpan = new CieLuv[5]; + inputSpan.Fill(input); + + Span actualSpan = new HunterLab[5]; + + // Act + HunterLab actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } + + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(30.59289, 48.55542, 9.80487, 36.0555, 93.6901, 10.01514)] + public void Convert_HunterLab_To_CieLuv(float l2, float a, float b, float l, float u, float v) + { + // Arrange + HunterLab input = new(l2, a, b); + CieLuv expected = new(l, u, v); + ColorConversionOptions options = new() { WhitePoint = KnownIlluminants.D50, TargetWhitePoint = KnownIlluminants.D65 }; + ColorProfileConverter converter = new(options); + + Span inputSpan = new HunterLab[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieLuv[5]; + + // Act + CieLuv actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } +} diff --git a/tests/ImageSharp.Tests/ColorProfiles/CieLuvAndLmsConversionTests.cs b/tests/ImageSharp.Tests/ColorProfiles/CieLuvAndLmsConversionTests.cs new file mode 100644 index 0000000000..812ca44ddc --- /dev/null +++ b/tests/ImageSharp.Tests/ColorProfiles/CieLuvAndLmsConversionTests.cs @@ -0,0 +1,72 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using SixLabors.ImageSharp.ColorProfiles; + +namespace SixLabors.ImageSharp.Tests.ColorProfiles; + +/// +/// Tests - conversions. +/// +public class CieLuvAndLmsConversionTests +{ + private static readonly ApproximateColorProfileComparer Comparer = new(.0002F); + + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(36.0555, 93.6901, 10.01514, 0.164352, 0.03267485, 0.0483408)] + public void Convert_CieLuv_to_Lms(float l, float u, float v, float l2, float m, float s) + { + // Arrange + CieLuv input = new(l, u, v); + Lms expected = new(l2, m, s); + ColorConversionOptions options = new() { WhitePoint = KnownIlluminants.D65, TargetWhitePoint = KnownIlluminants.D65 }; + ColorProfileConverter converter = new(options); + + Span inputSpan = new CieLuv[5]; + inputSpan.Fill(input); + + Span actualSpan = new Lms[5]; + + // Act + Lms actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } + + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(0.164352, 0.03267485, 0.0483408, 36.0555, 93.69009, 10.01514)] + public void Convert_Lms_to_CieLuv(float l2, float m, float s, float l, float u, float v) + { + // Arrange + Lms input = new(l2, m, s); + CieLuv expected = new(l, u, v); + ColorConversionOptions options = new() { WhitePoint = KnownIlluminants.D65, TargetWhitePoint = KnownIlluminants.D65 }; + ColorProfileConverter converter = new(options); + + Span inputSpan = new Lms[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieLuv[5]; + + // Act + CieLuv actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } +} diff --git a/tests/ImageSharp.Tests/ColorProfiles/CieLuvAndRgbConversionTests.cs b/tests/ImageSharp.Tests/ColorProfiles/CieLuvAndRgbConversionTests.cs new file mode 100644 index 0000000000..f1da6e33fd --- /dev/null +++ b/tests/ImageSharp.Tests/ColorProfiles/CieLuvAndRgbConversionTests.cs @@ -0,0 +1,72 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using SixLabors.ImageSharp.ColorProfiles; + +namespace SixLabors.ImageSharp.Tests.ColorProfiles; + +/// +/// Tests - conversions. +/// +public class CieLuvAndRgbConversionTests +{ + private static readonly ApproximateColorProfileComparer Comparer = new(.0002F); + + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(36.0555, 93.6901, 10.01514, 0.6444615, 0.1086071, 0.2213444)] + public void Convert_CieLuv_to_Rgb(float l, float u, float v, float r, float g, float b) + { + // Arrange + CieLuv input = new(l, u, v); + Rgb expected = new(r, g, b); + ColorConversionOptions options = new() { WhitePoint = KnownIlluminants.D65, TargetWhitePoint = KnownIlluminants.D65 }; + ColorProfileConverter converter = new(options); + + Span inputSpan = new CieLuv[5]; + inputSpan.Fill(input); + + Span actualSpan = new Rgb[5]; + + // Act + Rgb actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } + + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(0.6444615, 0.1086071, 0.2213444, 36.0555, 93.69012, 10.01514)] + public void Convert_Rgb_to_CieLuv(float r, float g, float b, float l, float u, float v) + { + // Arrange + Rgb input = new(r, g, b); + CieLuv expected = new(l, u, v); + ColorConversionOptions options = new() { WhitePoint = KnownIlluminants.D65, TargetWhitePoint = KnownIlluminants.D65 }; + ColorProfileConverter converter = new(options); + + Span inputSpan = new Rgb[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieLuv[5]; + + // Act + CieLuv actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } +} diff --git a/tests/ImageSharp.Tests/ColorProfiles/CieLuvAndYCbCrConversionTests.cs b/tests/ImageSharp.Tests/ColorProfiles/CieLuvAndYCbCrConversionTests.cs new file mode 100644 index 0000000000..fa7e2ece3f --- /dev/null +++ b/tests/ImageSharp.Tests/ColorProfiles/CieLuvAndYCbCrConversionTests.cs @@ -0,0 +1,72 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using SixLabors.ImageSharp.ColorProfiles; + +namespace SixLabors.ImageSharp.Tests.ColorProfiles; + +/// +/// Tests - conversions. +/// +public class CieLuvAndYCbCrConversionTests +{ + private static readonly ApproximateColorProfileComparer Comparer = new(.0002F); + + [Theory] + [InlineData(0, 0, 0, 0, 128, 128)] + [InlineData(36.0555, 93.6901, 10.01514, 71.8283, 119.3174, 193.9839)] + public void Convert_CieLuv_to_YCbCr(float l, float u, float v, float y, float cb, float cr) + { + // Arrange + CieLuv input = new(l, u, v); + YCbCr expected = new(y, cb, cr); + ColorConversionOptions options = new() { WhitePoint = KnownIlluminants.D65, TargetWhitePoint = KnownIlluminants.D65 }; + ColorProfileConverter converter = new(options); + + Span inputSpan = new CieLuv[5]; + inputSpan.Fill(input); + + Span actualSpan = new YCbCr[5]; + + // Act + YCbCr actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } + + [Theory] + [InlineData(0, 128, 128, 0, 0, 0)] + [InlineData(71.8283, 119.3174, 193.9839, 36.00565, 93.44593, 10.2234)] + public void Convert_YCbCr_to_CieLuv(float y, float cb, float cr, float l, float u, float v) + { + // Arrange + YCbCr input = new(y, cb, cr); + CieLuv expected = new(l, u, v); + ColorConversionOptions options = new() { WhitePoint = KnownIlluminants.D65, TargetWhitePoint = KnownIlluminants.D65 }; + ColorProfileConverter converter = new(options); + + Span inputSpan = new YCbCr[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieLuv[5]; + + // Act + CieLuv actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } +} diff --git a/tests/ImageSharp.Tests/Colorspaces/CieLuvTests.cs b/tests/ImageSharp.Tests/ColorProfiles/CieLuvTests.cs similarity index 65% rename from tests/ImageSharp.Tests/Colorspaces/CieLuvTests.cs rename to tests/ImageSharp.Tests/ColorProfiles/CieLuvTests.cs index 0ebf1bdeaa..db903a0bf5 100644 --- a/tests/ImageSharp.Tests/Colorspaces/CieLuvTests.cs +++ b/tests/ImageSharp.Tests/ColorProfiles/CieLuvTests.cs @@ -1,10 +1,10 @@ -// Copyright (c) Six Labors. +// Copyright (c) Six Labors. // Licensed under the Six Labors Split License. using System.Numerics; -using SixLabors.ImageSharp.ColorSpaces; +using SixLabors.ImageSharp.ColorProfiles; -namespace SixLabors.ImageSharp.Tests.Colorspaces; +namespace SixLabors.ImageSharp.Tests.ColorProfiles; /// /// Tests the struct. @@ -17,7 +17,7 @@ public class CieLuvTests const float l = 75F; const float c = -64F; const float h = 87F; - var cieLuv = new CieLuv(l, c, h); + CieLuv cieLuv = new(l, c, h); Assert.Equal(l, cieLuv.L); Assert.Equal(c, cieLuv.U); @@ -27,12 +27,12 @@ public class CieLuvTests [Fact] public void CieLuvEquality() { - var x = default(CieLuv); - var y = new CieLuv(Vector3.One); + CieLuv x = default; + CieLuv y = new(Vector3.One); - Assert.True(default(CieLuv) == default(CieLuv)); - Assert.False(default(CieLuv) != default(CieLuv)); - Assert.Equal(default(CieLuv), default(CieLuv)); + Assert.True(default == default(CieLuv)); + Assert.False(default != default(CieLuv)); + Assert.Equal(default, default(CieLuv)); Assert.Equal(new CieLuv(1, 0, 1), new CieLuv(1, 0, 1)); Assert.Equal(new CieLuv(Vector3.One), new CieLuv(Vector3.One)); Assert.False(x.Equals(y)); diff --git a/tests/ImageSharp.Tests/Colorspaces/CieXyChromaticityCoordinatesTests.cs b/tests/ImageSharp.Tests/ColorProfiles/CieXyChromaticityCoordinatesTests.cs similarity index 64% rename from tests/ImageSharp.Tests/Colorspaces/CieXyChromaticityCoordinatesTests.cs rename to tests/ImageSharp.Tests/ColorProfiles/CieXyChromaticityCoordinatesTests.cs index 061d6c432f..a85a08a21e 100644 --- a/tests/ImageSharp.Tests/Colorspaces/CieXyChromaticityCoordinatesTests.cs +++ b/tests/ImageSharp.Tests/ColorProfiles/CieXyChromaticityCoordinatesTests.cs @@ -1,9 +1,9 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -using SixLabors.ImageSharp.ColorSpaces.Conversion; +using SixLabors.ImageSharp.ColorProfiles; -namespace SixLabors.ImageSharp.Tests.Colorspaces; +namespace SixLabors.ImageSharp.Tests.ColorProfiles; /// /// Tests the struct. @@ -15,7 +15,7 @@ public class CieXyChromaticityCoordinatesTests { const float x = .75F; const float y = .64F; - var coordinates = new CieXyChromaticityCoordinates(x, y); + CieXyChromaticityCoordinates coordinates = new(x, y); Assert.Equal(x, coordinates.X); Assert.Equal(y, coordinates.Y); @@ -24,17 +24,17 @@ public class CieXyChromaticityCoordinatesTests [Fact] public void CieXyChromaticityCoordinatesEquality() { - var x = default(CieXyChromaticityCoordinates); - var y = new CieXyChromaticityCoordinates(1, 1); + CieXyChromaticityCoordinates x = default; + CieXyChromaticityCoordinates y = new(1, 1); - Assert.True(default(CieXyChromaticityCoordinates) == default(CieXyChromaticityCoordinates)); - Assert.True(new CieXyChromaticityCoordinates(1, 0) != default(CieXyChromaticityCoordinates)); - Assert.False(new CieXyChromaticityCoordinates(1, 0) == default(CieXyChromaticityCoordinates)); - Assert.Equal(default(CieXyChromaticityCoordinates), default(CieXyChromaticityCoordinates)); + Assert.True(default == default(CieXyChromaticityCoordinates)); + Assert.True(new CieXyChromaticityCoordinates(1, 0) != default); + Assert.False(new CieXyChromaticityCoordinates(1, 0) == default); + Assert.Equal(default, default(CieXyChromaticityCoordinates)); Assert.Equal(new CieXyChromaticityCoordinates(1, 0), new CieXyChromaticityCoordinates(1, 0)); Assert.Equal(new CieXyChromaticityCoordinates(1, 1), new CieXyChromaticityCoordinates(1, 1)); Assert.False(x.Equals(y)); - Assert.False(new CieXyChromaticityCoordinates(1, 0) == default(CieXyChromaticityCoordinates)); + Assert.False(new CieXyChromaticityCoordinates(1, 0) == default); Assert.False(x.Equals((object)y)); Assert.False(x.GetHashCode().Equals(y.GetHashCode())); } diff --git a/tests/ImageSharp.Tests/ColorProfiles/CieXyyAndHslConversionTests.cs b/tests/ImageSharp.Tests/ColorProfiles/CieXyyAndHslConversionTests.cs new file mode 100644 index 0000000000..3e93206ce4 --- /dev/null +++ b/tests/ImageSharp.Tests/ColorProfiles/CieXyyAndHslConversionTests.cs @@ -0,0 +1,70 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using SixLabors.ImageSharp.ColorProfiles; + +namespace SixLabors.ImageSharp.Tests.ColorProfiles; + +/// +/// Tests - conversions. +/// +public class CieXyyAndHslConversionTests +{ + private static readonly ApproximateColorProfileComparer Comparer = new(.0002F); + + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(0.360555, 0.936901, 0.1001514, 120, 1, 0.2138507)] + public void Convert_CieXyy_to_Hsl(float x, float y, float yl, float h, float s, float l) + { + // Arrange + CieXyy input = new(x, y, yl); + Hsl expected = new(h, s, l); + ColorProfileConverter converter = new(); + + Span inputSpan = new CieXyy[5]; + inputSpan.Fill(input); + + Span actualSpan = new Hsl[5]; + + // Act + Hsl actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } + + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(120, 1, 0.2138507, 0.32114, 0.59787, 0.10976)] + public void Convert_Hsl_to_CieXyy(float h, float s, float l, float x, float y, float yl) + { + // Arrange + Hsl input = new(h, s, l); + CieXyy expected = new(x, y, yl); + ColorProfileConverter converter = new(); + + Span inputSpan = new Hsl[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieXyy[5]; + + // Act + CieXyy actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } +} diff --git a/tests/ImageSharp.Tests/ColorProfiles/CieXyyAndHsvConversionTests.cs b/tests/ImageSharp.Tests/ColorProfiles/CieXyyAndHsvConversionTests.cs new file mode 100644 index 0000000000..c2547ca847 --- /dev/null +++ b/tests/ImageSharp.Tests/ColorProfiles/CieXyyAndHsvConversionTests.cs @@ -0,0 +1,70 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using SixLabors.ImageSharp.ColorProfiles; + +namespace SixLabors.ImageSharp.Tests.ColorProfiles; + +/// +/// Tests - conversions. +/// +public class CieXyyAndHsvConversionTests +{ + private static readonly ApproximateColorProfileComparer Comparer = new(.0002F); + + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(0.360555, 0.936901, 0.1001514, 120, 1, 0.42770)] + public void Convert_CieXyy_To_Hsv(float x, float y, float yl, float h, float s, float v) + { + // Arrange + CieXyy input = new(x, y, yl); + Hsv expected = new(h, s, v); + ColorProfileConverter converter = new(); + + Span inputSpan = new CieXyy[5]; + inputSpan.Fill(input); + + Span actualSpan = new Hsv[5]; + + // Act + Hsv actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } + + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(120, 1, 0.42770, 0.32114, 0.59787, 0.10976)] + public void Convert_Hsv_To_CieXyy(float h, float s, float v, float x, float y, float yl) + { + // Arrange + Hsv input = new(h, s, v); + CieXyy expected = new(x, y, yl); + ColorProfileConverter converter = new(); + + Span inputSpan = new Hsv[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieXyy[5]; + + // Act + CieXyy actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } +} diff --git a/tests/ImageSharp.Tests/ColorProfiles/CieXyyAndHunterLabConversionTests.cs b/tests/ImageSharp.Tests/ColorProfiles/CieXyyAndHunterLabConversionTests.cs new file mode 100644 index 0000000000..4f66538f0f --- /dev/null +++ b/tests/ImageSharp.Tests/ColorProfiles/CieXyyAndHunterLabConversionTests.cs @@ -0,0 +1,70 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using SixLabors.ImageSharp.ColorProfiles; + +namespace SixLabors.ImageSharp.Tests.ColorProfiles; + +/// +/// Tests - conversions. +/// +public class CieXyyAndHunterLabConversionTests +{ + private static readonly ApproximateColorProfileComparer Comparer = new(.0002f); + + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(0.360555, 0.936901, 0.1001514, 31.6467056, -33.00599, 25.67032)] + public void Convert_CieXyy_To_HunterLab(float x, float y, float yl, float l, float a, float b) + { + // Arrange + CieXyy input = new(x, y, yl); + HunterLab expected = new(l, a, b); + ColorProfileConverter converter = new(); + + Span inputSpan = new CieXyy[5]; + inputSpan.Fill(input); + + Span actualSpan = new HunterLab[5]; + + // Act + HunterLab actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } + + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(31.6467056, -33.00599, 25.67032, 0.360555, 0.936901, 0.1001514)] + public void Convert_HunterLab_To_CieXyy(float l, float a, float b, float x, float y, float yl) + { + // Arrange + HunterLab input = new(l, a, b); + CieXyy expected = new(x, y, yl); + ColorProfileConverter converter = new(); + + Span inputSpan = new HunterLab[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieXyy[5]; + + // Act + CieXyy actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } +} diff --git a/tests/ImageSharp.Tests/ColorProfiles/CieXyyAndLmsConversionTests.cs b/tests/ImageSharp.Tests/ColorProfiles/CieXyyAndLmsConversionTests.cs new file mode 100644 index 0000000000..1a89cb26dc --- /dev/null +++ b/tests/ImageSharp.Tests/ColorProfiles/CieXyyAndLmsConversionTests.cs @@ -0,0 +1,70 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using SixLabors.ImageSharp.ColorProfiles; + +namespace SixLabors.ImageSharp.Tests.ColorProfiles; + +/// +/// Tests - conversions. +/// +public class CieXyyAndLmsConversionTests +{ + private static readonly ApproximateColorProfileComparer Comparer = new(.0002f); + + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(0.360555, 0.936901, 0.1001514, 0.06631134, 0.1415282, -0.03809926)] + public void Convert_CieXyy_to_Lms(float x, float y, float yl, float l, float m, float s) + { + // Arrange + CieXyy input = new(x, y, yl); + Lms expected = new(l, m, s); + ColorProfileConverter converter = new(); + + Span inputSpan = new CieXyy[5]; + inputSpan.Fill(input); + + Span actualSpan = new Lms[5]; + + // Act + Lms actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } + + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(0.06631134, 0.1415282, -0.03809926, 0.360555, 0.936901, 0.1001514)] + public void Convert_Lms_to_CieXyy(float l, float m, float s, float x, float y, float yl) + { + // Arrange + Lms input = new(l, m, s); + CieXyy expected = new(x, y, yl); + ColorProfileConverter converter = new(); + + Span inputSpan = new Lms[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieXyy[5]; + + // Act + CieXyy actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } +} diff --git a/tests/ImageSharp.Tests/ColorProfiles/CieXyyAndRgbConversionTests.cs b/tests/ImageSharp.Tests/ColorProfiles/CieXyyAndRgbConversionTests.cs new file mode 100644 index 0000000000..18df2ce145 --- /dev/null +++ b/tests/ImageSharp.Tests/ColorProfiles/CieXyyAndRgbConversionTests.cs @@ -0,0 +1,70 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using SixLabors.ImageSharp.ColorProfiles; + +namespace SixLabors.ImageSharp.Tests.ColorProfiles; + +/// +/// Tests - conversions. +/// +public class CieXyyAndRgbConversionTests +{ + private static readonly ApproximateColorProfileComparer Comparer = new(.0002f); + + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(0.360555, 0.936901, 0.1001514, 0, 0.4277014, 0)] + public void Convert_CieXyy_to_Rgb(float x, float y, float yl, float r, float g, float b) + { + // Arrange + CieXyy input = new(x, y, yl); + Rgb expected = new(r, g, b); + ColorProfileConverter converter = new(); + + Span inputSpan = new CieXyy[5]; + inputSpan.Fill(input); + + Span actualSpan = new Rgb[5]; + + // Act + Rgb actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } + + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(0, 0.4277014, 0, 0.32114, 0.59787, 0.10976)] + public void Convert_Rgb_to_CieXyy(float r, float g, float b, float x, float y, float yl) + { + // Arrange + Rgb input = new(r, g, b); + CieXyy expected = new(x, y, yl); + ColorProfileConverter converter = new(); + + Span inputSpan = new Rgb[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieXyy[5]; + + // Act + CieXyy actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } +} diff --git a/tests/ImageSharp.Tests/ColorProfiles/CieXyyAndYCbCrConversionTests.cs b/tests/ImageSharp.Tests/ColorProfiles/CieXyyAndYCbCrConversionTests.cs new file mode 100644 index 0000000000..1fe3596036 --- /dev/null +++ b/tests/ImageSharp.Tests/ColorProfiles/CieXyyAndYCbCrConversionTests.cs @@ -0,0 +1,70 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using SixLabors.ImageSharp.ColorProfiles; + +namespace SixLabors.ImageSharp.Tests.ColorProfiles; + +/// +/// Tests - conversions. +/// +public class CieXyyAndYCbCrConversionTests +{ + private static readonly ApproximateColorProfileComparer Comparer = new(.0002f); + + [Theory] + [InlineData(0, 0, 0, 0, 128, 128)] + [InlineData(0.360555, 0.936901, 0.1001514, 64.0204849, 91.87107, 82.33627)] + public void Convert_CieXyy_to_YCbCr(float x, float y, float yl, float y2, float cb, float cr) + { + // Arrange + CieXyy input = new(x, y, yl); + YCbCr expected = new(y2, cb, cr); + ColorProfileConverter converter = new(); + + Span inputSpan = new CieXyy[5]; + inputSpan.Fill(input); + + Span actualSpan = new YCbCr[5]; + + // Act + YCbCr actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } + + [Theory] + [InlineData(0, 128, 128, 0, 0, 0)] + [InlineData(64.0204849, 91.87107, 82.33627, 0.32114, 0.59787, 0.10976)] + public void Convert_YCbCr_to_CieXyy(float y2, float cb, float cr, float x, float y, float yl) + { + // Arrange + YCbCr input = new(y2, cb, cr); + CieXyy expected = new(x, y, yl); + ColorProfileConverter converter = new(); + + Span inputSpan = new YCbCr[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieXyy[5]; + + // Act + CieXyy actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } +} diff --git a/tests/ImageSharp.Tests/Colorspaces/CieXyyTests.cs b/tests/ImageSharp.Tests/ColorProfiles/CieXyyTests.cs similarity index 65% rename from tests/ImageSharp.Tests/Colorspaces/CieXyyTests.cs rename to tests/ImageSharp.Tests/ColorProfiles/CieXyyTests.cs index f1eb126401..245512f8a8 100644 --- a/tests/ImageSharp.Tests/Colorspaces/CieXyyTests.cs +++ b/tests/ImageSharp.Tests/ColorProfiles/CieXyyTests.cs @@ -1,10 +1,10 @@ -// Copyright (c) Six Labors. +// Copyright (c) Six Labors. // Licensed under the Six Labors Split License. using System.Numerics; -using SixLabors.ImageSharp.ColorSpaces; +using SixLabors.ImageSharp.ColorProfiles; -namespace SixLabors.ImageSharp.Tests.Colorspaces; +namespace SixLabors.ImageSharp.Tests.ColorProfiles; /// /// Tests the struct. @@ -17,7 +17,7 @@ public class CieXyyTests const float x = 75F; const float y = 64F; const float yl = 287F; - var cieXyy = new CieXyy(x, y, yl); + CieXyy cieXyy = new(x, y, yl); Assert.Equal(x, cieXyy.X); Assert.Equal(y, cieXyy.Y); @@ -27,12 +27,12 @@ public class CieXyyTests [Fact] public void CieXyyEquality() { - var x = default(CieXyy); - var y = new CieXyy(Vector3.One); + CieXyy x = default; + CieXyy y = new(Vector3.One); - Assert.True(default(CieXyy) == default(CieXyy)); - Assert.False(default(CieXyy) != default(CieXyy)); - Assert.Equal(default(CieXyy), default(CieXyy)); + Assert.True(default == default(CieXyy)); + Assert.False(default != default(CieXyy)); + Assert.Equal(default, default(CieXyy)); Assert.Equal(new CieXyy(1, 0, 1), new CieXyy(1, 0, 1)); Assert.Equal(new CieXyy(Vector3.One), new CieXyy(Vector3.One)); Assert.False(x.Equals(y)); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndCieLabConversionTest.cs b/tests/ImageSharp.Tests/ColorProfiles/CieXyzAndCieLabConversionTest.cs similarity index 51% rename from tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndCieLabConversionTest.cs rename to tests/ImageSharp.Tests/ColorProfiles/CieXyzAndCieLabConversionTest.cs index 3ea4228e5e..cb4d028895 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndCieLabConversionTest.cs +++ b/tests/ImageSharp.Tests/ColorProfiles/CieXyzAndCieLabConversionTest.cs @@ -1,10 +1,9 @@ -// Copyright (c) Six Labors. +// Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion; +using SixLabors.ImageSharp.ColorProfiles; -namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion; +namespace SixLabors.ImageSharp.Tests.ColorProfiles; /// /// Tests - conversions. @@ -15,11 +14,8 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion; /// public class CieXyzAndCieLabConversionTest { - private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0001F); + private static readonly ApproximateColorProfileComparer Comparer = new(.0001f); - /// - /// Tests conversion from to (). - /// [Theory] [InlineData(100, 0, 0, 0.95047, 1, 1.08883)] [InlineData(0, 0, 0, 0, 0, 0)] @@ -28,14 +24,14 @@ public class CieXyzAndCieLabConversionTest [InlineData(0, 0, -172.4138, 0, 0, 1.08883)] [InlineData(45.6398, 39.8753, 35.2091, 0.216938, 0.150041, 0.048850)] [InlineData(77.1234, -40.1235, 78.1120, 0.358530, 0.517372, 0.076273)] - [InlineData(10, -400, 20, 0, 0.011260, 0)] + [InlineData(10, -400, 20, -0.08712, 0.01126, -0.00192)] public void Convert_Lab_to_Xyz(float l, float a, float b, float x, float y, float z) { // Arrange - var input = new CieLab(l, a, b, Illuminants.D65); - var options = new ColorSpaceConverterOptions { WhitePoint = Illuminants.D65, TargetLabWhitePoint = Illuminants.D65 }; - var converter = new ColorSpaceConverter(options); - var expected = new CieXyz(x, y, z); + CieLab input = new(l, a, b); + ColorConversionOptions options = new() { WhitePoint = KnownIlluminants.D65, TargetWhitePoint = KnownIlluminants.D65 }; + ColorProfileConverter converter = new(options); + CieXyz expected = new(x, y, z); Span inputSpan = new CieLab[5]; inputSpan.Fill(input); @@ -43,21 +39,18 @@ public class CieXyzAndCieLabConversionTest Span actualSpan = new CieXyz[5]; // Act - var actual = converter.ToCieXyz(input); - converter.Convert(inputSpan, actualSpan); + CieXyz actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); + Assert.Equal(expected, actual, Comparer); for (int i = 0; i < actualSpan.Length; i++) { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); + Assert.Equal(expected, actualSpan[i], Comparer); } } - /// - /// Tests conversion from () to . - /// [Theory] [InlineData(0.95047, 1, 1.08883, 100, 0, 0)] [InlineData(0, 0, 0, 0, 0, 0)] @@ -68,10 +61,10 @@ public class CieXyzAndCieLabConversionTest public void Convert_Xyz_to_Lab(float x, float y, float z, float l, float a, float b) { // Arrange - var input = new CieXyz(x, y, z); - var options = new ColorSpaceConverterOptions { WhitePoint = Illuminants.D65, TargetLabWhitePoint = Illuminants.D65 }; - var converter = new ColorSpaceConverter(options); - var expected = new CieLab(l, a, b); + CieXyz input = new(x, y, z); + ColorConversionOptions options = new() { WhitePoint = KnownIlluminants.D65, TargetWhitePoint = KnownIlluminants.D65 }; + ColorProfileConverter converter = new(options); + CieLab expected = new(l, a, b); Span inputSpan = new CieXyz[5]; inputSpan.Fill(input); @@ -79,15 +72,15 @@ public class CieXyzAndCieLabConversionTest Span actualSpan = new CieLab[5]; // Act - var actual = converter.ToCieLab(input); - converter.Convert(inputSpan, actualSpan); + CieLab actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); + Assert.Equal(expected, actual, Comparer); for (int i = 0; i < actualSpan.Length; i++) { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); + Assert.Equal(expected, actualSpan[i], Comparer); } } } diff --git a/tests/ImageSharp.Tests/ColorProfiles/CieXyzAndCieLchConversionTests.cs b/tests/ImageSharp.Tests/ColorProfiles/CieXyzAndCieLchConversionTests.cs new file mode 100644 index 0000000000..bde3b8e17b --- /dev/null +++ b/tests/ImageSharp.Tests/ColorProfiles/CieXyzAndCieLchConversionTests.cs @@ -0,0 +1,70 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using SixLabors.ImageSharp.ColorProfiles; + +namespace SixLabors.ImageSharp.Tests.ColorProfiles; + +/// +/// Tests - conversions. +/// +public class CieXyzAndCieLchConversionTests +{ + private static readonly ApproximateColorProfileComparer Comparer = new(.0002f); + + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(0.360555, 0.936901, 0.1001514, 97.50697, 161.235321, 143.157)] + public void Convert_CieXyz_to_CieLch(float x, float y, float yl, float l, float c, float h) + { + // Arrange + CieXyz input = new(x, y, yl); + CieLch expected = new(l, c, h); + ColorProfileConverter converter = new(); + + Span inputSpan = new CieXyz[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieLch[5]; + + // Act + CieLch actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } + + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(97.50697, 161.235321, 143.157, 0.3605551, 0.936901, 0.1001514)] + public void Convert_CieLch_to_CieXyz(float l, float c, float h, float x, float y, float yl) + { + // Arrange + CieLch input = new(l, c, h); + CieXyz expected = new(x, y, yl); + ColorProfileConverter converter = new(); + + Span inputSpan = new CieLch[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieXyz[5]; + + // Act + CieXyz actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } +} diff --git a/tests/ImageSharp.Tests/ColorProfiles/CieXyzAndCieLchuvConversionTests.cs b/tests/ImageSharp.Tests/ColorProfiles/CieXyzAndCieLchuvConversionTests.cs new file mode 100644 index 0000000000..fa604250f2 --- /dev/null +++ b/tests/ImageSharp.Tests/ColorProfiles/CieXyzAndCieLchuvConversionTests.cs @@ -0,0 +1,69 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using SixLabors.ImageSharp.ColorProfiles; + +namespace SixLabors.ImageSharp.Tests.ColorProfiles; + +/// +/// Tests - conversions. +/// +public class CieXyzAndCieLchuvConversionTests +{ + private static readonly ApproximateColorProfileComparer Comparer = new(.0002f); + + [Theory] + [InlineData(0.360555, 0.936901, 0.1001514, 97.50697, 177.345169, 142.601547)] + public void Convert_CieXyz_to_CieLchuv(float x, float y, float yl, float l, float c, float h) + { + // Arrange + CieXyz input = new(x, y, yl); + CieLchuv expected = new(l, c, h); + ColorProfileConverter converter = new(); + + Span inputSpan = new CieXyz[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieLchuv[5]; + + // Act + CieLchuv actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } + + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(97.50697, 177.345169, 142.601547, 0.360555, 0.936901, 0.1001514)] + public void Convert_CieLchuv_to_CieXyz(float l, float c, float h, float x, float y, float yl) + { + // Arrange + CieLchuv input = new(l, c, h); + CieXyz expected = new(x, y, yl); + ColorProfileConverter converter = new(); + + Span inputSpan = new CieLchuv[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieXyz[5]; + + // Act + CieXyz actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } +} diff --git a/tests/ImageSharp.Tests/ColorProfiles/CieXyzAndCieLuvConversionTest.cs b/tests/ImageSharp.Tests/ColorProfiles/CieXyzAndCieLuvConversionTest.cs new file mode 100644 index 0000000000..944b990054 --- /dev/null +++ b/tests/ImageSharp.Tests/ColorProfiles/CieXyzAndCieLuvConversionTest.cs @@ -0,0 +1,87 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using SixLabors.ImageSharp.ColorProfiles; + +namespace SixLabors.ImageSharp.Tests.ColorProfiles; + +/// +/// Tests - conversions. +/// +/// +/// Test data generated using: +/// +/// +public class CieXyzAndCieLuvConversionTest +{ + private static readonly ApproximateColorProfileComparer Comparer = new(.0002f); + + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(0.000493, 0.000111, 0, 0.10026589, 0.9332349, -0.00704865158)] + [InlineData(0.569310, 0.407494, 0.365843, 70.0000, 86.3524, 2.8240)] + [InlineData(0.012191, 0.011260, 0.025939, 9.9998, -1.2343, -9.9999)] + [InlineData(0.950470, 1.000000, 1.088830, 100, 0, 0)] + [InlineData(0.001255, 0.001107, 0.000137, 0.9999, 0.9998, 1.0004)] + public void Convert_Xyz_To_Luv(float x, float y, float z, float l, float u, float v) + { + // Arrange + CieXyz input = new(x, y, z); + CieLuv expected = new(l, u, v); + + ColorConversionOptions options = new() { WhitePoint = KnownIlluminants.D65, TargetWhitePoint = KnownIlluminants.D65 }; + ColorProfileConverter converter = new(options); + + Span inputSpan = new CieXyz[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieLuv[5]; + + // Act + CieLuv actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } + + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(0, 100, 50, 0, 0, 0)] + [InlineData(0.1, 100, 50, 0.000493, 0.000111, -0.000709)] + [InlineData(70.0000, 86.3525, 2.8240, 0.569310, 0.407494, 0.365843)] + [InlineData(10.0000, -1.2345, -10.0000, 0.012191, 0.011260, 0.025939)] + [InlineData(100, 0, 0, 0.950470, 1.000000, 1.088830)] + [InlineData(1, 1, 1, 0.001255, 0.001107, 0.000137)] + public void Convert_Luv_To_Xyz(float l, float u, float v, float x, float y, float z) + { + // Arrange + CieLuv input = new(l, u, v); + CieXyz expected = new(x, y, z); + + ColorConversionOptions options = new() { WhitePoint = KnownIlluminants.D65, TargetWhitePoint = KnownIlluminants.D65 }; + ColorProfileConverter converter = new(options); + + Span inputSpan = new CieLuv[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieXyz[5]; + + // Act + CieXyz actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } +} diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndCieXyyConversionTest.cs b/tests/ImageSharp.Tests/ColorProfiles/CieXyzAndCieXyyConversionTest.cs similarity index 55% rename from tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndCieXyyConversionTest.cs rename to tests/ImageSharp.Tests/ColorProfiles/CieXyzAndCieXyyConversionTest.cs index 5ef5c4d21a..7b1d0ac781 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndCieXyyConversionTest.cs +++ b/tests/ImageSharp.Tests/ColorProfiles/CieXyzAndCieXyyConversionTest.cs @@ -1,10 +1,9 @@ -// Copyright (c) Six Labors. +// Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion; +using SixLabors.ImageSharp.ColorProfiles; -namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion; +namespace SixLabors.ImageSharp.Tests.ColorProfiles; /// /// Tests - conversions. @@ -15,18 +14,18 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion; /// public class CieXyzAndCieXyyConversionTest { - private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0001F); - private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); + private static readonly ApproximateColorProfileComparer Comparer = new(.0001F); [Theory] [InlineData(0.436075, 0.222504, 0.013932, 0.648427, 0.330856, 0.222504)] [InlineData(0.964220, 1.000000, 0.825210, 0.345669, 0.358496, 1.000000)] [InlineData(0.434119, 0.356820, 0.369447, 0.374116, 0.307501, 0.356820)] [InlineData(0, 0, 0, 0.538842, 0.000000, 0.000000)] - public void Convert_xyY_to_XYZ(float xyzX, float xyzY, float xyzZ, float x, float y, float yl) + public void Convert_Xyy_To_Xyz(float xyzX, float xyzY, float xyzZ, float x, float y, float yl) { - var input = new CieXyy(x, y, yl); - var expected = new CieXyz(xyzX, xyzY, xyzZ); + CieXyy input = new(x, y, yl); + CieXyz expected = new(xyzX, xyzY, xyzZ); + ColorProfileConverter converter = new(); Span inputSpan = new CieXyy[5]; inputSpan.Fill(input); @@ -34,15 +33,15 @@ public class CieXyzAndCieXyyConversionTest Span actualSpan = new CieXyz[5]; // Act - var actual = ColorSpaceConverter.ToCieXyz(input); - ColorSpaceConverter.Convert(inputSpan, actualSpan); + CieXyz actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); + Assert.Equal(expected, actual, Comparer); for (int i = 0; i < actualSpan.Length; i++) { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); + Assert.Equal(expected, actualSpan[i], Comparer); } } @@ -51,10 +50,11 @@ public class CieXyzAndCieXyyConversionTest [InlineData(0.964220, 1.000000, 0.825210, 0.345669, 0.358496, 1.000000)] [InlineData(0.434119, 0.356820, 0.369447, 0.374116, 0.307501, 0.356820)] [InlineData(0.231809, 0, 0.077528, 0.749374, 0.000000, 0.000000)] - public void Convert_XYZ_to_xyY(float xyzX, float xyzY, float xyzZ, float x, float y, float yl) + public void Convert_Xyz_to_Xyy(float xyzX, float xyzY, float xyzZ, float x, float y, float yl) { - var input = new CieXyz(xyzX, xyzY, xyzZ); - var expected = new CieXyy(x, y, yl); + CieXyz input = new(xyzX, xyzY, xyzZ); + CieXyy expected = new(x, y, yl); + ColorProfileConverter converter = new(); Span inputSpan = new CieXyz[5]; inputSpan.Fill(input); @@ -62,15 +62,15 @@ public class CieXyzAndCieXyyConversionTest Span actualSpan = new CieXyy[5]; // Act - var actual = ColorSpaceConverter.ToCieXyy(input); - ColorSpaceConverter.Convert(inputSpan, actualSpan); + CieXyy actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); + Assert.Equal(expected, actual, Comparer); for (int i = 0; i < actualSpan.Length; i++) { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); + Assert.Equal(expected, actualSpan[i], Comparer); } } } diff --git a/tests/ImageSharp.Tests/ColorProfiles/CieXyzAndHslConversionTests.cs b/tests/ImageSharp.Tests/ColorProfiles/CieXyzAndHslConversionTests.cs new file mode 100644 index 0000000000..cffdb008b8 --- /dev/null +++ b/tests/ImageSharp.Tests/ColorProfiles/CieXyzAndHslConversionTests.cs @@ -0,0 +1,70 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using SixLabors.ImageSharp.ColorProfiles; + +namespace SixLabors.ImageSharp.Tests.ColorProfiles; + +/// +/// Tests - conversions. +/// +public class CieXyzAndHslConversionTests +{ + private static readonly ApproximateColorProfileComparer Comparer = new(.0002F); + + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(0.360555, 0.936901, 0.1001514, 120, 1, 0.5)] + public void Convert_CieXyz_to_Hsl(float x, float y, float yl, float h, float s, float l) + { + // Arrange + CieXyz input = new(x, y, yl); + Hsl expected = new(h, s, l); + ColorProfileConverter converter = new(); + + Span inputSpan = new CieXyz[5]; + inputSpan.Fill(input); + + Span actualSpan = new Hsl[5]; + + // Act + Hsl actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } + + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(120, 1, 0.5, 0.38506496, 0.716878653, 0.09710451)] + public void Convert_Hsl_to_CieXyz(float h, float s, float l, float x, float y, float yl) + { + // Arrange + Hsl input = new(h, s, l); + CieXyz expected = new(x, y, yl); + ColorProfileConverter converter = new(); + + Span inputSpan = new Hsl[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieXyz[5]; + + // Act + CieXyz actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } +} diff --git a/tests/ImageSharp.Tests/ColorProfiles/CieXyzAndHsvConversionTests.cs b/tests/ImageSharp.Tests/ColorProfiles/CieXyzAndHsvConversionTests.cs new file mode 100644 index 0000000000..d4a0022a47 --- /dev/null +++ b/tests/ImageSharp.Tests/ColorProfiles/CieXyzAndHsvConversionTests.cs @@ -0,0 +1,70 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using SixLabors.ImageSharp.ColorProfiles; + +namespace SixLabors.ImageSharp.Tests.ColorProfiles; + +/// +/// Tests - conversions. +/// +public class CieXyzAndHsvConversionTests +{ + private static readonly ApproximateColorProfileComparer Comparer = new(.0002F); + + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(0.360555, 0.936901, 0.1001514, 120, 1, 0.9999999)] + public void Convert_CieXyz_to_Hsv(float x, float y, float yl, float h, float s, float v) + { + // Arrange + CieXyz input = new(x, y, yl); + Hsv expected = new(h, s, v); + ColorProfileConverter converter = new(); + + Span inputSpan = new CieXyz[5]; + inputSpan.Fill(input); + + Span actualSpan = new Hsv[5]; + + // Act + Hsv actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } + + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(120, 1, 0.9999999, 0.3850648, 0.7168785, 0.09710446)] + public void Convert_Hsv_to_CieXyz(float h, float s, float v, float x, float y, float yl) + { + // Arrange + Hsv input = new(h, s, v); + CieXyz expected = new(x, y, yl); + ColorProfileConverter converter = new(); + + Span inputSpan = new Hsv[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieXyz[5]; + + // Act + CieXyz actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } +} diff --git a/tests/ImageSharp.Tests/ColorProfiles/CieXyzAndHunterLabConversionTest.cs b/tests/ImageSharp.Tests/ColorProfiles/CieXyzAndHunterLabConversionTest.cs new file mode 100644 index 0000000000..aef26fe9a3 --- /dev/null +++ b/tests/ImageSharp.Tests/ColorProfiles/CieXyzAndHunterLabConversionTest.cs @@ -0,0 +1,74 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using SixLabors.ImageSharp.ColorProfiles; + +namespace SixLabors.ImageSharp.Tests.ColorProfiles; + +/// +/// Tests - conversions. +/// +/// +/// Test data generated using: +/// +/// +public class CieXyzAndHunterLabConversionTest +{ + private static readonly ApproximateColorProfileComparer Comparer = new(.0002f); + + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(0.360555, 0.936901, 0.1001514, 96.79365, -100.951096, 49.35507)] + public void Convert_Xyz_To_HunterLab(float x, float y, float z, float l, float a, float b) + { + // Arrange + CieXyz input = new(x, y, z); + HunterLab expected = new(l, a, b); + ColorProfileConverter converter = new(); + + Span inputSpan = new CieXyz[5]; + inputSpan.Fill(input); + + Span actualSpan = new HunterLab[5]; + + // Act + HunterLab actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } + + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(31.6467056, -33.00599, 25.67032, 0.0385420471, 0.10015139, -0.0317969956)] + public void Convert_HunterLab_To_Xyz(float l, float a, float b, float x, float y, float z) + { + // Arrange + HunterLab input = new(l, a, b); + CieXyz expected = new(x, y, z); + ColorProfileConverter converter = new(); + + Span inputSpan = new HunterLab[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieXyz[5]; + + // Act + CieXyz actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } +} diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndLmsConversionTest.cs b/tests/ImageSharp.Tests/ColorProfiles/CieXyzAndLmsConversionTest.cs similarity index 53% rename from tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndLmsConversionTest.cs rename to tests/ImageSharp.Tests/ColorProfiles/CieXyzAndLmsConversionTest.cs index 33bdc6e935..185fcd256c 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndLmsConversionTest.cs +++ b/tests/ImageSharp.Tests/ColorProfiles/CieXyzAndLmsConversionTest.cs @@ -1,10 +1,9 @@ -// Copyright (c) Six Labors. +// Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion; +using SixLabors.ImageSharp.ColorProfiles; -namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion; +namespace SixLabors.ImageSharp.Tests.ColorProfiles; /// /// Tests - conversions. @@ -14,11 +13,8 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion; /// public class CieXyzAndLmsConversionTest { - private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0001F); + private static readonly ApproximateColorProfileComparer Comparer = new(.0001f); - /// - /// Tests conversion from () to . - /// [Theory] [InlineData(0.941428535, 1.040417467, 1.089532651, 0.95047, 1, 1.08883)] [InlineData(0, 0, 0, 0, 0, 0)] @@ -26,12 +22,12 @@ public class CieXyzAndLmsConversionTest [InlineData(0.2664, 1.7135, -0.0685, 0, 1, 0)] [InlineData(-0.175737162, 0.039960061, 1.121059368, 0, 0, 1.08883)] [InlineData(0.2262677362, 0.0961411609, 0.0484570397, 0.216938, 0.150041, 0.048850)] - public void Convert_Lms_to_CieXyz(float l, float m, float s, float x, float y, float z) + public void Convert_Lms_To_CieXyz(float l, float m, float s, float x, float y, float z) { // Arrange - var input = new Lms(l, m, s); - var converter = new ColorSpaceConverter(); - var expected = new CieXyz(x, y, z); + Lms input = new(l, m, s); + ColorProfileConverter converter = new(); + CieXyz expected = new(x, y, z); Span inputSpan = new Lms[5]; inputSpan.Fill(input); @@ -39,21 +35,18 @@ public class CieXyzAndLmsConversionTest Span actualSpan = new CieXyz[5]; // Act - var actual = converter.ToCieXyz(input); - converter.Convert(inputSpan, actualSpan); + CieXyz actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); + Assert.Equal(expected, actual, Comparer); for (int i = 0; i < actualSpan.Length; i++) { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); + Assert.Equal(expected, actualSpan[i], Comparer); } } - /// - /// Tests conversion from () to . - /// [Theory] [InlineData(0.95047, 1, 1.08883, 0.941428535, 1.040417467, 1.089532651)] [InlineData(0, 0, 0, 0, 0, 0)] @@ -61,12 +54,12 @@ public class CieXyzAndLmsConversionTest [InlineData(0, 1, 0, 0.2664, 1.7135, -0.0685)] [InlineData(0, 0, 1.08883, -0.175737162, 0.039960061, 1.121059368)] [InlineData(0.216938, 0.150041, 0.048850, 0.2262677362, 0.0961411609, 0.0484570397)] - public void Convert_CieXyz_to_Lms(float x, float y, float z, float l, float m, float s) + public void Convert_CieXyz_To_Lms(float x, float y, float z, float l, float m, float s) { // Arrange - var input = new CieXyz(x, y, z); - var converter = new ColorSpaceConverter(); - var expected = new Lms(l, m, s); + CieXyz input = new(x, y, z); + ColorProfileConverter converter = new(); + Lms expected = new(l, m, s); Span inputSpan = new CieXyz[5]; inputSpan.Fill(input); @@ -74,15 +67,15 @@ public class CieXyzAndLmsConversionTest Span actualSpan = new Lms[5]; // Act - var actual = converter.ToLms(input); - converter.Convert(inputSpan, actualSpan); + Lms actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); + Assert.Equal(expected, actual, Comparer); for (int i = 0; i < actualSpan.Length; i++) { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); + Assert.Equal(expected, actualSpan[i], Comparer); } } } diff --git a/tests/ImageSharp.Tests/ColorProfiles/CieXyzAndYCbCrConversionTests.cs b/tests/ImageSharp.Tests/ColorProfiles/CieXyzAndYCbCrConversionTests.cs new file mode 100644 index 0000000000..475673da84 --- /dev/null +++ b/tests/ImageSharp.Tests/ColorProfiles/CieXyzAndYCbCrConversionTests.cs @@ -0,0 +1,70 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using SixLabors.ImageSharp.ColorProfiles; + +namespace SixLabors.ImageSharp.Tests.ColorProfiles; + +/// +/// Tests - conversions. +/// +public class CieXyzAndYCbCrConversionTests +{ + private static readonly ApproximateColorProfileComparer Comparer = new(.0002f); + + [Theory] + [InlineData(0, 0, 0, 0, 128, 128)] + [InlineData(0.360555, 0.936901, 0.1001514, 149.685, 43.52769, 21.23457)] + public void Convert_CieXyz_to_YCbCr(float x, float y, float z, float y2, float cb, float cr) + { + // Arrange + CieXyz input = new(x, y, z); + YCbCr expected = new(y2, cb, cr); + ColorProfileConverter converter = new(); + + Span inputSpan = new CieXyz[5]; + inputSpan.Fill(input); + + Span actualSpan = new YCbCr[5]; + + // Act + YCbCr actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } + + [Theory] + [InlineData(0, 128, 128, 0, 0, 0)] + [InlineData(149.685, 43.52769, 21.23457, 0.38506496, 0.716878653, 0.0971045)] + public void Convert_YCbCr_to_CieXyz(float y2, float cb, float cr, float x, float y, float z) + { + // Arrange + YCbCr input = new(y2, cb, cr); + CieXyz expected = new(x, y, z); + ColorProfileConverter converter = new(); + + Span inputSpan = new YCbCr[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieXyz[5]; + + // Act + CieXyz actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } +} diff --git a/tests/ImageSharp.Tests/Colorspaces/CieXyzTests.cs b/tests/ImageSharp.Tests/ColorProfiles/CieXyzTests.cs similarity index 65% rename from tests/ImageSharp.Tests/Colorspaces/CieXyzTests.cs rename to tests/ImageSharp.Tests/ColorProfiles/CieXyzTests.cs index 6de961cf1b..88138304a8 100644 --- a/tests/ImageSharp.Tests/Colorspaces/CieXyzTests.cs +++ b/tests/ImageSharp.Tests/ColorProfiles/CieXyzTests.cs @@ -1,10 +1,10 @@ -// Copyright (c) Six Labors. +// Copyright (c) Six Labors. // Licensed under the Six Labors Split License. using System.Numerics; -using SixLabors.ImageSharp.ColorSpaces; +using SixLabors.ImageSharp.ColorProfiles; -namespace SixLabors.ImageSharp.Tests.Colorspaces; +namespace SixLabors.ImageSharp.Tests.ColorProfiles; /// /// Tests the struct. @@ -17,7 +17,7 @@ public class CieXyzTests const float x = 75F; const float y = 64F; const float z = 287F; - var cieXyz = new CieXyz(x, y, z); + CieXyz cieXyz = new(x, y, z); Assert.Equal(x, cieXyz.X); Assert.Equal(y, cieXyz.Y); @@ -27,12 +27,12 @@ public class CieXyzTests [Fact] public void CieXyzEquality() { - var x = default(CieXyz); - var y = new CieXyz(Vector3.One); + CieXyz x = default; + CieXyz y = new(Vector3.One); - Assert.True(default(CieXyz) == default(CieXyz)); - Assert.False(default(CieXyz) != default(CieXyz)); - Assert.Equal(default(CieXyz), default(CieXyz)); + Assert.True(default == default(CieXyz)); + Assert.False(default != default(CieXyz)); + Assert.Equal(default, default(CieXyz)); Assert.Equal(new CieXyz(1, 0, 1), new CieXyz(1, 0, 1)); Assert.Equal(new CieXyz(Vector3.One), new CieXyz(Vector3.One)); Assert.False(x.Equals(y)); diff --git a/tests/ImageSharp.Tests/ColorProfiles/CmykAndCieLchConversionTests.cs b/tests/ImageSharp.Tests/ColorProfiles/CmykAndCieLchConversionTests.cs new file mode 100644 index 0000000000..a5230eb312 --- /dev/null +++ b/tests/ImageSharp.Tests/ColorProfiles/CmykAndCieLchConversionTests.cs @@ -0,0 +1,69 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using SixLabors.ImageSharp.ColorProfiles; + +namespace SixLabors.ImageSharp.Tests.ColorProfiles; + +/// +/// Tests - conversions. +/// +public class CmykAndCieLchConversionTests +{ + private static readonly ApproximateColorProfileComparer Comparer = new(.0002f); + + [Theory] + [InlineData(0.360555, 0.1036901, 0.818514, 0.274615, 62.85025, 64.77041, 118.2425)] + public void Convert_Cmyk_To_CieLch(float c, float m, float y, float k, float l, float c2, float h) + { + // Arrange + Cmyk input = new(c, m, y, k); + CieLch expected = new(l, c2, h); + ColorProfileConverter converter = new(); + + Span inputSpan = new Cmyk[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieLch[5]; + + // Act + CieLch actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } + + [Theory] + [InlineData(100, 3.81656E-05, 218.6598, 0, 1.192093E-07, 0, 5.960464E-08)] + [InlineData(62.85025, 64.77041, 118.2425, 0.286581, 0, 0.7975187, 0.34983)] + public void Convert_CieLch_To_Cmyk(float l, float c2, float h, float c, float m, float y, float k) + { + // Arrange + CieLch input = new(l, c2, h); + Cmyk expected = new(c, m, y, k); + ColorProfileConverter converter = new(); + + Span inputSpan = new CieLch[5]; + inputSpan.Fill(input); + + Span actualSpan = new Cmyk[5]; + + // Act + Cmyk actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } +} diff --git a/tests/ImageSharp.Tests/ColorProfiles/CmykAndCieLuvConversionTests.cs b/tests/ImageSharp.Tests/ColorProfiles/CmykAndCieLuvConversionTests.cs new file mode 100644 index 0000000000..cfbd080541 --- /dev/null +++ b/tests/ImageSharp.Tests/ColorProfiles/CmykAndCieLuvConversionTests.cs @@ -0,0 +1,70 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using SixLabors.ImageSharp.ColorProfiles; + +namespace SixLabors.ImageSharp.Tests.ColorProfiles; + +/// +/// Tests - conversions. +/// +public class CmykAndCieLuvConversionTests +{ + private static readonly ApproximateColorProfileComparer Comparer = new(.0002f); + + [Theory] + [InlineData(0, 0, 0, 0, 100, -1.937151E-05, -3.874302E-05)] + [InlineData(0.360555, 0.1036901, 0.818514, 0.274615, 62.85024, -24.4844189, 54.8588524)] + public void Convert_Cmyk_To_CieLuv(float c, float m, float y, float k, float l, float u, float v) + { + // Arrange + Cmyk input = new(c, m, y, k); + CieLuv expected = new(l, u, v); + ColorProfileConverter converter = new(); + + Span inputSpan = new Cmyk[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieLuv[5]; + + // Act + CieLuv actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } + + [Theory] + [InlineData(100, -1.937151E-05, -3.874302E-05, 0, 5.96046448E-08, 0, 0)] + [InlineData(62.85024, -24.4844189, 54.8588524, 0.2865809, 0, 0.797518551, 0.3498301)] + public void Convert_CieLuv_To_Cmyk(float l, float u, float v, float c, float m, float y, float k) + { + // Arrange + CieLuv input = new(l, u, v); + Cmyk expected = new(c, m, y, k); + ColorProfileConverter converter = new(); + + Span inputSpan = new CieLuv[5]; + inputSpan.Fill(input); + + Span actualSpan = new Cmyk[5]; + + // Act + Cmyk actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } +} diff --git a/tests/ImageSharp.Tests/ColorProfiles/CmykAndYCbCrConversionTests.cs b/tests/ImageSharp.Tests/ColorProfiles/CmykAndYCbCrConversionTests.cs new file mode 100644 index 0000000000..64b47e2b97 --- /dev/null +++ b/tests/ImageSharp.Tests/ColorProfiles/CmykAndYCbCrConversionTests.cs @@ -0,0 +1,70 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using SixLabors.ImageSharp.ColorProfiles; + +namespace SixLabors.ImageSharp.Tests.ColorProfiles; + +/// +/// Tests - conversions. +/// +public class CmykAndYCbCrConversionTests +{ + private static readonly ApproximateColorProfileComparer Comparer = new(.0002F); + + [Theory] + [InlineData(0, 0, 0, 0, 255, 128, 128)] + [InlineData(0.360555, 0.1036901, 0.818514, 0.274615, 136.5134, 69.90555, 114.9948)] + public void Convert_Cmyk_To_YCbCr(float c, float m, float y, float k, float y2, float cb, float cr) + { + // Arrange + Cmyk input = new(c, m, y, k); + YCbCr expected = new(y2, cb, cr); + ColorProfileConverter converter = new(); + + Span inputSpan = new Cmyk[5]; + inputSpan.Fill(input); + + Span actualSpan = new YCbCr[5]; + + // Act + YCbCr actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } + + [Theory] + [InlineData(255, 128, 128, 0, 0, 0, 5.960464E-08)] + [InlineData(136.5134, 69.90555, 114.9948, 0.2891567, 0, 0.7951807, 0.3490196)] + public void Convert_YCbCr_To_Cmyk(float y2, float cb, float cr, float c, float m, float y, float k) + { + // Arrange + YCbCr input = new(y2, cb, cr); + Cmyk expected = new(c, m, y, k); + ColorProfileConverter converter = new(); + + Span inputSpan = new YCbCr[5]; + inputSpan.Fill(input); + + Span actualSpan = new Cmyk[5]; + + // Act + Cmyk actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } +} diff --git a/tests/ImageSharp.Tests/Colorspaces/CmykTests.cs b/tests/ImageSharp.Tests/ColorProfiles/CmykTests.cs similarity index 67% rename from tests/ImageSharp.Tests/Colorspaces/CmykTests.cs rename to tests/ImageSharp.Tests/ColorProfiles/CmykTests.cs index b4e55ed24c..e2044a75d0 100644 --- a/tests/ImageSharp.Tests/Colorspaces/CmykTests.cs +++ b/tests/ImageSharp.Tests/ColorProfiles/CmykTests.cs @@ -1,10 +1,10 @@ -// Copyright (c) Six Labors. +// Copyright (c) Six Labors. // Licensed under the Six Labors Split License. using System.Numerics; -using SixLabors.ImageSharp.ColorSpaces; +using SixLabors.ImageSharp.ColorProfiles; -namespace SixLabors.ImageSharp.Tests.Colorspaces; +namespace SixLabors.ImageSharp.Tests.ColorProfiles; /// /// Tests the struct. @@ -18,7 +18,7 @@ public class CmykTests const float m = .64F; const float y = .87F; const float k = .334F; - var cmyk = new Cmyk(c, m, y, k); + Cmyk cmyk = new(c, m, y, k); Assert.Equal(c, cmyk.C); Assert.Equal(m, cmyk.M); @@ -29,12 +29,12 @@ public class CmykTests [Fact] public void CmykEquality() { - var x = default(Cmyk); - var y = new Cmyk(Vector4.One); + Cmyk x = default; + Cmyk y = new(Vector4.One); - Assert.True(default(Cmyk) == default(Cmyk)); - Assert.False(default(Cmyk) != default(Cmyk)); - Assert.Equal(default(Cmyk), default(Cmyk)); + Assert.True(default == default(Cmyk)); + Assert.False(default != default(Cmyk)); + Assert.Equal(default, default(Cmyk)); Assert.Equal(new Cmyk(1, 0, 1, 0), new Cmyk(1, 0, 1, 0)); Assert.Equal(new Cmyk(Vector4.One), new Cmyk(Vector4.One)); Assert.False(x.Equals(y)); diff --git a/tests/ImageSharp.Tests/ColorProfiles/ColorProfileConverterChomaticAdaptationTests.cs b/tests/ImageSharp.Tests/ColorProfiles/ColorProfileConverterChomaticAdaptationTests.cs new file mode 100644 index 0000000000..a90e5b9e86 --- /dev/null +++ b/tests/ImageSharp.Tests/ColorProfiles/ColorProfileConverterChomaticAdaptationTests.cs @@ -0,0 +1,203 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using SixLabors.ImageSharp.ColorProfiles; + +namespace SixLabors.ImageSharp.Tests.ColorProfiles; + +/// +/// Tests chromatic adaptation within the . +/// Test data generated using: +/// +/// +/// +public class ColorProfileConverterChomaticAdaptationTests +{ + private static readonly ApproximateColorProfileComparer Comparer = new(.0001F); + + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(1, 1, 1, 1, 1, 1)] + [InlineData(0.206162, 0.260277, 0.746717, 0.220000, 0.130000, 0.780000)] + public void Adapt_RGB_WideGamutRGB_To_sRGB(float r1, float g1, float b1, float r2, float g2, float b2) + { + // Arrange + Rgb input = new(r1, g1, b1); + Rgb expected = new(r2, g2, b2); + ColorConversionOptions options = new() + { + RgbWorkingSpace = KnownRgbWorkingSpaces.WideGamutRgb, + TargetRgbWorkingSpace = KnownRgbWorkingSpaces.SRgb + }; + ColorProfileConverter converter = new(options); + + // Action + Rgb actual = converter.Convert(input); + + // Assert + Assert.Equal(expected, actual, Comparer); + } + + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(1, 1, 1, 1, 1, 1)] + [InlineData(0.220000, 0.130000, 0.780000, 0.206162, 0.260277, 0.746717)] + public void Adapt_RGB_SRGB_To_WideGamutRGB(float r1, float g1, float b1, float r2, float g2, float b2) + { + // Arrange + Rgb input = new(r1, g1, b1); + Rgb expected = new(r2, g2, b2); + ColorConversionOptions options = new() + { + RgbWorkingSpace = KnownRgbWorkingSpaces.SRgb, + TargetRgbWorkingSpace = KnownRgbWorkingSpaces.WideGamutRgb + }; + ColorProfileConverter converter = new(options); + + // Action + Rgb actual = converter.Convert(input); + + // Assert + Assert.Equal(expected, actual, Comparer); + } + + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(22, 33, 1, 22.269869, 32.841164, 1.633926)] + public void Adapt_Lab_D65_To_D50(float l1, float a1, float b1, float l2, float a2, float b2) + { + // Arrange + CieLab input = new(l1, a1, b1); + CieLab expected = new(l2, a2, b2); + ColorConversionOptions options = new() + { + WhitePoint = KnownIlluminants.D65, + TargetWhitePoint = KnownIlluminants.D50 + }; + ColorProfileConverter converter = new(options); + + // Action + CieLab actual = converter.Convert(input); + + // Assert + Assert.Equal(expected, actual, Comparer); + } + + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(0.5, 0.5, 0.5, 0.510286, 0.501489, 0.378970)] + public void Adapt_Xyz_D65_To_D50_Bradford(float x1, float y1, float z1, float x2, float y2, float z2) + { + // Arrange + CieXyz input = new(x1, y1, z1); + CieXyz expected = new(x2, y2, z2); + ColorConversionOptions options = new() + { + WhitePoint = KnownIlluminants.D65, + TargetWhitePoint = KnownIlluminants.D50, + AdaptationMatrix = KnownChromaticAdaptationMatrices.Bradford + }; + + ColorProfileConverter converter = new(options); + + // Action + CieXyz actual = converter.Convert(input); + + // Assert + Assert.Equal(expected, actual, Comparer); + } + + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(0.5, 0.5, 0.5, 0.507233, 0.500000, 0.378943)] + public void Adapt_Xyz_D65_To_D50_XyzScaling(float x1, float y1, float z1, float x2, float y2, float z2) + { + // Arrange + CieXyz input = new(x1, y1, z1); + CieXyz expected = new(x2, y2, z2); + ColorConversionOptions options = new() + { + WhitePoint = KnownIlluminants.D65, + TargetWhitePoint = KnownIlluminants.D50, + AdaptationMatrix = KnownChromaticAdaptationMatrices.XyzScaling + }; + + ColorProfileConverter converter = new(options); + + // Action + CieXyz actual = converter.Convert(input); + + // Assert + Assert.Equal(expected, actual, Comparer); + } + + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(22, 33, 1, 22.28086, 33.0681534, 1.30099022)] + public void Adapt_HunterLab_D65_To_D50(float l1, float a1, float b1, float l2, float a2, float b2) + { + // Arrange + HunterLab input = new(l1, a1, b1); + HunterLab expected = new(l2, a2, b2); + ColorConversionOptions options = new() + { + WhitePoint = KnownIlluminants.D65, + TargetWhitePoint = KnownIlluminants.D50, + }; + + ColorProfileConverter converter = new(options); + + // Action + HunterLab actual = converter.Convert(input); + + // Assert + Assert.Equal(expected, actual, Comparer); + } + + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(22, 33, 1, 22, 34.0843468, 359.009)] + public void Adapt_CieLchuv_D65_To_D50_XyzScaling(float l1, float c1, float h1, float l2, float c2, float h2) + { + // Arrange + CieLchuv input = new(l1, c1, h1); + CieLchuv expected = new(l2, c2, h2); + ColorConversionOptions options = new() + { + WhitePoint = KnownIlluminants.D65, + TargetWhitePoint = KnownIlluminants.D50, + AdaptationMatrix = KnownChromaticAdaptationMatrices.XyzScaling + }; + + ColorProfileConverter converter = new(options); + + // Action + CieLchuv actual = converter.Convert(input); + + // Assert + Assert.Equal(expected, actual, Comparer); + } + + [Theory] + [InlineData(22, 33, 1, 22, 33, 0.9999999)] + public void Adapt_CieLch_D65_To_D50_XyzScaling(float l1, float c1, float h1, float l2, float c2, float h2) + { + // Arrange + CieLch input = new(l1, c1, h1); + CieLch expected = new(l2, c2, h2); + ColorConversionOptions options = new() + { + WhitePoint = KnownIlluminants.D65, + TargetWhitePoint = KnownIlluminants.D50, + AdaptationMatrix = KnownChromaticAdaptationMatrices.XyzScaling + }; + + ColorProfileConverter converter = new(options); + + // Action + CieLch actual = converter.Convert(input); + + // Assert + Assert.Equal(expected, actual, Comparer); + } +} diff --git a/tests/ImageSharp.Tests/ColorProfiles/CompandingTests.cs b/tests/ImageSharp.Tests/ColorProfiles/CompandingTests.cs new file mode 100644 index 0000000000..1bdefa1095 --- /dev/null +++ b/tests/ImageSharp.Tests/ColorProfiles/CompandingTests.cs @@ -0,0 +1,108 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using System.Numerics; +using SixLabors.ImageSharp.ColorProfiles.Companding; + +namespace SixLabors.ImageSharp.Tests.ColorProfiles; + +/// +/// Tests various companding algorithms. Expanded numbers are hand calculated from formulas online. +/// +public class CompandingTests +{ + private static readonly ApproximateFloatComparer Comparer = new(.000001F); + + [Fact] + public void Rec2020Companding_IsCorrect() + { + Vector4 input = new(.667F); + Vector4 e = Rec2020Companding.Expand(input); + Vector4 c = Rec2020Companding.Compress(e); + CompandingIsCorrectImpl(e, c, .44847462F, input); + } + + [Fact] + public void Rec709Companding_IsCorrect() + { + Vector4 input = new(.667F); + Vector4 e = Rec709Companding.Expand(input); + Vector4 c = Rec709Companding.Compress(e); + CompandingIsCorrectImpl(e, c, .4483577F, input); + } + + [Fact] + public void SRgbCompanding_IsCorrect() + { + Vector4 input = new(.667F); + Vector4 e = SRgbCompanding.Expand(input); + Vector4 c = SRgbCompanding.Compress(e); + CompandingIsCorrectImpl(e, c, .40242353F, input); + } + + [Theory] + [InlineData(0)] + [InlineData(1)] + [InlineData(30)] + public void SRgbCompanding_Expand_VectorSpan(int length) + { + Random rnd = new(42); + Vector4[] source = rnd.GenerateRandomVectorArray(length, 0, 1); + Vector4[] expected = new Vector4[source.Length]; + + for (int i = 0; i < source.Length; i++) + { + expected[i] = SRgbCompanding.Expand(source[i]); + } + + SRgbCompanding.Expand(source); + + Assert.Equal(expected, source, Comparer); + } + + [Theory] + [InlineData(0)] + [InlineData(1)] + [InlineData(30)] + public void SRgbCompanding_Compress_VectorSpan(int length) + { + Random rnd = new(42); + Vector4[] source = rnd.GenerateRandomVectorArray(length, 0, 1); + Vector4[] expected = new Vector4[source.Length]; + + for (int i = 0; i < source.Length; i++) + { + expected[i] = SRgbCompanding.Compress(source[i]); + } + + SRgbCompanding.Compress(source); + + Assert.Equal(expected, source, Comparer); + } + + [Fact] + public void GammaCompanding_IsCorrect() + { + const double gamma = 2.2; + Vector4 input = new(.667F); + Vector4 e = GammaCompanding.Expand(input, gamma); + Vector4 c = GammaCompanding.Compress(e, gamma); + CompandingIsCorrectImpl(e, c, .41027668F, input); + } + + [Fact] + public void LCompanding_IsCorrect() + { + Vector4 input = new(.667F); + Vector4 e = LCompanding.Expand(input); + Vector4 c = LCompanding.Compress(e); + CompandingIsCorrectImpl(e, c, .36236193F, input); + } + + private static void CompandingIsCorrectImpl(Vector4 e, Vector4 c, float expanded, Vector4 compressed) + { + // W (alpha) is already the linear representation of the color. + Assert.Equal(new Vector4(expanded, expanded, expanded, e.W), e, Comparer); + Assert.Equal(compressed, c, Comparer); + } +} diff --git a/tests/ImageSharp.Tests/Colorspaces/HslTests.cs b/tests/ImageSharp.Tests/ColorProfiles/HslTests.cs similarity index 66% rename from tests/ImageSharp.Tests/Colorspaces/HslTests.cs rename to tests/ImageSharp.Tests/ColorProfiles/HslTests.cs index a8702488a6..d18e65117e 100644 --- a/tests/ImageSharp.Tests/Colorspaces/HslTests.cs +++ b/tests/ImageSharp.Tests/ColorProfiles/HslTests.cs @@ -1,10 +1,10 @@ -// Copyright (c) Six Labors. +// Copyright (c) Six Labors. // Licensed under the Six Labors Split License. using System.Numerics; -using SixLabors.ImageSharp.ColorSpaces; +using SixLabors.ImageSharp.ColorProfiles; -namespace SixLabors.ImageSharp.Tests.Colorspaces; +namespace SixLabors.ImageSharp.Tests.ColorProfiles; /// /// Tests the struct. @@ -17,7 +17,7 @@ public class HslTests const float h = 275F; const float s = .64F; const float l = .87F; - var hsl = new Hsl(h, s, l); + Hsl hsl = new(h, s, l); Assert.Equal(h, hsl.H); Assert.Equal(s, hsl.S); @@ -27,12 +27,12 @@ public class HslTests [Fact] public void HslEquality() { - var x = default(Hsl); - var y = new Hsl(Vector3.One); + Hsl x = default; + Hsl y = new(Vector3.One); - Assert.True(default(Hsl) == default(Hsl)); - Assert.False(default(Hsl) != default(Hsl)); - Assert.Equal(default(Hsl), default(Hsl)); + Assert.True(default == default(Hsl)); + Assert.False(default != default(Hsl)); + Assert.Equal(default, default(Hsl)); Assert.Equal(new Hsl(1, 0, 1), new Hsl(1, 0, 1)); Assert.Equal(new Hsl(Vector3.One), new Hsl(Vector3.One)); Assert.False(x.Equals(y)); diff --git a/tests/ImageSharp.Tests/Colorspaces/HsvTests.cs b/tests/ImageSharp.Tests/ColorProfiles/HsvTests.cs similarity index 66% rename from tests/ImageSharp.Tests/Colorspaces/HsvTests.cs rename to tests/ImageSharp.Tests/ColorProfiles/HsvTests.cs index caedd3f171..46f58b18e2 100644 --- a/tests/ImageSharp.Tests/Colorspaces/HsvTests.cs +++ b/tests/ImageSharp.Tests/ColorProfiles/HsvTests.cs @@ -1,10 +1,10 @@ -// Copyright (c) Six Labors. +// Copyright (c) Six Labors. // Licensed under the Six Labors Split License. using System.Numerics; -using SixLabors.ImageSharp.ColorSpaces; +using SixLabors.ImageSharp.ColorProfiles; -namespace SixLabors.ImageSharp.Tests.Colorspaces; +namespace SixLabors.ImageSharp.Tests.ColorProfiles; /// /// Tests the struct. @@ -17,7 +17,7 @@ public class HsvTests const float h = 275F; const float s = .64F; const float v = .87F; - var hsv = new Hsv(h, s, v); + Hsv hsv = new(h, s, v); Assert.Equal(h, hsv.H); Assert.Equal(s, hsv.S); @@ -27,12 +27,12 @@ public class HsvTests [Fact] public void HsvEquality() { - var x = default(Hsv); - var y = new Hsv(Vector3.One); + Hsv x = default; + Hsv y = new(Vector3.One); - Assert.True(default(Hsv) == default(Hsv)); - Assert.False(default(Hsv) != default(Hsv)); - Assert.Equal(default(Hsv), default(Hsv)); + Assert.True(default == default(Hsv)); + Assert.False(default != default(Hsv)); + Assert.Equal(default, default(Hsv)); Assert.Equal(new Hsv(1, 0, 1), new Hsv(1, 0, 1)); Assert.Equal(new Hsv(Vector3.One), new Hsv(Vector3.One)); Assert.False(x.Equals(y)); diff --git a/tests/ImageSharp.Tests/Colorspaces/HunterLabTests.cs b/tests/ImageSharp.Tests/ColorProfiles/HunterLabTests.cs similarity index 63% rename from tests/ImageSharp.Tests/Colorspaces/HunterLabTests.cs rename to tests/ImageSharp.Tests/ColorProfiles/HunterLabTests.cs index 9c97c4c91b..5fbdd0788f 100644 --- a/tests/ImageSharp.Tests/Colorspaces/HunterLabTests.cs +++ b/tests/ImageSharp.Tests/ColorProfiles/HunterLabTests.cs @@ -2,9 +2,9 @@ // Licensed under the Six Labors Split License. using System.Numerics; -using SixLabors.ImageSharp.ColorSpaces; +using SixLabors.ImageSharp.ColorProfiles; -namespace SixLabors.ImageSharp.Tests.Colorspaces; +namespace SixLabors.ImageSharp.Tests.ColorProfiles; /// /// Tests the struct. @@ -17,7 +17,7 @@ public class HunterLabTests const float l = 75F; const float a = -64F; const float b = 87F; - var hunterLab = new HunterLab(l, a, b); + HunterLab hunterLab = new(l, a, b); Assert.Equal(l, hunterLab.L); Assert.Equal(a, hunterLab.A); @@ -27,13 +27,13 @@ public class HunterLabTests [Fact] public void HunterLabEquality() { - var x = default(HunterLab); - var y = new HunterLab(Vector3.One); + HunterLab x = default; + HunterLab y = new(Vector3.One); - Assert.True(default(HunterLab) == default(HunterLab)); - Assert.True(new HunterLab(1, 0, 1) != default(HunterLab)); - Assert.False(new HunterLab(1, 0, 1) == default(HunterLab)); - Assert.Equal(default(HunterLab), default(HunterLab)); + Assert.True(default == default(HunterLab)); + Assert.True(new HunterLab(1, 0, 1) != default); + Assert.False(new HunterLab(1, 0, 1) == default); + Assert.Equal(default, default(HunterLab)); Assert.Equal(new HunterLab(1, 0, 1), new HunterLab(1, 0, 1)); Assert.Equal(new HunterLab(Vector3.One), new HunterLab(Vector3.One)); Assert.False(x.Equals(y)); diff --git a/tests/ImageSharp.Tests/Colorspaces/LmsTests.cs b/tests/ImageSharp.Tests/ColorProfiles/LmsTests.cs similarity index 65% rename from tests/ImageSharp.Tests/Colorspaces/LmsTests.cs rename to tests/ImageSharp.Tests/ColorProfiles/LmsTests.cs index 5e8840664e..138fd544da 100644 --- a/tests/ImageSharp.Tests/Colorspaces/LmsTests.cs +++ b/tests/ImageSharp.Tests/ColorProfiles/LmsTests.cs @@ -2,9 +2,9 @@ // Licensed under the Six Labors Split License. using System.Numerics; -using SixLabors.ImageSharp.ColorSpaces; +using SixLabors.ImageSharp.ColorProfiles; -namespace SixLabors.ImageSharp.Tests.Colorspaces; +namespace SixLabors.ImageSharp.Tests.ColorProfiles; /// /// Tests the struct. @@ -17,7 +17,7 @@ public class LmsTests const float l = 75F; const float m = -64F; const float s = 87F; - var lms = new Lms(l, m, s); + Lms lms = new(l, m, s); Assert.Equal(l, lms.L); Assert.Equal(m, lms.M); @@ -27,13 +27,13 @@ public class LmsTests [Fact] public void LmsEquality() { - var x = default(Lms); - var y = new Lms(Vector3.One); + Lms x = default; + Lms y = new(Vector3.One); - Assert.True(default(Lms) == default(Lms)); - Assert.True(new Lms(1, 0, 1) != default(Lms)); - Assert.False(new Lms(1, 0, 1) == default(Lms)); - Assert.Equal(default(Lms), default(Lms)); + Assert.True(default == default(Lms)); + Assert.True(new Lms(1, 0, 1) != default); + Assert.False(new Lms(1, 0, 1) == default); + Assert.Equal(default, default(Lms)); Assert.Equal(new Lms(1, 0, 1), new Lms(1, 0, 1)); Assert.Equal(new Lms(Vector3.One), new Lms(Vector3.One)); Assert.False(x.Equals(y)); diff --git a/tests/ImageSharp.Tests/ColorProfiles/RgbAndCieXyzConversionTest.cs b/tests/ImageSharp.Tests/ColorProfiles/RgbAndCieXyzConversionTest.cs new file mode 100644 index 0000000000..c10aa2c3c5 --- /dev/null +++ b/tests/ImageSharp.Tests/ColorProfiles/RgbAndCieXyzConversionTest.cs @@ -0,0 +1,150 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using SixLabors.ImageSharp.ColorProfiles; + +namespace SixLabors.ImageSharp.Tests.ColorProfiles; + +/// +/// Tests - conversions. +/// +/// +/// Test data generated using: +/// +/// +public class RgbAndCieXyzConversionTest +{ + private static readonly ApproximateColorProfileComparer Comparer = new(.0001F); + + [Theory] + [InlineData(0.96422, 1.00000, 0.82521, 1, 1, 1)] + [InlineData(0.00000, 1.00000, 0.00000, 0, 1, 0)] + [InlineData(0.96422, 0.00000, 0.00000, 1, 0, 0.292064)] + [InlineData(0.00000, 0.00000, 0.82521, 0, 0.181415, 1)] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(0.297676, 0.267854, 0.045504, 0.720315, 0.509999, 0.168112)] + public void Convert_XYZ_D50_To_SRGB(float x, float y, float z, float r, float g, float b) + { + // Arrange + CieXyz input = new(x, y, z); + ColorConversionOptions options = new() { WhitePoint = KnownIlluminants.D50, TargetRgbWorkingSpace = KnownRgbWorkingSpaces.SRgb }; + ColorProfileConverter converter = new(options); + Rgb expected = new(r, g, b); + + Span inputSpan = new CieXyz[5]; + inputSpan.Fill(input); + + Span actualSpan = new Rgb[5]; + + // Act + Rgb actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } + + [Theory] + [InlineData(0.950470, 1.000000, 1.088830, 1, 1, 1)] + [InlineData(0, 1.000000, 0, 0, 1, 0)] + [InlineData(0.950470, 0, 0, 1, 0, 0.254967)] + [InlineData(0, 0, 1.088830, 0, 0.235458, 1)] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(0.297676, 0.267854, 0.045504, 0.754903, 0.501961, 0.099998)] + public void Convert_XYZ_D65_To_SRGB(float x, float y, float z, float r, float g, float b) + { + // Arrange + CieXyz input = new(x, y, z); + ColorConversionOptions options = new() { WhitePoint = KnownIlluminants.D65, TargetRgbWorkingSpace = KnownRgbWorkingSpaces.SRgb }; + ColorProfileConverter converter = new(options); + Rgb expected = new(r, g, b); + + Span inputSpan = new CieXyz[5]; + inputSpan.Fill(input); + + Span actualSpan = new Rgb[5]; + + // Act + Rgb actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } + + [Theory] + [InlineData(1, 1, 1, 0.964220, 1.000000, 0.825210)] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(1, 0, 0, 0.436075, 0.222504, 0.013932)] + [InlineData(0, 1, 0, 0.385065, 0.716879, 0.0971045)] + [InlineData(0, 0, 1, 0.143080, 0.060617, 0.714173)] + [InlineData(0.754902, 0.501961, 0.100000, 0.315757, 0.273323, 0.035506)] + public void Convert_SRGB_To_XYZ_D50(float r, float g, float b, float x, float y, float z) + { + // Arrange + Rgb input = new(r, g, b); + ColorConversionOptions options = new() { TargetWhitePoint = KnownIlluminants.D50, RgbWorkingSpace = KnownRgbWorkingSpaces.SRgb }; + ColorProfileConverter converter = new(options); + CieXyz expected = new(x, y, z); + + Span inputSpan = new Rgb[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieXyz[5]; + + // Act + CieXyz actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } + + [Theory] + [InlineData(1, 1, 1, 0.950470, 1.000000, 1.088830)] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(1, 0, 0, 0.412456, 0.212673, 0.019334)] + [InlineData(0, 1, 0, 0.357576, 0.715152, 0.119192)] + [InlineData(0, 0, 1, 0.1804375, 0.072175, 0.950304)] + [InlineData(0.754902, 0.501961, 0.100000, 0.297676, 0.267854, 0.045504)] + public void Convert_SRGB_To_XYZ_D65(float r, float g, float b, float x, float y, float z) + { + // Arrange + Rgb input = new(r, g, b); + ColorConversionOptions options = new() { TargetWhitePoint = KnownIlluminants.D65, RgbWorkingSpace = KnownRgbWorkingSpaces.SRgb }; + ColorProfileConverter converter = new(options); + CieXyz expected = new(x, y, z); + + Span inputSpan = new Rgb[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieXyz[5]; + + // Act + CieXyz actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } +} diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/RgbAndCmykConversionTest.cs b/tests/ImageSharp.Tests/ColorProfiles/RgbAndCmykConversionTest.cs similarity index 50% rename from tests/ImageSharp.Tests/Colorspaces/Conversion/RgbAndCmykConversionTest.cs rename to tests/ImageSharp.Tests/ColorProfiles/RgbAndCmykConversionTest.cs index 942b34db33..4f4ecb70be 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/RgbAndCmykConversionTest.cs +++ b/tests/ImageSharp.Tests/ColorProfiles/RgbAndCmykConversionTest.cs @@ -1,10 +1,9 @@ -// Copyright (c) Six Labors. +// Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion; +using SixLabors.ImageSharp.ColorProfiles; -namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion; +namespace SixLabors.ImageSharp.Tests.ColorProfiles; /// /// Tests - conversions. @@ -16,12 +15,8 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion; /// public class RgbAndCmykConversionTest { - private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); - private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0001F); + private static readonly ApproximateColorProfileComparer Comparer = new(.0001F); - /// - /// Tests conversion from to . - /// [Theory] [InlineData(1, 1, 1, 1, 0, 0, 0)] [InlineData(0, 0, 0, 0, 1, 1, 1)] @@ -29,8 +24,9 @@ public class RgbAndCmykConversionTest public void Convert_Cmyk_To_Rgb(float c, float m, float y, float k, float r, float g, float b) { // Arrange - var input = new Cmyk(c, m, y, k); - var expected = new Rgb(r, g, b); + Cmyk input = new(c, m, y, k); + Rgb expected = new(r, g, b); + ColorProfileConverter converter = new(); Span inputSpan = new Cmyk[5]; inputSpan.Fill(input); @@ -38,22 +34,18 @@ public class RgbAndCmykConversionTest Span actualSpan = new Rgb[5]; // Act - var actual = ColorSpaceConverter.ToRgb(input); - ColorSpaceConverter.Convert(inputSpan, actualSpan); + Rgb actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); // Assert - Assert.Equal(Rgb.DefaultWorkingSpace, actual.WorkingSpace, ColorSpaceComparer); - Assert.Equal(expected, actual, ColorSpaceComparer); + Assert.Equal(expected, actual, Comparer); for (int i = 0; i < actualSpan.Length; i++) { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); + Assert.Equal(expected, actualSpan[i], Comparer); } } - /// - /// Tests conversion from to . - /// [Theory] [InlineData(1, 1, 1, 0, 0, 0, 0)] [InlineData(0, 0, 0, 0, 0, 0, 1)] @@ -61,8 +53,9 @@ public class RgbAndCmykConversionTest public void Convert_Rgb_To_Cmyk(float r, float g, float b, float c, float m, float y, float k) { // Arrange - var input = new Rgb(r, g, b); - var expected = new Cmyk(c, m, y, k); + Rgb input = new(r, g, b); + Cmyk expected = new(c, m, y, k); + ColorProfileConverter converter = new(); Span inputSpan = new Rgb[5]; inputSpan.Fill(input); @@ -70,15 +63,15 @@ public class RgbAndCmykConversionTest Span actualSpan = new Cmyk[5]; // Act - var actual = ColorSpaceConverter.ToCmyk(input); - ColorSpaceConverter.Convert(inputSpan, actualSpan); + Cmyk actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); + Assert.Equal(expected, actual, Comparer); for (int i = 0; i < actualSpan.Length; i++) { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); + Assert.Equal(expected, actualSpan[i], Comparer); } } } diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/RgbAndHslConversionTest.cs b/tests/ImageSharp.Tests/ColorProfiles/RgbAndHslConversionTest.cs similarity index 54% rename from tests/ImageSharp.Tests/Colorspaces/Conversion/RgbAndHslConversionTest.cs rename to tests/ImageSharp.Tests/ColorProfiles/RgbAndHslConversionTest.cs index 8b448a0426..0dc95628b9 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/RgbAndHslConversionTest.cs +++ b/tests/ImageSharp.Tests/ColorProfiles/RgbAndHslConversionTest.cs @@ -1,10 +1,9 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion; +using SixLabors.ImageSharp.ColorProfiles; -namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion; +namespace SixLabors.ImageSharp.Tests.ColorProfiles; /// /// Tests - conversions. @@ -16,12 +15,8 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion; /// public class RgbAndHslConversionTest { - private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); - private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0001F); + private static readonly ApproximateColorProfileComparer Comparer = new(.0001f); - /// - /// Tests conversion from to . - /// [Theory] [InlineData(0, 0, 0, 0, 0, 0)] [InlineData(0, 1, 1, 1, 1, 1)] @@ -32,8 +27,9 @@ public class RgbAndHslConversionTest public void Convert_Hsl_To_Rgb(float h, float s, float l, float r, float g, float b) { // Arrange - var input = new Hsl(h, s, l); - var expected = new Rgb(r, g, b); + Hsl input = new(h, s, l); + Rgb expected = new(r, g, b); + ColorProfileConverter converter = new(); Span inputSpan = new Hsl[5]; inputSpan.Fill(input); @@ -41,22 +37,18 @@ public class RgbAndHslConversionTest Span actualSpan = new Rgb[5]; // Act - var actual = ColorSpaceConverter.ToRgb(input); - ColorSpaceConverter.Convert(inputSpan, actualSpan); + Rgb actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); // Assert - Assert.Equal(Rgb.DefaultWorkingSpace, actual.WorkingSpace, ColorSpaceComparer); - Assert.Equal(expected, actual, ColorSpaceComparer); + Assert.Equal(expected, actual, Comparer); for (int i = 0; i < actualSpan.Length; i++) { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); + Assert.Equal(expected, actualSpan[i], Comparer); } } - /// - /// Tests conversion from to . - /// [Theory] [InlineData(0, 0, 0, 0, 0, 0)] [InlineData(1, 1, 1, 0, 0, 1)] @@ -67,8 +59,9 @@ public class RgbAndHslConversionTest public void Convert_Rgb_To_Hsl(float r, float g, float b, float h, float s, float l) { // Arrange - var input = new Rgb(r, g, b); - var expected = new Hsl(h, s, l); + Rgb input = new(r, g, b); + Hsl expected = new(h, s, l); + ColorProfileConverter converter = new(); Span inputSpan = new Rgb[5]; inputSpan.Fill(input); @@ -76,15 +69,15 @@ public class RgbAndHslConversionTest Span actualSpan = new Hsl[5]; // Act - var actual = ColorSpaceConverter.ToHsl(input); - ColorSpaceConverter.Convert(inputSpan, actualSpan); + Hsl actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); + Assert.Equal(expected, actual, Comparer); for (int i = 0; i < actualSpan.Length; i++) { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); + Assert.Equal(expected, actualSpan[i], Comparer); } } } diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/RgbAndHsvConversionTest.cs b/tests/ImageSharp.Tests/ColorProfiles/RgbAndHsvConversionTest.cs similarity index 50% rename from tests/ImageSharp.Tests/Colorspaces/Conversion/RgbAndHsvConversionTest.cs rename to tests/ImageSharp.Tests/ColorProfiles/RgbAndHsvConversionTest.cs index d80aa6c329..b89b576b6c 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/RgbAndHsvConversionTest.cs +++ b/tests/ImageSharp.Tests/ColorProfiles/RgbAndHsvConversionTest.cs @@ -1,10 +1,9 @@ -// Copyright (c) Six Labors. +// Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion; +using SixLabors.ImageSharp.ColorProfiles; -namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion; +namespace SixLabors.ImageSharp.Tests.ColorProfiles; /// /// Tests - conversions. @@ -15,12 +14,8 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion; /// public class RgbAndHsvConversionTest { - private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); - private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0001F); + private static readonly ApproximateColorProfileComparer Comparer = new(.0001f); - /// - /// Tests conversion from to . - /// [Theory] [InlineData(0, 0, 0, 0, 0, 0)] [InlineData(0, 0, 1, 1, 1, 1)] @@ -31,8 +26,9 @@ public class RgbAndHsvConversionTest public void Convert_Hsv_To_Rgb(float h, float s, float v, float r, float g, float b) { // Arrange - var input = new Hsv(h, s, v); - var expected = new Rgb(r, g, b); + Hsv input = new(h, s, v); + Rgb expected = new(r, g, b); + ColorProfileConverter converter = new(); Span inputSpan = new Hsv[5]; inputSpan.Fill(input); @@ -40,22 +36,18 @@ public class RgbAndHsvConversionTest Span actualSpan = new Rgb[5]; // Act - var actual = ColorSpaceConverter.ToRgb(input); - ColorSpaceConverter.Convert(inputSpan, actualSpan); + Rgb actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); // Assert - Assert.Equal(Rgb.DefaultWorkingSpace, actual.WorkingSpace, ColorSpaceComparer); - Assert.Equal(expected, actual, ColorSpaceComparer); + Assert.Equal(expected, actual, Comparer); for (int i = 0; i < actualSpan.Length; i++) { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); + Assert.Equal(expected, actualSpan[i], Comparer); } } - /// - /// Tests conversion from to . - /// [Theory] [InlineData(0, 0, 0, 0, 0, 0)] [InlineData(1, 1, 1, 0, 0, 1)] @@ -65,8 +57,9 @@ public class RgbAndHsvConversionTest public void Convert_Rgb_To_Hsv(float r, float g, float b, float h, float s, float v) { // Arrange - var input = new Rgb(r, g, b); - var expected = new Hsv(h, s, v); + Rgb input = new(r, g, b); + Hsv expected = new(h, s, v); + ColorProfileConverter converter = new(); Span inputSpan = new Rgb[5]; inputSpan.Fill(input); @@ -74,15 +67,15 @@ public class RgbAndHsvConversionTest Span actualSpan = new Hsv[5]; // Act - var actual = ColorSpaceConverter.ToHsv(input); - ColorSpaceConverter.Convert(inputSpan, actualSpan); + Hsv actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); + Assert.Equal(expected, actual, Comparer); for (int i = 0; i < actualSpan.Length; i++) { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); + Assert.Equal(expected, actualSpan[i], Comparer); } } } diff --git a/tests/ImageSharp.Tests/ColorProfiles/RgbAndYCbCrConversionTest.cs b/tests/ImageSharp.Tests/ColorProfiles/RgbAndYCbCrConversionTest.cs new file mode 100644 index 0000000000..91f7fc08ee --- /dev/null +++ b/tests/ImageSharp.Tests/ColorProfiles/RgbAndYCbCrConversionTest.cs @@ -0,0 +1,76 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using SixLabors.ImageSharp.ColorProfiles; + +namespace SixLabors.ImageSharp.Tests.ColorProfiles; + +/// +/// Tests - conversions. +/// +/// +/// Test data generated mathematically +/// +public class RgbAndYCbCrConversionTest +{ + private static readonly ApproximateColorProfileComparer Comparer = new(.001F); + + [Theory] + [InlineData(255, 128, 128, 1, 1, 1)] + [InlineData(0, 128, 128, 0, 0, 0)] + [InlineData(128, 128, 128, 0.502, 0.502, 0.502)] + public void Convert_YCbCr_To_Rgb(float y, float cb, float cr, float r, float g, float b) + { + // Arrange + YCbCr input = new(y, cb, cr); + Rgb expected = new(r, g, b); + ColorProfileConverter converter = new(); + + Span inputSpan = new YCbCr[5]; + inputSpan.Fill(input); + + Span actualSpan = new Rgb[5]; + + // Act + Rgb actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } + + [Theory] + [InlineData(0, 0, 0, 0, 128, 128)] + [InlineData(1, 1, 1, 255, 128, 128)] + [InlineData(0.5, 0.5, 0.5, 127.5, 128, 128)] + [InlineData(1, 0, 0, 76.245, 84.972, 255)] + public void Convert_Rgb_To_YCbCr(float r, float g, float b, float y, float cb, float cr) + { + // Arrange + Rgb input = new(r, g, b); + YCbCr expected = new(y, cb, cr); + ColorProfileConverter converter = new(); + + Span inputSpan = new Rgb[5]; + inputSpan.Fill(input); + + Span actualSpan = new YCbCr[5]; + + // Act + YCbCr actual = converter.Convert(input); + converter.Convert(inputSpan, actualSpan); + + // Assert + Assert.Equal(expected, actual, Comparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } +} diff --git a/tests/ImageSharp.Tests/Colorspaces/RgbTests.cs b/tests/ImageSharp.Tests/ColorProfiles/RgbTests.cs similarity index 66% rename from tests/ImageSharp.Tests/Colorspaces/RgbTests.cs rename to tests/ImageSharp.Tests/ColorProfiles/RgbTests.cs index be96b79f46..7e4d4ee0e7 100644 --- a/tests/ImageSharp.Tests/Colorspaces/RgbTests.cs +++ b/tests/ImageSharp.Tests/ColorProfiles/RgbTests.cs @@ -2,10 +2,10 @@ // Licensed under the Six Labors Split License. using System.Numerics; -using SixLabors.ImageSharp.ColorSpaces; +using SixLabors.ImageSharp.ColorProfiles; using SixLabors.ImageSharp.PixelFormats; -namespace SixLabors.ImageSharp.Tests.Colorspaces; +namespace SixLabors.ImageSharp.Tests.ColorProfiles; /// /// Tests the struct. @@ -18,7 +18,7 @@ public class RgbTests const float r = .75F; const float g = .64F; const float b = .87F; - var rgb = new Rgb(r, g, b); + Rgb rgb = new(r, g, b); Assert.Equal(r, rgb.R); Assert.Equal(g, rgb.G); @@ -28,12 +28,12 @@ public class RgbTests [Fact] public void RgbEquality() { - var x = default(Rgb); - var y = new Rgb(Vector3.One); + Rgb x = default; + Rgb y = new(Vector3.One); - Assert.True(default(Rgb) == default(Rgb)); - Assert.False(default(Rgb) != default(Rgb)); - Assert.Equal(default(Rgb), default(Rgb)); + Assert.True(default == default(Rgb)); + Assert.False(default != default(Rgb)); + Assert.Equal(default, default(Rgb)); Assert.Equal(new Rgb(1, 0, 1), new Rgb(1, 0, 1)); Assert.Equal(new Rgb(Vector3.One), new Rgb(Vector3.One)); Assert.False(x.Equals(y)); @@ -42,14 +42,14 @@ public class RgbTests } [Fact] - public void RgbAndRgb24Operators() + public void RgbAndRgb24Interop() { const byte r = 64; const byte g = 128; const byte b = 255; - Rgb24 rgb24 = new Rgb(r / 255F, g / 255F, b / 255F); - Rgb rgb2 = rgb24; + Rgb24 rgb24 = Rgb24.FromScaledVector4(new Rgb(r / 255F, g / 255F, b / 255F).ToScaledVector4()); + Rgb rgb2 = Rgb.FromScaledVector4(rgb24.ToScaledVector4()); Assert.Equal(r, rgb24.R); Assert.Equal(g, rgb24.G); @@ -61,14 +61,14 @@ public class RgbTests } [Fact] - public void RgbAndRgba32Operators() + public void RgbAndRgba32Interop() { const byte r = 64; const byte g = 128; const byte b = 255; - Rgba32 rgba32 = new Rgb(r / 255F, g / 255F, b / 255F); - Rgb rgb2 = rgba32; + Rgba32 rgba32 = Rgba32.FromScaledVector4(new Rgb(r / 255F, g / 255F, b / 255F).ToScaledVector4()); + Rgb rgb2 = Rgb.FromScaledVector4(rgba32.ToScaledVector4()); Assert.Equal(r, rgba32.R); Assert.Equal(g, rgba32.G); diff --git a/tests/ImageSharp.Tests/Colorspaces/StringRepresentationTests.cs b/tests/ImageSharp.Tests/ColorProfiles/StringRepresentationTests.cs similarity index 78% rename from tests/ImageSharp.Tests/Colorspaces/StringRepresentationTests.cs rename to tests/ImageSharp.Tests/ColorProfiles/StringRepresentationTests.cs index 2ae0824f28..770c987dba 100644 --- a/tests/ImageSharp.Tests/Colorspaces/StringRepresentationTests.cs +++ b/tests/ImageSharp.Tests/ColorProfiles/StringRepresentationTests.cs @@ -2,18 +2,17 @@ // Licensed under the Six Labors Split License. using System.Numerics; -using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion; +using SixLabors.ImageSharp.ColorProfiles; -namespace SixLabors.ImageSharp.Tests.Colorspaces; +namespace SixLabors.ImageSharp.Tests.ColorProfiles; public class StringRepresentationTests { - private static readonly Vector3 One = new Vector3(1); - private static readonly Vector3 Zero = new Vector3(0); - private static readonly Vector3 Random = new Vector3(42.4F, 94.5F, 83.4F); + private static readonly Vector3 One = new(1); + private static readonly Vector3 Zero = new(0); + private static readonly Vector3 Random = new(42.4F, 94.5F, 83.4F); - public static readonly TheoryData TestData = new TheoryData + public static readonly TheoryData TestData = new() { { new CieLab(Zero), "CieLab(0, 0, 0)" }, { new CieLch(Zero), "CieLch(0, 0, 0)" }, @@ -23,7 +22,6 @@ public class StringRepresentationTests { new CieXyy(Zero), "CieXyy(0, 0, 0)" }, { new HunterLab(Zero), "HunterLab(0, 0, 0)" }, { new Lms(Zero), "Lms(0, 0, 0)" }, - { new LinearRgb(Zero), "LinearRgb(0, 0, 0)" }, { new Rgb(Zero), "Rgb(0, 0, 0)" }, { new Hsl(Zero), "Hsl(0, 0, 0)" }, { new Hsv(Zero), "Hsv(0, 0, 0)" }, @@ -36,7 +34,6 @@ public class StringRepresentationTests { new CieXyy(One), "CieXyy(1, 1, 1)" }, { new HunterLab(One), "HunterLab(1, 1, 1)" }, { new Lms(One), "Lms(1, 1, 1)" }, - { new LinearRgb(One), "LinearRgb(1, 1, 1)" }, { new Rgb(One), "Rgb(1, 1, 1)" }, { new Hsl(One), "Hsl(1, 1, 1)" }, { new Hsv(One), "Hsv(1, 1, 1)" }, @@ -50,8 +47,8 @@ public class StringRepresentationTests { new CieXyy(Random), "CieXyy(42.4, 94.5, 83.4)" }, { new HunterLab(Random), "HunterLab(42.4, 94.5, 83.4)" }, { new Lms(Random), "Lms(42.4, 94.5, 83.4)" }, - { new LinearRgb(Random), "LinearRgb(1, 1, 1)" }, // clamping to 1 is expected - { new Rgb(Random), "Rgb(1, 1, 1)" }, // clamping to 1 is expected + { new Rgb(Random), "Rgb(42.4, 94.5, 83.4)" }, + { Rgb.Clamp(new Rgb(Random)), "Rgb(1, 1, 1)" }, { new Hsl(Random), "Hsl(42.4, 1, 1)" }, // clamping to 1 is expected { new Hsv(Random), "Hsv(42.4, 1, 1)" }, // clamping to 1 is expected { new YCbCr(Random), "YCbCr(42.4, 94.5, 83.4)" }, diff --git a/tests/ImageSharp.Tests/ColorProfiles/VonKriesChromaticAdaptationTests.cs b/tests/ImageSharp.Tests/ColorProfiles/VonKriesChromaticAdaptationTests.cs new file mode 100644 index 0000000000..7f5687dee2 --- /dev/null +++ b/tests/ImageSharp.Tests/ColorProfiles/VonKriesChromaticAdaptationTests.cs @@ -0,0 +1,42 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using SixLabors.ImageSharp.ColorProfiles; + +namespace SixLabors.ImageSharp.Tests.ColorProfiles; + +public class VonKriesChromaticAdaptationTests +{ + private static readonly ApproximateColorProfileComparer Comparer = new(.0001F); + public static readonly TheoryData WhitePoints = new() + { + { KnownIlluminants.D65, KnownIlluminants.D50 }, + { KnownIlluminants.D65, KnownIlluminants.D65 } + }; + + [Theory] + [MemberData(nameof(WhitePoints))] + public void SingleAndBulkTransformYieldIdenticalResults(CieXyz from, CieXyz to) + { + ColorConversionOptions options = new() + { + WhitePoint = from, + TargetWhitePoint = to + }; + + CieXyz input = new(1, 0, 1); + CieXyz expected = VonKriesChromaticAdaptation.Transform(in input, (from, to), KnownChromaticAdaptationMatrices.Bradford); + + Span inputSpan = new CieXyz[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieXyz[5]; + + VonKriesChromaticAdaptation.Transform(inputSpan, actualSpan, (from, to), KnownChromaticAdaptationMatrices.Bradford); + + for (int i = 0; i < inputSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], Comparer); + } + } +} diff --git a/tests/ImageSharp.Tests/Colorspaces/YCbCrTests.cs b/tests/ImageSharp.Tests/ColorProfiles/YCbCrTests.cs similarity index 65% rename from tests/ImageSharp.Tests/Colorspaces/YCbCrTests.cs rename to tests/ImageSharp.Tests/ColorProfiles/YCbCrTests.cs index efab45c3cb..f8404ad948 100644 --- a/tests/ImageSharp.Tests/Colorspaces/YCbCrTests.cs +++ b/tests/ImageSharp.Tests/ColorProfiles/YCbCrTests.cs @@ -1,10 +1,10 @@ -// Copyright (c) Six Labors. +// Copyright (c) Six Labors. // Licensed under the Six Labors Split License. using System.Numerics; -using SixLabors.ImageSharp.ColorSpaces; +using SixLabors.ImageSharp.ColorProfiles; -namespace SixLabors.ImageSharp.Tests.Colorspaces; +namespace SixLabors.ImageSharp.Tests.ColorProfiles; /// /// Tests the struct. @@ -17,7 +17,7 @@ public class YCbCrTests const float y = 75F; const float cb = 64F; const float cr = 87F; - var yCbCr = new YCbCr(y, cb, cr); + YCbCr yCbCr = new(y, cb, cr); Assert.Equal(y, yCbCr.Y); Assert.Equal(cb, yCbCr.Cb); @@ -27,12 +27,12 @@ public class YCbCrTests [Fact] public void YCbCrEquality() { - var x = default(YCbCr); - var y = new YCbCr(Vector3.One); + YCbCr x = default; + YCbCr y = new(Vector3.One); - Assert.True(default(YCbCr) == default(YCbCr)); - Assert.False(default(YCbCr) != default(YCbCr)); - Assert.Equal(default(YCbCr), default(YCbCr)); + Assert.True(default == default(YCbCr)); + Assert.False(default != default(YCbCr)); + Assert.Equal(default, default(YCbCr)); Assert.Equal(new YCbCr(1, 0, 1), new YCbCr(1, 0, 1)); Assert.Equal(new YCbCr(Vector3.One), new YCbCr(Vector3.One)); Assert.False(x.Equals(y)); diff --git a/tests/ImageSharp.Tests/Colorspaces/Companding/CompandingTests.cs b/tests/ImageSharp.Tests/Colorspaces/Companding/CompandingTests.cs deleted file mode 100644 index 3fb3598909..0000000000 --- a/tests/ImageSharp.Tests/Colorspaces/Companding/CompandingTests.cs +++ /dev/null @@ -1,113 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using System.Numerics; -using SixLabors.ImageSharp.ColorSpaces.Companding; - -namespace SixLabors.ImageSharp.Tests.Colorspaces.Companding; - -/// -/// Tests various companding algorithms. Expanded numbers are hand calculated from formulas online. -/// -public class CompandingTests -{ - private static readonly ApproximateFloatComparer FloatComparer = new ApproximateFloatComparer(.00001F); - - [Fact] - public void Rec2020Companding_IsCorrect() - { - const float input = .667F; - float e = Rec2020Companding.Expand(input); - float c = Rec2020Companding.Compress(e); - CompandingIsCorrectImpl(e, c, .4484759F, input); - } - - [Fact] - public void Rec709Companding_IsCorrect() - { - const float input = .667F; - float e = Rec709Companding.Expand(input); - float c = Rec709Companding.Compress(e); - CompandingIsCorrectImpl(e, c, .4483577F, input); - } - - [Fact] - public void SRgbCompanding_IsCorrect() - { - const float input = .667F; - float e = SRgbCompanding.Expand(input); - float c = SRgbCompanding.Compress(e); - CompandingIsCorrectImpl(e, c, .40242353F, input); - } - - [Theory] - [InlineData(0)] - [InlineData(1)] - [InlineData(30)] - public void SRgbCompanding_Expand_VectorSpan(int length) - { - var rnd = new Random(42); - Vector4[] source = rnd.GenerateRandomVectorArray(length, 0, 1); - var expected = new Vector4[source.Length]; - - for (int i = 0; i < source.Length; i++) - { - Vector4 s = source[i]; - ref Vector4 e = ref expected[i]; - SRgbCompanding.Expand(ref s); - e = s; - } - - SRgbCompanding.Expand(source); - - Assert.Equal(expected, source, new ApproximateFloatComparer(1e-6f)); - } - - [Theory] - [InlineData(0)] - [InlineData(1)] - [InlineData(30)] - public void SRgbCompanding_Compress_VectorSpan(int length) - { - var rnd = new Random(42); - Vector4[] source = rnd.GenerateRandomVectorArray(length, 0, 1); - var expected = new Vector4[source.Length]; - - for (int i = 0; i < source.Length; i++) - { - Vector4 s = source[i]; - ref Vector4 e = ref expected[i]; - SRgbCompanding.Compress(ref s); - e = s; - } - - SRgbCompanding.Compress(source); - - Assert.Equal(expected, source, new ApproximateFloatComparer(1e-6f)); - } - - [Fact] - public void GammaCompanding_IsCorrect() - { - const float gamma = 2.2F; - const float input = .667F; - float e = GammaCompanding.Expand(input, gamma); - float c = GammaCompanding.Compress(e, gamma); - CompandingIsCorrectImpl(e, c, .41027668F, input); - } - - [Fact] - public void LCompanding_IsCorrect() - { - const float input = .667F; - float e = LCompanding.Expand(input); - float c = LCompanding.Compress(e); - CompandingIsCorrectImpl(e, c, .36236193F, input); - } - - private static void CompandingIsCorrectImpl(float e, float c, float expanded, float compressed) - { - Assert.Equal(expanded, e, FloatComparer); - Assert.Equal(compressed, c, FloatComparer); - } -} diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/ApproximateColorspaceComparer.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/ApproximateColorspaceComparer.cs deleted file mode 100644 index d66a73b5a1..0000000000 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/ApproximateColorspaceComparer.cs +++ /dev/null @@ -1,238 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion; - -namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion; - -/// -/// Allows the approximate comparison of colorspace component values. -/// -internal readonly struct ApproximateColorSpaceComparer : - IEqualityComparer, - IEqualityComparer, - IEqualityComparer, - IEqualityComparer, - IEqualityComparer, - IEqualityComparer, - IEqualityComparer, - IEqualityComparer, - IEqualityComparer, - IEqualityComparer, - IEqualityComparer, - IEqualityComparer, - IEqualityComparer, - IEqualityComparer, - IEqualityComparer, - IEqualityComparer, - IEqualityComparer, - IEqualityComparer -{ - private readonly float epsilon; - - /// - /// Initializes a new instance of the class. - /// - /// The comparison error difference epsilon to use. - public ApproximateColorSpaceComparer(float epsilon = 1F) => this.epsilon = epsilon; - - /// - public bool Equals(Rgb x, Rgb y) - { - return this.Equals(x.R, y.R) - && this.Equals(x.G, y.G) - && this.Equals(x.B, y.B); - } - - /// - public int GetHashCode(Rgb obj) => obj.GetHashCode(); - - /// - public bool Equals(LinearRgb x, LinearRgb y) - { - return this.Equals(x.R, y.R) - && this.Equals(x.G, y.G) - && this.Equals(x.B, y.B); - } - - /// - public int GetHashCode(LinearRgb obj) => obj.GetHashCode(); - - /// - public bool Equals(CieLab x, CieLab y) - { - return this.Equals(x.L, y.L) - && this.Equals(x.A, y.A) - && this.Equals(x.B, y.B); - } - - /// - public int GetHashCode(CieLab obj) => obj.GetHashCode(); - - /// - public bool Equals(CieLch x, CieLch y) - { - return this.Equals(x.L, y.L) - && this.Equals(x.C, y.C) - && this.Equals(x.H, y.H); - } - - /// - public int GetHashCode(CieLch obj) => obj.GetHashCode(); - - /// - public bool Equals(CieLchuv x, CieLchuv y) - { - return this.Equals(x.L, y.L) - && this.Equals(x.C, y.C) - && this.Equals(x.H, y.H); - } - - /// - public int GetHashCode(CieLchuv obj) => obj.GetHashCode(); - - /// - public bool Equals(CieLuv x, CieLuv y) - { - return this.Equals(x.L, y.L) - && this.Equals(x.U, y.U) - && this.Equals(x.V, y.V); - } - - /// - public int GetHashCode(CieLuv obj) => obj.GetHashCode(); - - /// - public bool Equals(CieXyz x, CieXyz y) - { - return this.Equals(x.X, y.X) - && this.Equals(x.Y, y.Y) - && this.Equals(x.Z, y.Z); - } - - /// - public int GetHashCode(CieXyz obj) => obj.GetHashCode(); - - /// - public bool Equals(CieXyy x, CieXyy y) - { - return this.Equals(x.X, y.X) - && this.Equals(x.Y, y.Y) - && this.Equals(x.Yl, y.Yl); - } - - /// - public int GetHashCode(CieXyy obj) => obj.GetHashCode(); - - /// - public bool Equals(Cmyk x, Cmyk y) - { - return this.Equals(x.C, y.C) - && this.Equals(x.M, y.M) - && this.Equals(x.Y, y.Y) - && this.Equals(x.K, y.K); - } - - /// - public int GetHashCode(Cmyk obj) => obj.GetHashCode(); - - /// - public bool Equals(HunterLab x, HunterLab y) - { - return this.Equals(x.L, y.L) - && this.Equals(x.A, y.A) - && this.Equals(x.B, y.B); - } - - /// - public int GetHashCode(HunterLab obj) => obj.GetHashCode(); - - /// - public bool Equals(Hsl x, Hsl y) - { - return this.Equals(x.H, y.H) - && this.Equals(x.S, y.S) - && this.Equals(x.L, y.L); - } - - /// - public int GetHashCode(Hsl obj) => obj.GetHashCode(); - - /// - public bool Equals(Hsv x, Hsv y) - { - return this.Equals(x.H, y.H) - && this.Equals(x.S, y.S) - && this.Equals(x.V, y.V); - } - - /// - public int GetHashCode(Hsv obj) => obj.GetHashCode(); - - /// - public bool Equals(Lms x, Lms y) - { - return this.Equals(x.L, y.L) - && this.Equals(x.M, y.M) - && this.Equals(x.S, y.S); - } - - /// - public int GetHashCode(Lms obj) => obj.GetHashCode(); - - /// - public bool Equals(YCbCr x, YCbCr y) - { - return this.Equals(x.Y, y.Y) - && this.Equals(x.Cb, y.Cb) - && this.Equals(x.Cr, y.Cr); - } - - /// - public int GetHashCode(YCbCr obj) => obj.GetHashCode(); - - /// - public bool Equals(CieXyChromaticityCoordinates x, CieXyChromaticityCoordinates y) => this.Equals(x.X, y.X) && this.Equals(x.Y, y.Y); - - /// - public int GetHashCode(CieXyChromaticityCoordinates obj) => obj.GetHashCode(); - - /// - public bool Equals(RgbPrimariesChromaticityCoordinates x, RgbPrimariesChromaticityCoordinates y) => this.Equals(x.R, y.R) && this.Equals(x.G, y.G) && this.Equals(x.B, y.B); - - /// - public int GetHashCode(RgbPrimariesChromaticityCoordinates obj) => obj.GetHashCode(); - - /// - public bool Equals(GammaWorkingSpace x, GammaWorkingSpace y) - { - if (x is GammaWorkingSpace g1 && y is GammaWorkingSpace g2) - { - return this.Equals(g1.Gamma, g2.Gamma) - && this.Equals(g1.WhitePoint, g2.WhitePoint) - && this.Equals(g1.ChromaticityCoordinates, g2.ChromaticityCoordinates); - } - - return false; - } - - /// - public int GetHashCode(GammaWorkingSpace obj) => obj.GetHashCode(); - - /// - public bool Equals(RgbWorkingSpace x, RgbWorkingSpace y) - { - return this.Equals(x.WhitePoint, y.WhitePoint) - && this.Equals(x.ChromaticityCoordinates, y.ChromaticityCoordinates); - } - - /// - public int GetHashCode(RgbWorkingSpace obj) => obj.GetHashCode(); - - private bool Equals(float x, float y) - { - float d = x - y; - return d >= -this.epsilon && d <= this.epsilon; - } -} diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndCieLchuvConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndCieLchuvConversionTests.cs deleted file mode 100644 index d8378217e4..0000000000 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndCieLchuvConversionTests.cs +++ /dev/null @@ -1,80 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion; - -namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion; - -/// -/// Tests - conversions. -/// -/// -/// Test data generated using: -/// -/// -public class CieLabAndCieLchuvConversionTests -{ - private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0002F); - private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 0, 0, 0, 0, 0)] - [InlineData(30.66194, 200, 352.7564, 31.95653, 116.8745, 2.388602)] - public void Convert_Lchuv_to_Lab(float l, float c, float h, float l2, float a, float b) - { - // Arrange - var input = new CieLchuv(l, c, h); - var expected = new CieLab(l2, a, b); - - Span inputSpan = new CieLchuv[5]; - inputSpan.Fill(input); - - Span actualSpan = new CieLab[5]; - - // Act - var actual = Converter.ToCieLab(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 0, 0, 0, 0, 0)] - [InlineData(36.0555, 303.6901, 10.01514, 30.66194, 200, 352.7564)] - public void Convert_Lab_to_Lchuv(float l, float a, float b, float l2, float c, float h) - { - // Arrange - var input = new CieLab(l, a, b); - var expected = new CieLchuv(l2, c, h); - - Span inputSpan = new CieLab[5]; - inputSpan.Fill(input); - - Span actualSpan = new CieLchuv[5]; - - // Act - var actual = Converter.ToCieLchuv(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } -} diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndCieLuvConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndCieLuvConversionTests.cs deleted file mode 100644 index 220ef4f220..0000000000 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndCieLuvConversionTests.cs +++ /dev/null @@ -1,80 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion; - -namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion; - -/// -/// Tests - conversions. -/// -/// -/// Test data generated using: -/// -/// -public class CieLabAndCieLuvConversionTests -{ - private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0002F); - private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 0, 0, 0, 0, 0)] - [InlineData(10, 36.0555, 303.6901, 10.0151367, -23.9644356, 17.0226)] - public void Convert_CieLuv_to_CieLab(float l, float u, float v, float l2, float a, float b) - { - // Arrange - var input = new CieLuv(l, u, v); - var expected = new CieLab(l2, a, b); - - Span inputSpan = new CieLuv[5]; - inputSpan.Fill(input); - - Span actualSpan = new CieLab[5]; - - // Act - var actual = Converter.ToCieLab(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 0, 0, 0, 0, 0)] - [InlineData(10.0151367, -23.9644356, 17.0226, 10.0000038, -12.830183, 15.1829338)] - public void Convert_CieLab_to_CieLuv(float l, float a, float b, float l2, float u, float v) - { - // Arrange - var input = new CieLab(l, a, b); - var expected = new CieLuv(l2, u, v); - - Span inputSpan = new CieLab[5]; - inputSpan.Fill(input); - - Span actualSpan = new CieLuv[5]; - - // Act - var actual = Converter.ToCieLuv(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } -} diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndCieXyyConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndCieXyyConversionTests.cs deleted file mode 100644 index 49ea4502fc..0000000000 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndCieXyyConversionTests.cs +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion; - -namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion; - -/// -/// Tests - conversions. -/// -public class CieLabAndCieXyyConversionTests -{ - private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0002F); - private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 0, 0, 0, 0, 0)] - [InlineData(0.8644734, 0.06098868, 0.06509002, 36.05552, 275.6228, 10.01517)] - public void Convert_CieXyy_to_CieLab(float x, float y, float yl, float l, float a, float b) - { - // Arrange - var input = new CieXyy(x, y, yl); - var expected = new CieLab(l, a, b); - - Span inputSpan = new CieXyy[5]; - inputSpan.Fill(input); - - Span actualSpan = new CieLab[5]; - - // Act - var actual = Converter.ToCieLab(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 0, 0, 0, 0, 0)] - [InlineData(36.0555, 303.6901, 10.01514, 0.8644734, 0.06098868, 0.06509002)] - public void Convert_CieLab_to_CieXyy(float l, float a, float b, float x, float y, float yl) - { - // Arrange - var input = new CieLab(l, a, b); - var expected = new CieXyy(x, y, yl); - - Span inputSpan = new CieLab[5]; - inputSpan.Fill(input); - - Span actualSpan = new CieXyy[5]; - - // Act - var actual = Converter.ToCieXyy(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } -} diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndCmykConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndCmykConversionTests.cs deleted file mode 100644 index 7f9470e202..0000000000 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndCmykConversionTests.cs +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion; - -namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion; - -/// -/// Tests - conversions. -/// -public class CieLabAndCmykConversionTests -{ - private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0002F); - private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 0, 0, 1, 0, 0, 0)] - [InlineData(0, 1, 0.6156551, 5.960464E-08, 55.063, 82.54871, 23.16506)] - public void Convert_Cmyk_to_CieLab(float c, float m, float y, float k, float l, float a, float b) - { - // Arrange - var input = new Cmyk(c, m, y, k); - var expected = new CieLab(l, a, b); - - Span inputSpan = new Cmyk[5]; - inputSpan.Fill(input); - - Span actualSpan = new CieLab[5]; - - // Act - var actual = Converter.ToCieLab(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 0, 0, 0, 0, 0, 1)] - [InlineData(36.0555, 303.6901, 10.01514, 0, 1, 0.6156551, 5.960464E-08)] - public void Convert_CieLab_to_Cmyk(float l, float a, float b, float c, float m, float y, float k) - { - // Arrange - var input = new CieLab(l, a, b); - var expected = new Cmyk(c, m, y, k); - - Span inputSpan = new CieLab[5]; - inputSpan.Fill(input); - - Span actualSpan = new Cmyk[5]; - - // Act - var actual = Converter.ToCmyk(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } -} diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndHslConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndHslConversionTests.cs deleted file mode 100644 index 1af6a9315f..0000000000 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndHslConversionTests.cs +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion; - -namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion; - -/// -/// Tests - conversions. -/// -public class CieLabAndHslConversionTests -{ - private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0002F); - private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 0, 0, 0, 0, 0)] - [InlineData(336.9393, 1, 0.5, 55.063, 82.54868, 23.16508)] - public void Convert_Hsl_to_CieLab(float h, float s, float ll, float l, float a, float b) - { - // Arrange - var input = new Hsl(h, s, ll); - var expected = new CieLab(l, a, b); - - Span inputSpan = new Hsl[5]; - inputSpan.Fill(input); - - Span actualSpan = new CieLab[5]; - - // Act - var actual = Converter.ToCieLab(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 0, 0, 0, 0, 0)] - [InlineData(36.0555, 303.6901, 10.01514, 336.9393, 1, 0.5)] - public void Convert_CieLab_to_Hsl(float l, float a, float b, float h, float s, float ll) - { - // Arrange - var input = new CieLab(l, a, b); - var expected = new Hsl(h, s, ll); - - Span inputSpan = new CieLab[5]; - inputSpan.Fill(input); - - Span actualSpan = new Hsl[5]; - - // Act - var actual = Converter.ToHsl(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } -} diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndHsvConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndHsvConversionTests.cs deleted file mode 100644 index c7c3ad19b5..0000000000 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndHsvConversionTests.cs +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion; - -namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion; - -/// -/// Tests - conversions. -/// -public class CieLabAndHsvConversionTests -{ - private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0002F); - private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 0, 0, 0, 0, 0)] - [InlineData(336.9393, 1, 0.9999999, 55.063, 82.54871, 23.16504)] - public void Convert_Hsv_to_CieLab(float h, float s, float v, float l, float a, float b) - { - // Arrange - var input = new Hsv(h, s, v); - var expected = new CieLab(l, a, b); - - Span inputSpan = new Hsv[5]; - inputSpan.Fill(input); - - Span actualSpan = new CieLab[5]; - - // Act - var actual = Converter.ToCieLab(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 0, 0, 0, 0, 0)] - [InlineData(36.0555, 303.6901, 10.01514, 336.9393, 1, 0.9999999)] - public void Convert_CieLab_to_Hsv(float l, float a, float b, float h, float s, float v) - { - // Arrange - var input = new CieLab(l, a, b); - var expected = new Hsv(h, s, v); - - Span inputSpan = new CieLab[5]; - inputSpan.Fill(input); - - Span actualSpan = new Hsv[5]; - - // Act - var actual = Converter.ToHsv(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } -} diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndHunterLabConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndHunterLabConversionTests.cs deleted file mode 100644 index 81fff6e144..0000000000 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndHunterLabConversionTests.cs +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion; - -namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion; - -/// -/// Tests - conversions. -/// -public class CieLabAndHunterLabConversionTests -{ - private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0002F); - private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 0, 0, 0, 0, 0)] - [InlineData(27.51646, 556.9392, -0.03974226, 36.05554, 275.6227, 10.01519)] - public void Convert_HunterLab_to_CieLab(float l2, float a2, float b2, float l, float a, float b) - { - // Arrange - var input = new HunterLab(l2, a2, b2); - var expected = new CieLab(l, a, b); - - Span inputSpan = new HunterLab[5]; - inputSpan.Fill(input); - - Span actualSpan = new CieLab[5]; - - // Act - var actual = Converter.ToCieLab(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 0, 0, 0, 0, 0)] - [InlineData(36.0555, 303.6901, 10.01514, 27.51646, 556.9392, -0.03974226)] - public void Convert_CieLab_to_HunterLab(float l, float a, float b, float l2, float a2, float b2) - { - // Arrange - var input = new CieLab(l, a, b); - var expected = new HunterLab(l2, a2, b2); - - Span inputSpan = new CieLab[5]; - inputSpan.Fill(input); - - Span actualSpan = new HunterLab[5]; - - // Act - var actual = Converter.ToHunterLab(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } -} diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndLinearRgbConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndLinearRgbConversionTests.cs deleted file mode 100644 index 68547d8a22..0000000000 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndLinearRgbConversionTests.cs +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion; - -namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion; - -/// -/// Tests - conversions. -/// -public class CieLabAndLinearRgbConversionTests -{ - private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0002F); - private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 0, 0, 0, 0, 0)] - [InlineData(1, 0, 0.1221596, 55.063, 82.54871, 23.16505)] - public void Convert_LinearRgb_to_CieLab(float r, float g, float b2, float l, float a, float b) - { - // Arrange - var input = new LinearRgb(r, g, b2); - var expected = new CieLab(l, a, b); - - Span inputSpan = new LinearRgb[5]; - inputSpan.Fill(input); - - Span actualSpan = new CieLab[5]; - - // Act - var actual = Converter.ToCieLab(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 0, 0, 0, 0, 0)] - [InlineData(36.0555, 303.6901, 10.01514, 1, 0, 0.1221596)] - public void Convert_CieLab_to_LinearRgb(float l, float a, float b, float r, float g, float b2) - { - // Arrange - var input = new CieLab(l, a, b); - var expected = new LinearRgb(r, g, b2); - - Span inputSpan = new CieLab[5]; - inputSpan.Fill(input); - - Span actualSpan = new LinearRgb[5]; - - // Act - var actual = Converter.ToLinearRgb(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } -} diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndLmsConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndLmsConversionTests.cs deleted file mode 100644 index 2918b6f62b..0000000000 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndLmsConversionTests.cs +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion; - -namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion; - -/// -/// Tests - conversions. -/// -public class CieLabAndLmsConversionTests -{ - private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0002F); - private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 0, 0, 0, 0, 0)] - [InlineData(0.8303261, -0.5776886, 0.1133359, 36.05553, 275.6228, 10.01518)] - public void Convert_Lms_to_CieLab(float l2, float m, float s, float l, float a, float b) - { - // Arrange - var input = new Lms(l2, m, s); - var expected = new CieLab(l, a, b); - - Span inputSpan = new Lms[5]; - inputSpan.Fill(input); - - Span actualSpan = new CieLab[5]; - - // Act - var actual = Converter.ToCieLab(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 0, 0, 0, 0, 0)] - [InlineData(36.0555, 303.6901, 10.01514, 0.8303261, -0.5776886, 0.1133359)] - public void Convert_CieLab_to_Lms(float l, float a, float b, float l2, float m, float s) - { - // Arrange - var input = new CieLab(l, a, b); - var expected = new Lms(l2, m, s); - - Span inputSpan = new CieLab[5]; - inputSpan.Fill(input); - - Span actualSpan = new Lms[5]; - - // Act - var actual = Converter.ToLms(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } -} diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndRgbConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndRgbConversionTests.cs deleted file mode 100644 index 3acf695d12..0000000000 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndRgbConversionTests.cs +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion; - -namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion; - -/// -/// Tests - conversions. -/// -public class CieLabAndRgbConversionTests -{ - private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0002F); - private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 0, 0, 0, 0, 0)] - [InlineData(0.9999999, 0, 0.384345, 55.063, 82.54871, 23.16505)] - public void Convert_Rgb_to_CieLab(float r, float g, float b2, float l, float a, float b) - { - // Arrange - var input = new Rgb(r, g, b2); - var expected = new CieLab(l, a, b); - - Span inputSpan = new Rgb[5]; - inputSpan.Fill(input); - - Span actualSpan = new CieLab[5]; - - // Act - var actual = Converter.ToCieLab(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 0, 0, 0, 0, 0)] - [InlineData(36.0555, 303.6901, 10.01514, 0.9999999, 0, 0.384345)] - public void Convert_CieLab_to_Rgb(float l, float a, float b, float r, float g, float b2) - { - // Arrange - var input = new CieLab(l, a, b); - var expected = new Rgb(r, g, b2); - - Span inputSpan = new CieLab[5]; - inputSpan.Fill(input); - - Span actualSpan = new Rgb[5]; - - // Act - var actual = Converter.ToRgb(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } -} diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndYCbCrConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndYCbCrConversionTests.cs deleted file mode 100644 index f13e989a85..0000000000 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndYCbCrConversionTests.cs +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion; - -namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion; - -/// -/// Tests - conversions. -/// -public class CieLabAndYCbCrConversionTests -{ - private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0002F); - private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 128, 128, 0, 0, 0)] - [InlineData(87.4179, 133.9763, 247.5308, 55.06287, 82.54838, 23.1697)] - public void Convert_YCbCr_to_CieLab(float y, float cb, float cr, float l, float a, float b) - { - // Arrange - var input = new YCbCr(y, cb, cr); - var expected = new CieLab(l, a, b); - - Span inputSpan = new YCbCr[5]; - inputSpan.Fill(input); - - Span actualSpan = new CieLab[5]; - - // Act - var actual = Converter.ToCieLab(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 0, 0, 0, 128, 128)] - [InlineData(36.0555, 303.6901, 10.01514, 87.4179, 133.9763, 247.5308)] - public void Convert_CieLab_to_YCbCr(float l, float a, float b, float y, float cb, float cr) - { - // Arrange - var input = new CieLab(l, a, b); - var expected = new YCbCr(y, cb, cr); - - Span inputSpan = new CieLab[5]; - inputSpan.Fill(input); - - Span actualSpan = new YCbCr[5]; - - // Act - var actual = Converter.ToYCbCr(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } -} diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndCieLuvConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndCieLuvConversionTests.cs deleted file mode 100644 index b50d47aeba..0000000000 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndCieLuvConversionTests.cs +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion; - -namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion; - -/// -/// Tests - conversions. -/// -public class CieLchAndCieLuvConversionTests -{ - private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0002F); - private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 0, 0, 0, 0, 0)] - [InlineData(36.0555, 103.6901, 10.01514, 34.89777, 187.6642, -7.181467)] - public void Convert_CieLch_to_CieLuv(float l, float c, float h, float l2, float u, float v) - { - // Arrange - var input = new CieLch(l, c, h); - var expected = new CieLuv(l2, u, v); - - Span inputSpan = new CieLch[5]; - inputSpan.Fill(input); - - Span actualSpan = new CieLuv[5]; - - // Act - var actual = Converter.ToCieLuv(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(34.89777, 187.6642, -7.181467, 36.05552, 103.6901, 10.01514)] - public void Convert_CieLuv_to_CieLch(float l2, float u, float v, float l, float c, float h) - { - // Arrange - var input = new CieLuv(l2, u, v); - var expected = new CieLch(l, c, h); - - Span inputSpan = new CieLuv[5]; - inputSpan.Fill(input); - - Span actualSpan = new CieLch[5]; - - // Act - var actual = Converter.ToCieLch(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } -} diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndCieXyyConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndCieXyyConversionTests.cs deleted file mode 100644 index 93f0828861..0000000000 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndCieXyyConversionTests.cs +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion; - -namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion; - -/// -/// Tests - conversions. -/// -public class CieLchAndCieXyyConversionTests -{ - private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0002F); - private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 0, 0, 0, 0, 0)] - [InlineData(36.0555, 103.6901, 10.01514, 0.6529307, 0.2147411, 0.08447381)] - public void Convert_CieLch_to_CieXyy(float l, float c, float h, float x, float y, float yl) - { - // Arrange - var input = new CieLch(l, c, h); - var expected = new CieXyy(x, y, yl); - - Span inputSpan = new CieLch[5]; - inputSpan.Fill(input); - - Span actualSpan = new CieXyy[5]; - - // Act - var actual = Converter.ToCieXyy(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0.6529307, 0.2147411, 0.08447381, 36.05552, 103.6901, 10.01515)] - public void Convert_CieXyy_to_CieLch(float x, float y, float yl, float l, float c, float h) - { - // Arrange - var input = new CieXyy(x, y, yl); - var expected = new CieLch(l, c, h); - - Span inputSpan = new CieXyy[5]; - inputSpan.Fill(input); - - Span actualSpan = new CieLch[5]; - - // Act - var actual = Converter.ToCieLch(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } -} diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndHslConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndHslConversionTests.cs deleted file mode 100644 index 0bc76562b1..0000000000 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndHslConversionTests.cs +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion; - -namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion; - -/// -/// Tests - conversions. -/// -public class CieLchAndHslConversionTests -{ - private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0002F); - private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 0, 0, 0, 0, 0)] - [InlineData(36.0555, 103.6901, 10.01514, 341.959, 1, 0.4207301)] - public void Convert_CieLch_to_Hsl(float l, float c, float h, float h2, float s, float l2) - { - // Arrange - var input = new CieLch(l, c, h); - var expected = new Hsl(h2, s, l2); - - Span inputSpan = new CieLch[5]; - inputSpan.Fill(input); - - Span actualSpan = new Hsl[5]; - - // Act - var actual = Converter.ToHsl(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(341.959, 1, 0.4207301, 46.13444, 78.0637, 22.90503)] - public void Convert_Hsl_to_CieLch(float h2, float s, float l2, float l, float c, float h) - { - // Arrange - var input = new Hsl(h2, s, l2); - var expected = new CieLch(l, c, h); - - Span inputSpan = new Hsl[5]; - inputSpan.Fill(input); - - Span actualSpan = new CieLch[5]; - - // Act - var actual = Converter.ToCieLch(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } -} diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndHsvConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndHsvConversionTests.cs deleted file mode 100644 index bb28c03946..0000000000 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndHsvConversionTests.cs +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion; - -namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion; - -/// -/// Tests - conversions. -/// -public class CieLchAndHsvConversionTests -{ - private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0002F); - private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 0, 0, 0, 0, 0)] - [InlineData(36.0555, 103.6901, 10.01514, 341.959, 1, 0.8414602)] - public void Convert_CieLch_to_Hsv(float l, float c, float h, float h2, float s, float v) - { - // Arrange - var input = new CieLch(l, c, h); - var expected = new Hsv(h2, s, v); - - Span inputSpan = new CieLch[5]; - inputSpan.Fill(input); - - Span actualSpan = new Hsv[5]; - - // Act - var actual = Converter.ToHsv(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(341.959, 1, 0.8414602, 46.13444, 78.0637, 22.90501)] - public void Convert_Hsv_to_CieLch(float h2, float s, float v, float l, float c, float h) - { - // Arrange - var input = new Hsv(h2, s, v); - var expected = new CieLch(l, c, h); - - Span inputSpan = new Hsv[5]; - inputSpan.Fill(input); - - Span actualSpan = new CieLch[5]; - - // Act - var actual = Converter.ToCieLch(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } -} diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndHunterLabConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndHunterLabConversionTests.cs deleted file mode 100644 index 9892ac8f57..0000000000 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndHunterLabConversionTests.cs +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion; - -namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion; - -/// -/// Tests - conversions. -/// -public class CieLchAndHunterLabConversionTests -{ - private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0002F); - private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 0, 0, 0, 0, 0)] - [InlineData(36.0555, 103.6901, 10.01514, 29.41358, 106.6302, 9.102425)] - public void Convert_CieLch_to_HunterLab(float l, float c, float h, float l2, float a, float b) - { - // Arrange - var input = new CieLch(l, c, h); - var expected = new HunterLab(l2, a, b); - - Span inputSpan = new CieLch[5]; - inputSpan.Fill(input); - - Span actualSpan = new HunterLab[5]; - - // Act - var actual = Converter.ToHunterLab(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(29.41358, 106.6302, 9.102425, 36.05551, 103.6901, 10.01515)] - public void Convert_HunterLab_to_CieLch(float l2, float a, float b, float l, float c, float h) - { - // Arrange - var input = new HunterLab(l2, a, b); - var expected = new CieLch(l, c, h); - - Span inputSpan = new HunterLab[5]; - inputSpan.Fill(input); - - Span actualSpan = new CieLch[5]; - - // Act - var actual = Converter.ToCieLch(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } -} diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndLinearRgbConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndLinearRgbConversionTests.cs deleted file mode 100644 index 3ecfadf113..0000000000 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndLinearRgbConversionTests.cs +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion; - -namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion; - -/// -/// Tests - conversions. -/// -public class CieLchAndLinearRgbConversionTests -{ - private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0002F); - private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 0, 0, 0, 0, 0)] - [InlineData(36.0555, 103.6901, 10.01514, 0.6765013, 0, 0.05209038)] - public void Convert_CieLch_to_LinearRgb(float l, float c, float h, float r, float g, float b) - { - // Arrange - var input = new CieLch(l, c, h); - var expected = new LinearRgb(r, g, b); - - Span inputSpan = new CieLch[5]; - inputSpan.Fill(input); - - Span actualSpan = new LinearRgb[5]; - - // Act - var actual = Converter.ToLinearRgb(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0.6765013, 0, 0.05209038, 46.13445, 78.06367, 22.90504)] - public void Convert_LinearRgb_to_CieLch(float r, float g, float b, float l, float c, float h) - { - // Arrange - var input = new LinearRgb(r, g, b); - var expected = new CieLch(l, c, h); - - Span inputSpan = new LinearRgb[5]; - inputSpan.Fill(input); - - Span actualSpan = new CieLch[5]; - - // Act - var actual = Converter.ToCieLch(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } -} diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndLmsConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndLmsConversionTests.cs deleted file mode 100644 index 7a19391211..0000000000 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndLmsConversionTests.cs +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion; - -namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion; - -/// -/// Tests - conversions. -/// -public class CieLchAndLmsConversionTests -{ - private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0002F); - private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 0, 0, 0, 0, 0)] - [InlineData(36.0555, 103.6901, 10.01514, 0.2440057, -0.04603009, 0.05780027)] - public void Convert_CieLch_to_Lms(float l, float c, float h, float l2, float m, float s) - { - // Arrange - var input = new CieLch(l, c, h); - var expected = new Lms(l2, m, s); - - Span inputSpan = new CieLch[5]; - inputSpan.Fill(input); - - Span actualSpan = new Lms[5]; - - // Act - var actual = Converter.ToLms(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0.2440057, -0.04603009, 0.05780027, 36.05552, 103.6901, 10.01515)] - public void Convert_Lms_to_CieLch(float l2, float m, float s, float l, float c, float h) - { - // Arrange - var input = new Lms(l2, m, s); - var expected = new CieLch(l, c, h); - - Span inputSpan = new Lms[5]; - inputSpan.Fill(input); - - Span actualSpan = new CieLch[5]; - - // Act - var actual = Converter.ToCieLch(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } -} diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndRgbConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndRgbConversionTests.cs deleted file mode 100644 index 013e79534d..0000000000 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndRgbConversionTests.cs +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion; - -namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion; - -/// -/// Tests - conversions. -/// -public class CieLchAndRgbConversionTests -{ - private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0002F); - private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 0, 0, 0, 0, 0)] - [InlineData(36.0555, 103.6901, 10.01514, 0.8414602, 0, 0.2530123)] - public void Convert_CieLch_to_Rgb(float l, float c, float h, float r, float g, float b) - { - // Arrange - var input = new CieLch(l, c, h); - var expected = new Rgb(r, g, b); - - Span inputSpan = new CieLch[5]; - inputSpan.Fill(input); - - Span actualSpan = new Rgb[5]; - - // Act - var actual = Converter.ToRgb(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0.8414602, 0, 0.2530123, 46.13444, 78.0637, 22.90503)] - public void Convert_Rgb_to_CieLch(float r, float g, float b, float l, float c, float h) - { - // Arrange - var input = new Rgb(r, g, b); - var expected = new CieLch(l, c, h); - - Span inputSpan = new Rgb[5]; - inputSpan.Fill(input); - - Span actualSpan = new CieLch[5]; - - // Act - var actual = Converter.ToCieLch(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } -} diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndYCbCrConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndYCbCrConversionTests.cs deleted file mode 100644 index bcde97102f..0000000000 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndYCbCrConversionTests.cs +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion; - -namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion; - -/// -/// Tests - conversions. -/// -public class CieLchAndYCbCrConversionTests -{ - private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0002F); - private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 0, 0, 0, 128, 128)] - [InlineData(36.0555, 103.6901, 10.01514, 71.5122, 124.053, 230.0401)] - public void Convert_CieLch_to_YCbCr(float l, float c, float h, float y, float cb, float cr) - { - // Arrange - var input = new CieLch(l, c, h); - var expected = new YCbCr(y, cb, cr); - - Span inputSpan = new CieLch[5]; - inputSpan.Fill(input); - - Span actualSpan = new YCbCr[5]; - - // Act - var actual = Converter.ToYCbCr(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(71.5122, 124.053, 230.0401, 46.23178, 78.1114, 22.7662)] - public void Convert_YCbCr_to_CieLch(float y, float cb, float cr, float l, float c, float h) - { - // Arrange - var input = new YCbCr(y, cb, cr); - var expected = new CieLch(l, c, h); - - Span inputSpan = new YCbCr[5]; - inputSpan.Fill(input); - - Span actualSpan = new CieLch[5]; - - // Act - var actual = Converter.ToCieLch(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } -} diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchuvAndCieLchConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchuvAndCieLchConversionTests.cs deleted file mode 100644 index 1098de91e0..0000000000 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchuvAndCieLchConversionTests.cs +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion; - -namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion; - -/// -/// Tests - conversions. -/// -public class CieLchuvAndCieLchConversionTests -{ - private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0002F); - private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 0, 0, 0, 0, 0)] - [InlineData(36.73742, 64.79149, 30.1786, 36.0555, 103.6901, 10.01513)] - public void Convert_CieLch_to_CieLchuv(float l2, float c2, float h2, float l, float c, float h) - { - // Arrange - var input = new CieLch(l2, c2, h2); - var expected = new CieLchuv(l, c, h); - - Span inputSpan = new CieLch[5]; - inputSpan.Fill(input); - - Span actualSpan = new CieLchuv[5]; - - // Act - var actual = Converter.ToCieLchuv(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(36.0555, 103.6901, 10.01514, 36.73742, 64.79149, 30.1786)] - public void Convert_CieLchuv_to_CieLch(float l, float c, float h, float l2, float c2, float h2) - { - // Arrange - var input = new CieLchuv(l, c, h); - var expected = new CieLch(l2, c2, h2); - - Span inputSpan = new CieLchuv[5]; - inputSpan.Fill(input); - - Span actualSpan = new CieLch[5]; - - // Act - var actual = Converter.ToCieLch(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } -} diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchuvAndCmykConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchuvAndCmykConversionTests.cs deleted file mode 100644 index 176a0e2175..0000000000 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchuvAndCmykConversionTests.cs +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion; - -namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion; - -/// -/// Tests - conversions. -/// -public class CieLchuvAndCmykConversionTests -{ - private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0002F); - private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 0, 0, 1, 0, 0, 0)] - [InlineData(0, 0.8576171, 0.7693201, 0.3440427, 36.0555, 103.6901, 10.01514)] - public void Convert_Cmyk_to_CieLchuv(float c2, float m, float y, float k, float l, float c, float h) - { - // Arrange - var input = new Cmyk(c2, m, y, k); - var expected = new CieLchuv(l, c, h); - - Span inputSpan = new Cmyk[5]; - inputSpan.Fill(input); - - Span actualSpan = new CieLchuv[5]; - - // Act - var actual = Converter.ToCieLchuv(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 0, 0, 0, 0, 0, 1)] - [InlineData(36.0555, 103.6901, 10.01514, 0, 0.8576171, 0.7693201, 0.3440427)] - public void Convert_CieLchuv_to_Cmyk(float l, float c, float h, float c2, float m, float y, float k) - { - // Arrange - var input = new CieLchuv(l, c, h); - var expected = new Cmyk(c2, m, y, k); - - Span inputSpan = new CieLchuv[5]; - inputSpan.Fill(input); - - Span actualSpan = new Cmyk[5]; - - // Act - var actual = Converter.ToCmyk(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } -} diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndCieXyyConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndCieXyyConversionTests.cs deleted file mode 100644 index e32cc6ebfc..0000000000 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndCieXyyConversionTests.cs +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion; - -namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion; - -/// -/// Tests - conversions. -/// -public class CieLuvAndCieXyyConversionTests -{ - private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0002F); - private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 0, 0, 0, 0, 0)] - [InlineData(36.0555, 103.6901, 10.01514, 0.5646762, 0.2932749, 0.09037033)] - public void Convert_CieLuv_to_CieXyy(float l, float u, float v, float x, float y, float yl) - { - // Arrange - var input = new CieLuv(l, u, v); - var expected = new CieXyy(x, y, yl); - - Span inputSpan = new CieLuv[5]; - inputSpan.Fill(input); - - Span actualSpan = new CieXyy[5]; - - // Act - var actual = Converter.ToCieXyy(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 0, 0, 0, 0, 0)] - [InlineData(0.5646762, 0.2932749, 0.09037033, 36.0555, 103.6901, 10.01514)] - public void Convert_CieXyy_to_CieLuv(float x, float y, float yl, float l, float u, float v) - { - // Arrange - var input = new CieXyy(x, y, yl); - var expected = new CieLuv(l, u, v); - - Span inputSpan = new CieXyy[5]; - inputSpan.Fill(input); - - Span actualSpan = new CieLuv[5]; - - // Act - var actual = Converter.ToCieLuv(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } -} diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndHslConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndHslConversionTests.cs deleted file mode 100644 index 95f07465ab..0000000000 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndHslConversionTests.cs +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion; - -namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion; - -/// -/// Tests - conversions. -/// -public class CieLuvAndHslConversionTests -{ - private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0002F); - private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 0, 0, 0, 0, 0)] - [InlineData(36.0555, 93.6901, 10.01514, 347.3767, 0.7115612, 0.3765343)] - public void Convert_CieLuv_to_Hsl(float l, float u, float v, float h, float s, float l2) - { - // Arrange - var input = new CieLuv(l, u, v); - var expected = new Hsl(h, s, l2); - - Span inputSpan = new CieLuv[5]; - inputSpan.Fill(input); - - Span actualSpan = new Hsl[5]; - - // Act - var actual = Converter.ToHsl(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 0, 0, 0, 0, 0)] - [InlineData(347.3767, 0.7115612, 0.3765343, 36.0555, 93.69012, 10.01514)] - public void Convert_Hsl_to_CieLuv(float h, float s, float l2, float l, float u, float v) - { - // Arrange - var input = new Hsl(h, s, l2); - var expected = new CieLuv(l, u, v); - - Span inputSpan = new Hsl[5]; - inputSpan.Fill(input); - - Span actualSpan = new CieLuv[5]; - - // Act - var actual = Converter.ToCieLuv(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } -} diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndHsvConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndHsvConversionTests.cs deleted file mode 100644 index ddb90f0ef9..0000000000 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndHsvConversionTests.cs +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion; - -namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion; - -/// -/// Tests - conversions. -/// -public class CieLuvAndHsvConversionTests -{ - private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0002F); - private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 0, 0, 0, 0, 0)] - [InlineData(36.0555, 93.6901, 10.01514, 347.3767, 0.8314762, 0.6444615)] - public void Convert_CieLuv_to_Hsv(float l, float u, float v, float h, float s, float v2) - { - // Arrange - var input = new CieLuv(l, u, v); - var expected = new Hsv(h, s, v2); - - Span inputSpan = new CieLuv[5]; - inputSpan.Fill(input); - - Span actualSpan = new Hsv[5]; - - // Act - var actual = Converter.ToHsv(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 0, 0, 0, 0, 0)] - [InlineData(347.3767, 0.8314762, 0.6444615, 36.0555, 93.69012, 10.01514)] - public void Convert_Hsv_to_CieLuv(float h, float s, float v2, float l, float u, float v) - { - // Arrange - var input = new Hsv(h, s, v2); - var expected = new CieLuv(l, u, v); - - Span inputSpan = new Hsv[5]; - inputSpan.Fill(input); - - Span actualSpan = new CieLuv[5]; - - // Act - var actual = Converter.ToCieLuv(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } -} diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndHunterLabConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndHunterLabConversionTests.cs deleted file mode 100644 index 38449e4b77..0000000000 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndHunterLabConversionTests.cs +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion; - -namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion; - -/// -/// Tests - conversions. -/// -public class CieLuvAndHunterLabConversionTests -{ - private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0002F); - private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 0, 0, 0, 0, 0)] - [InlineData(36.0555, 93.6901, 10.01514, 30.19531, 46.4312, 11.16259)] - public void Convert_CieLuv_to_HunterLab(float l, float u, float v, float l2, float a, float b) - { - // Arrange - var input = new CieLuv(l, u, v); - var expected = new HunterLab(l2, a, b); - - Span inputSpan = new CieLuv[5]; - inputSpan.Fill(input); - - Span actualSpan = new HunterLab[5]; - - // Act - var actual = Converter.ToHunterLab(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 0, 0, 0, 0, 0)] - [InlineData(30.19531, 46.4312, 11.16259, 36.0555, 93.6901, 10.01514)] - public void Convert_HunterLab_to_CieLuv(float l2, float a, float b, float l, float u, float v) - { - // Arrange - var input = new HunterLab(l2, a, b); - var expected = new CieLuv(l, u, v); - - Span inputSpan = new HunterLab[5]; - inputSpan.Fill(input); - - Span actualSpan = new CieLuv[5]; - - // Act - var actual = Converter.ToCieLuv(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } -} diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndLinearRgbConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndLinearRgbConversionTests.cs deleted file mode 100644 index f3bd936043..0000000000 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndLinearRgbConversionTests.cs +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion; - -namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion; - -/// -/// Tests - conversions. -/// -public class CieLuvAndLinearRgbConversionTests -{ - private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0002F); - private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 0, 0, 0, 0, 0)] - [InlineData(36.0555, 93.6901, 10.01514, 0.3729299, 0.01141088, 0.04014909)] - public void Convert_CieLuv_to_LinearRgb(float l, float u, float v, float r, float g, float b) - { - // Arrange - var input = new CieLuv(l, u, v); - var expected = new LinearRgb(r, g, b); - - Span inputSpan = new CieLuv[5]; - inputSpan.Fill(input); - - Span actualSpan = new LinearRgb[5]; - - // Act - var actual = Converter.ToLinearRgb(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 0, 0, 0, 0, 0)] - [InlineData(0.3729299, 0.01141088, 0.04014909, 36.0555, 93.6901, 10.01511)] - public void Convert_LinearRgb_to_CieLuv(float r, float g, float b, float l, float u, float v) - { - // Arrange - var input = new LinearRgb(r, g, b); - var expected = new CieLuv(l, u, v); - - Span inputSpan = new LinearRgb[5]; - inputSpan.Fill(input); - - Span actualSpan = new CieLuv[5]; - - // Act - var actual = Converter.ToCieLuv(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } -} diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndLmsConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndLmsConversionTests.cs deleted file mode 100644 index ac90a7ba41..0000000000 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndLmsConversionTests.cs +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion; - -namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion; - -/// -/// Tests - conversions. -/// -public class CieLuvAndLmsConversionTests -{ - private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0002F); - private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 0, 0, 0, 0, 0)] - [InlineData(36.0555, 93.6901, 10.01514, 0.164352, 0.03267485, 0.0483408)] - public void Convert_CieLuv_to_Lms(float l, float u, float v, float l2, float m, float s) - { - // Arrange - var input = new CieLuv(l, u, v); - var expected = new Lms(l2, m, s); - - Span inputSpan = new CieLuv[5]; - inputSpan.Fill(input); - - Span actualSpan = new Lms[5]; - - // Act - var actual = Converter.ToLms(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 0, 0, 0, 0, 0)] - [InlineData(0.164352, 0.03267485, 0.0483408, 36.0555, 93.69009, 10.01514)] - public void Convert_Lms_to_CieLuv(float l2, float m, float s, float l, float u, float v) - { - // Arrange - var input = new Lms(l2, m, s); - var expected = new CieLuv(l, u, v); - - Span inputSpan = new Lms[5]; - inputSpan.Fill(input); - - Span actualSpan = new CieLuv[5]; - - // Act - var actual = Converter.ToCieLuv(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } -} diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndRgbConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndRgbConversionTests.cs deleted file mode 100644 index b2e308fce0..0000000000 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndRgbConversionTests.cs +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion; - -namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion; - -/// -/// Tests - conversions. -/// -public class CieLuvAndRgbConversionTests -{ - private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0002F); - private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 0, 0, 0, 0, 0)] - [InlineData(36.0555, 93.6901, 10.01514, 0.6444615, 0.1086071, 0.2213444)] - public void Convert_CieLuv_to_Rgb(float l, float u, float v, float r, float g, float b) - { - // Arrange - var input = new CieLuv(l, u, v); - var expected = new Rgb(r, g, b); - - Span inputSpan = new CieLuv[5]; - inputSpan.Fill(input); - - Span actualSpan = new Rgb[5]; - - // Act - var actual = Converter.ToRgb(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 0, 0, 0, 0, 0)] - [InlineData(0.6444615, 0.1086071, 0.2213444, 36.0555, 93.69012, 10.01514)] - public void Convert_Rgb_to_CieLuv(float r, float g, float b, float l, float u, float v) - { - // Arrange - var input = new Rgb(r, g, b); - var expected = new CieLuv(l, u, v); - - Span inputSpan = new Rgb[5]; - inputSpan.Fill(input); - - Span actualSpan = new CieLuv[5]; - - // Act - var actual = Converter.ToCieLuv(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } -} diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndYCbCrConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndYCbCrConversionTests.cs deleted file mode 100644 index f7c6372b1a..0000000000 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndYCbCrConversionTests.cs +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion; - -namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion; - -/// -/// Tests - conversions. -/// -public class CieLuvAndYCbCrConversionTests -{ - private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0002F); - private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 0, 0, 0, 128, 128)] - [InlineData(36.0555, 93.6901, 10.01514, 71.8283, 119.3174, 193.9839)] - public void Convert_CieLuv_to_YCbCr(float l, float u, float v, float y, float cb, float cr) - { - // Arrange - var input = new CieLuv(l, u, v); - var expected = new YCbCr(y, cb, cr); - - Span inputSpan = new CieLuv[5]; - inputSpan.Fill(input); - - Span actualSpan = new YCbCr[5]; - - // Act - var actual = Converter.ToYCbCr(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 128, 128, 0, 0, 0)] - [InlineData(71.8283, 119.3174, 193.9839, 36.00565, 93.44593, 10.2234)] - public void Convert_YCbCr_to_CieLuv(float y, float cb, float cr, float l, float u, float v) - { - // Arrange - var input = new YCbCr(y, cb, cr); - var expected = new CieLuv(l, u, v); - - Span inputSpan = new YCbCr[5]; - inputSpan.Fill(input); - - Span actualSpan = new CieLuv[5]; - - // Act - var actual = Converter.ToCieLuv(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } -} diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndHslConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndHslConversionTests.cs deleted file mode 100644 index bae9140029..0000000000 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndHslConversionTests.cs +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion; - -namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion; - -/// -/// Tests - conversions. -/// -public class CieXyyAndHslConversionTests -{ - private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0002F); - private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 0, 0, 0, 0, 0)] - [InlineData(0.360555, 0.936901, 0.1001514, 120, 1, 0.211263)] - public void Convert_CieXyy_to_Hsl(float x, float y, float yl, float h, float s, float l) - { - // Arrange - var input = new CieXyy(x, y, yl); - var expected = new Hsl(h, s, l); - - Span inputSpan = new CieXyy[5]; - inputSpan.Fill(input); - - Span actualSpan = new Hsl[5]; - - // Act - var actual = Converter.ToHsl(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 0, 0, 0, 0, 0)] - [InlineData(120, 1, 0.211263, 0.3, 0.6, 0.1067051)] - public void Convert_Hsl_to_CieXyy(float h, float s, float l, float x, float y, float yl) - { - // Arrange - var input = new Hsl(h, s, l); - var expected = new CieXyy(x, y, yl); - - Span inputSpan = new Hsl[5]; - inputSpan.Fill(input); - - Span actualSpan = new CieXyy[5]; - - // Act - CieXyy actual = Converter.ToCieXyy(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } -} diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndHsvConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndHsvConversionTests.cs deleted file mode 100644 index 7de91cc322..0000000000 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndHsvConversionTests.cs +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion; - -namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion; - -/// -/// Tests - conversions. -/// -public class CieXyyAndHsvConversionTests -{ - private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0002F); - private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 0, 0, 0, 0, 0)] - [InlineData(0.360555, 0.936901, 0.1001514, 120, 1, 0.4225259)] - public void Convert_CieXyy_to_Hsv(float x, float y, float yl, float h, float s, float v) - { - // Arrange - var input = new CieXyy(x, y, yl); - var expected = new Hsv(h, s, v); - - Span inputSpan = new CieXyy[5]; - inputSpan.Fill(input); - - Span actualSpan = new Hsv[5]; - - // Act - var actual = Converter.ToHsv(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 0, 0, 0, 0, 0)] - [InlineData(120, 1, 0.4225259, 0.3, 0.6, 0.1067051)] - public void Convert_Hsv_to_CieXyy(float h, float s, float v, float x, float y, float yl) - { - // Arrange - var input = new Hsv(h, s, v); - var expected = new CieXyy(x, y, yl); - - Span inputSpan = new Hsv[5]; - inputSpan.Fill(input); - - Span actualSpan = new CieXyy[5]; - - // Act - var actual = Converter.ToCieXyy(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } -} diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndHunterLabConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndHunterLabConversionTests.cs deleted file mode 100644 index 40b58b7048..0000000000 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndHunterLabConversionTests.cs +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion; - -namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion; - -/// -/// Tests - conversions. -/// -public class CieXyyAndHunterLabConversionTests -{ - private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0002F); - private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 0, 0, 0, 0, 0)] - [InlineData(0.360555, 0.936901, 0.1001514, 31.46263, -32.81796, 28.64938)] - public void Convert_CieXyy_to_HunterLab(float x, float y, float yl, float l, float a, float b) - { - // Arrange - var input = new CieXyy(x, y, yl); - var expected = new HunterLab(l, a, b); - - Span inputSpan = new CieXyy[5]; - inputSpan.Fill(input); - - Span actualSpan = new HunterLab[5]; - - // Act - var actual = Converter.ToHunterLab(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 0, 0, 0, 0, 0)] - [InlineData(31.46263, -32.81796, 28.64938, 0.3605552, 0.9369011, 0.1001514)] - public void Convert_HunterLab_to_CieXyy(float l, float a, float b, float x, float y, float yl) - { - // Arrange - var input = new HunterLab(l, a, b); - var expected = new CieXyy(x, y, yl); - - Span inputSpan = new HunterLab[5]; - inputSpan.Fill(input); - - Span actualSpan = new CieXyy[5]; - - // Act - CieXyy actual = Converter.ToCieXyy(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } -} diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndLinearRgbConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndLinearRgbConversionTests.cs deleted file mode 100644 index 062f54abc3..0000000000 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndLinearRgbConversionTests.cs +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion; - -namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion; - -/// -/// Tests - conversions. -/// -public class CieXyyAndLinearRgbConversionTests -{ - private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0002F); - private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 0, 0, 0, 0, 0)] - [InlineData(0.360555, 0.936901, 0.1001514, 0, 0.1492062, 0)] - public void Convert_CieXyy_to_LinearRgb(float x, float y, float yl, float r, float g, float b) - { - // Arrange - var input = new CieXyy(x, y, yl); - var expected = new LinearRgb(r, g, b); - - Span inputSpan = new CieXyy[5]; - inputSpan.Fill(input); - - Span actualSpan = new LinearRgb[5]; - - // Act - var actual = Converter.ToLinearRgb(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 0, 0, 0, 0, 0)] - [InlineData(0, 0.1492062, 0, 0.3, 0.6, 0.1067051)] - public void Convert_LinearRgb_to_CieXyy(float r, float g, float b, float x, float y, float yl) - { - // Arrange - var input = new LinearRgb(r, g, b); - var expected = new CieXyy(x, y, yl); - - Span inputSpan = new LinearRgb[5]; - inputSpan.Fill(input); - - Span actualSpan = new CieXyy[5]; - - // Act - var actual = Converter.ToCieXyy(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } -} diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndLmsConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndLmsConversionTests.cs deleted file mode 100644 index 8e9cbc5ffc..0000000000 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndLmsConversionTests.cs +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion; - -namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion; - -/// -/// Tests - conversions. -/// -public class CieXyyAndLmsConversionTests -{ - private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0002F); - private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 0, 0, 0, 0, 0)] - [InlineData(0.360555, 0.936901, 0.1001514, 0.06631134, 0.1415282, -0.03809926)] - public void Convert_CieXyy_to_Lms(float x, float y, float yl, float l, float m, float s) - { - // Arrange - var input = new CieXyy(x, y, yl); - var expected = new Lms(l, m, s); - - Span inputSpan = new CieXyy[5]; - inputSpan.Fill(input); - - Span actualSpan = new Lms[5]; - - // Act - var actual = Converter.ToLms(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 0, 0, 0, 0, 0)] - [InlineData(0.06631134, 0.1415282, -0.03809926, 0.360555, 0.9369009, 0.1001514)] - public void Convert_Lms_to_CieXyy(float l, float m, float s, float x, float y, float yl) - { - // Arrange - var input = new Lms(l, m, s); - var expected = new CieXyy(x, y, yl); - - Span inputSpan = new Lms[5]; - inputSpan.Fill(input); - - Span actualSpan = new CieXyy[5]; - - // Act - CieXyy actual = Converter.ToCieXyy(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } -} diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndRgbConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndRgbConversionTests.cs deleted file mode 100644 index 0a7cd68429..0000000000 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndRgbConversionTests.cs +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion; - -namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion; - -/// -/// Tests - conversions. -/// -public class CieXyyAndRgbConversionTests -{ - private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0002F); - private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 0, 0, 0, 0, 0)] - [InlineData(0.360555, 0.936901, 0.1001514, 0, 0.4225259, 0)] - public void Convert_CieXyy_to_Rgb(float x, float y, float yl, float r, float g, float b) - { - // Arrange - var input = new CieXyy(x, y, yl); - var expected = new Rgb(r, g, b); - - Span inputSpan = new CieXyy[5]; - inputSpan.Fill(input); - - Span actualSpan = new Rgb[5]; - - // Act - var actual = Converter.ToRgb(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 0, 0, 0, 0, 0)] - [InlineData(0, 0.4225259, 0, 0.3, 0.6, 0.1067051)] - public void Convert_Rgb_to_CieXyy(float r, float g, float b, float x, float y, float yl) - { - // Arrange - var input = new Rgb(r, g, b); - var expected = new CieXyy(x, y, yl); - - Span inputSpan = new Rgb[5]; - inputSpan.Fill(input); - - Span actualSpan = new CieXyy[5]; - - // Act - CieXyy actual = Converter.ToCieXyy(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } -} diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndYCbCrConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndYCbCrConversionTests.cs deleted file mode 100644 index efacebcf19..0000000000 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndYCbCrConversionTests.cs +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion; - -namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion; - -/// -/// Tests - conversions. -/// -public class CieXyyAndYCbCrConversionTests -{ - private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0002F); - private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 0, 0, 0, 128, 128)] - [InlineData(0.360555, 0.936901, 0.1001514, 63.24579, 92.30826, 82.88884)] - public void Convert_CieXyy_to_YCbCr(float x, float y, float yl, float y2, float cb, float cr) - { - // Arrange - var input = new CieXyy(x, y, yl); - var expected = new YCbCr(y2, cb, cr); - - Span inputSpan = new CieXyy[5]; - inputSpan.Fill(input); - - Span actualSpan = new YCbCr[5]; - - // Act - var actual = Converter.ToYCbCr(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 128, 128, 0, 0, 0)] - [InlineData(63.24579, 92.30826, 82.88884, 0.3, 0.6, 0.1072441)] - public void Convert_YCbCr_to_CieXyy(float y2, float cb, float cr, float x, float y, float yl) - { - // Arrange - var input = new YCbCr(y2, cb, cr); - var expected = new CieXyy(x, y, yl); - - Span inputSpan = new YCbCr[5]; - inputSpan.Fill(input); - - Span actualSpan = new CieXyy[5]; - - // Act - CieXyy actual = Converter.ToCieXyy(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } -} diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndCieLchConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndCieLchConversionTests.cs deleted file mode 100644 index 698c9add60..0000000000 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndCieLchConversionTests.cs +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion; - -namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion; - -/// -/// Tests - conversions. -/// -public class CieXyzAndCieLchConversionTests -{ - private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0002F); - private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0.360555, 0.936901, 0.1001514, 97.50815, 155.8035, 139.323)] - public void Convert_CieXyz_to_CieLch(float x, float y, float yl, float l, float c, float h) - { - // Arrange - var input = new CieXyz(x, y, yl); - var expected = new CieLch(l, c, h); - - Span inputSpan = new CieXyz[5]; - inputSpan.Fill(input); - - Span actualSpan = new CieLch[5]; - - // Act - var actual = Converter.ToCieLch(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 0, 0, 0, 0, 0)] - [InlineData(97.50815, 155.8035, 139.323, 0.3605551, 0.936901, 0.1001514)] - public void Convert_CieLch_to_CieXyz(float l, float c, float h, float x, float y, float yl) - { - // Arrange - var input = new CieLch(l, c, h); - var expected = new CieXyz(x, y, yl); - - Span inputSpan = new CieLch[5]; - inputSpan.Fill(input); - - Span actualSpan = new CieXyz[5]; - - // Act - CieXyz actual = Converter.ToCieXyz(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } -} diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndCieLchuvConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndCieLchuvConversionTests.cs deleted file mode 100644 index a4caf4c857..0000000000 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndCieLchuvConversionTests.cs +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion; - -namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion; - -/// -/// Tests - conversions. -/// -public class CieXyzAndCieLchuvConversionTests -{ - private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0002F); - private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0.360555, 0.936901, 0.1001514, 97.50697, 183.3831, 133.6321)] - public void Convert_CieXyz_to_CieLchuv(float x, float y, float yl, float l, float c, float h) - { - // Arrange - var input = new CieXyz(x, y, yl); - var expected = new CieLchuv(l, c, h); - - Span inputSpan = new CieXyz[5]; - inputSpan.Fill(input); - - Span actualSpan = new CieLchuv[5]; - - // Act - var actual = Converter.ToCieLchuv(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 0, 0, 0, 0, 0)] - [InlineData(97.50697, 183.3831, 133.6321, 0.360555, 0.936901, 0.1001515)] - public void Convert_CieLchuv_to_CieXyz(float l, float c, float h, float x, float y, float yl) - { - // Arrange - var input = new CieLchuv(l, c, h); - var expected = new CieXyz(x, y, yl); - - Span inputSpan = new CieLchuv[5]; - inputSpan.Fill(input); - - Span actualSpan = new CieXyz[5]; - - // Act - CieXyz actual = Converter.ToCieXyz(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } -} diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndCieLuvConversionTest.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndCieLuvConversionTest.cs deleted file mode 100644 index 9e3381b40d..0000000000 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndCieLuvConversionTest.cs +++ /dev/null @@ -1,92 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion; - -namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion; - -/// -/// Tests - conversions. -/// -/// -/// Test data generated using: -/// -/// -public class CieXyzAndCieLuvConversionTest -{ - private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0001F); - - /// - /// Tests conversion from to (). - /// - [Theory] - [InlineData(0, 0, 0, 0, 0, 0)] - [InlineData(0, 100, 50, 0, 0, 0)] - [InlineData(0.1, 100, 50, 0.000493, 0.000111, 0)] - [InlineData(70.0000, 86.3525, 2.8240, 0.569310, 0.407494, 0.365843)] - [InlineData(10.0000, -1.2345, -10.0000, 0.012191, 0.011260, 0.025939)] - [InlineData(100, 0, 0, 0.950470, 1.000000, 1.088830)] - [InlineData(1, 1, 1, 0.001255, 0.001107, 0.000137)] - public void Convert_Luv_to_Xyz(float l, float u, float v, float x, float y, float z) - { - // Arrange - var input = new CieLuv(l, u, v, Illuminants.D65); - var options = new ColorSpaceConverterOptions { WhitePoint = Illuminants.D65, TargetLabWhitePoint = Illuminants.D65 }; - var converter = new ColorSpaceConverter(options); - var expected = new CieXyz(x, y, z); - - Span inputSpan = new CieLuv[5]; - inputSpan.Fill(input); - - Span actualSpan = new CieXyz[5]; - - // Act - var actual = converter.ToCieXyz(input); - converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } - - /// - /// Tests conversion from () to . - /// - [Theory] - [InlineData(0, 0, 0, 0, 0, 0)] - [InlineData(0.000493, 0.000111, 0, 0.1003, 0.9332, -0.0070)] - [InlineData(0.569310, 0.407494, 0.365843, 70.0000, 86.3524, 2.8240)] - [InlineData(0.012191, 0.011260, 0.025939, 9.9998, -1.2343, -9.9999)] - [InlineData(0.950470, 1.000000, 1.088830, 100, 0, 0)] - [InlineData(0.001255, 0.001107, 0.000137, 0.9999, 0.9998, 1.0004)] - public void Convert_Xyz_to_Luv(float x, float y, float z, float l, float u, float v) - { - // Arrange - var input = new CieXyz(x, y, z); - var options = new ColorSpaceConverterOptions { WhitePoint = Illuminants.D65, TargetLabWhitePoint = Illuminants.D65 }; - var converter = new ColorSpaceConverter(options); - var expected = new CieLuv(l, u, v); - - Span inputSpan = new CieXyz[5]; - inputSpan.Fill(input); - - Span actualSpan = new CieLuv[5]; - - // Act - var actual = converter.ToCieLuv(input); - converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } -} diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndHslConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndHslConversionTests.cs deleted file mode 100644 index 634d03a502..0000000000 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndHslConversionTests.cs +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion; - -namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion; - -/// -/// Tests - conversions. -/// -public class CieXyzAndHslConversionTests -{ - private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0002F); - private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 0, 0, 0, 0, 0)] - [InlineData(0.360555, 0.936901, 0.1001514, 120, 1, 0.5)] - public void Convert_CieXyz_to_Hsl(float x, float y, float yl, float h, float s, float l) - { - // Arrange - var input = new CieXyz(x, y, yl); - var expected = new Hsl(h, s, l); - - Span inputSpan = new CieXyz[5]; - inputSpan.Fill(input); - - Span actualSpan = new Hsl[5]; - - // Act - var actual = Converter.ToHsl(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 0, 0, 0, 0, 0)] - [InlineData(120, 1, 0.5, 0.3575761, 0.7151522, 0.119192)] - public void Convert_Hsl_to_CieXyz(float h, float s, float l, float x, float y, float yl) - { - // Arrange - var input = new Hsl(h, s, l); - var expected = new CieXyz(x, y, yl); - - Span inputSpan = new Hsl[5]; - inputSpan.Fill(input); - - Span actualSpan = new CieXyz[5]; - - // Act - var actual = Converter.ToCieXyz(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } -} diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndHsvConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndHsvConversionTests.cs deleted file mode 100644 index ccedd7b755..0000000000 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndHsvConversionTests.cs +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion; - -namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion; - -/// -/// Tests - conversions. -/// -public class CieXyzAndHsvConversionTests -{ - private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0002F); - private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 0, 0, 0, 0, 0)] - [InlineData(0.360555, 0.936901, 0.1001514, 120, 1, 0.9999999)] - public void Convert_CieXyz_to_Hsv(float x, float y, float yl, float h, float s, float v) - { - // Arrange - var input = new CieXyz(x, y, yl); - var expected = new Hsv(h, s, v); - - Span inputSpan = new CieXyz[5]; - inputSpan.Fill(input); - - Span actualSpan = new Hsv[5]; - - // Act - var actual = Converter.ToHsv(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 0, 0, 0, 0, 0)] - [InlineData(120, 1, 0.9999999, 0.3575761, 0.7151522, 0.119192)] - public void Convert_Hsv_to_CieXyz(float h, float s, float v, float x, float y, float yl) - { - // Arrange - var input = new Hsv(h, s, v); - var expected = new CieXyz(x, y, yl); - - Span inputSpan = new Hsv[5]; - inputSpan.Fill(input); - - Span actualSpan = new CieXyz[5]; - - // Act - CieXyz actual = Converter.ToCieXyz(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } -} diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndHunterLabConversionTest.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndHunterLabConversionTest.cs deleted file mode 100644 index af7087ba23..0000000000 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndHunterLabConversionTest.cs +++ /dev/null @@ -1,115 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion; - -namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion; - -/// -/// Tests - conversions. -/// -/// -/// Test data generated using: -/// -/// -public class CieXyzAndHunterLabConversionTest -{ - private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0001F); - - /// - /// Tests conversion from to (). - /// - [Theory] - [InlineData(0, 0, 0, 0, 0, 0)] - [InlineData(100, 0, 0, 0.98074, 1, 1.18232)] // C white point is HunterLab 100, 0, 0 - public void Convert_HunterLab_to_Xyz(float l, float a, float b, float x, float y, float z) - { - // Arrange - var input = new HunterLab(l, a, b); - var options = new ColorSpaceConverterOptions { WhitePoint = Illuminants.C }; - var converter = new ColorSpaceConverter(options); - var expected = new CieXyz(x, y, z); - - Span inputSpan = new HunterLab[5]; - inputSpan.Fill(input); - - Span actualSpan = new CieXyz[5]; - - // Act - var actual = converter.ToCieXyz(input); - converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } - - /// - /// Tests conversion from to (). - /// - [Theory] - [InlineData(0, 0, 0, 0, 0, 0)] - [InlineData(100, 0, 0, 0.95047, 1, 1.08883)] // D65 white point is HunerLab 100, 0, 0 (adaptation to C performed) - public void Convert_HunterLab_to_Xyz_D65(float l, float a, float b, float x, float y, float z) - { - // Arrange - var input = new HunterLab(l, a, b); - var options = new ColorSpaceConverterOptions { WhitePoint = Illuminants.D65 }; - var converter = new ColorSpaceConverter(options); - var expected = new CieXyz(x, y, z); - - Span inputSpan = new HunterLab[5]; - inputSpan.Fill(input); - - Span actualSpan = new CieXyz[5]; - - // Act - var actual = converter.ToCieXyz(input); - converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } - - /// - /// Tests conversion from () to . - /// - [Theory] - [InlineData(0, 0, 0, 0, 0, 0)] - [InlineData(0.95047, 1, 1.08883, 100, 0, 0)] // D65 white point is HunterLab 100, 0, 0 (adaptation to C performed) - public void Convert_Xyz_D65_to_HunterLab(float x, float y, float z, float l, float a, float b) - { - // Arrange - var input = new CieXyz(x, y, z); - var options = new ColorSpaceConverterOptions { WhitePoint = Illuminants.D65 }; - var converter = new ColorSpaceConverter(options); - var expected = new HunterLab(l, a, b); - - Span inputSpan = new CieXyz[5]; - inputSpan.Fill(input); - - Span actualSpan = new HunterLab[5]; - - // Act - var actual = converter.ToHunterLab(input); - converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } -} diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndYCbCrConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndYCbCrConversionTests.cs deleted file mode 100644 index ba67e605a6..0000000000 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndYCbCrConversionTests.cs +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion; - -namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion; - -/// -/// Tests - conversions. -/// -public class CieXyzAndYCbCrConversionTests -{ - private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0002F); - private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 0, 0, 0, 128, 128)] - [InlineData(0.360555, 0.936901, 0.1001514, 149.685, 43.52769, 21.23457)] - public void Convert_CieXyz_to_YCbCr(float x, float y, float z, float y2, float cb, float cr) - { - // Arrange - var input = new CieXyz(x, y, z); - var expected = new YCbCr(y2, cb, cr); - - Span inputSpan = new CieXyz[5]; - inputSpan.Fill(input); - - Span actualSpan = new YCbCr[5]; - - // Act - var actual = Converter.ToYCbCr(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 128, 128, 0, 0, 0)] - [InlineData(149.685, 43.52769, 21.23457, 0.3575761, 0.7151522, 0.119192)] - public void Convert_YCbCr_to_CieXyz(float y2, float cb, float cr, float x, float y, float z) - { - // Arrange - var input = new YCbCr(y2, cb, cr); - var expected = new CieXyz(x, y, z); - - Span inputSpan = new YCbCr[5]; - inputSpan.Fill(input); - - Span actualSpan = new CieXyz[5]; - - // Act - CieXyz actual = Converter.ToCieXyz(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } -} diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndCieLchConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndCieLchConversionTests.cs deleted file mode 100644 index 9def3e1b20..0000000000 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndCieLchConversionTests.cs +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion; - -namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion; - -/// -/// Tests - conversions. -/// -public class CmykAndCieLchConversionTests -{ - private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0002F); - private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0.360555, 0.1036901, 0.818514, 0.274615, 62.85025, 64.77041, 118.2425)] - public void Convert_Cmyk_to_CieLch(float c, float m, float y, float k, float l, float c2, float h) - { - // Arrange - var input = new Cmyk(c, m, y, k); - var expected = new CieLch(l, c2, h); - - Span inputSpan = new Cmyk[5]; - inputSpan.Fill(input); - - Span actualSpan = new CieLch[5]; - - // Act - var actual = Converter.ToCieLch(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(100, 3.81656E-05, 218.6598, 0, 1.192093E-07, 0, 5.960464E-08)] - [InlineData(62.85025, 64.77041, 118.2425, 0.286581, 0, 0.7975187, 0.34983)] - public void Convert_CieLch_to_Cmyk(float l, float c2, float h, float c, float m, float y, float k) - { - // Arrange - var input = new CieLch(l, c2, h); - var expected = new Cmyk(c, m, y, k); - - Span inputSpan = new CieLch[5]; - inputSpan.Fill(input); - - Span actualSpan = new Cmyk[5]; - - // Act - var actual = Converter.ToCmyk(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } -} diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndCieLuvConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndCieLuvConversionTests.cs deleted file mode 100644 index 9ae0fb7119..0000000000 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndCieLuvConversionTests.cs +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion; - -namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion; - -/// -/// Tests - conversions. -/// -public class CmykAndCieLuvConversionTests -{ - private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0002F); - private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 0, 0, 0, 100, -1.937151E-05, 0)] - [InlineData(0.360555, 0.1036901, 0.818514, 0.274615, 62.66017, -24.01712, 68.29556)] - public void Convert_Cmyk_to_CieLuv(float c, float m, float y, float k, float l, float u, float v) - { - // Arrange - var input = new Cmyk(c, m, y, k); - var expected = new CieLuv(l, u, v); - - Span inputSpan = new Cmyk[5]; - inputSpan.Fill(input); - - Span actualSpan = new CieLuv[5]; - - // Act - var actual = Converter.ToCieLuv(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(100, -1.937151E-05, 0, 3.576279E-07, 0, 0, 5.960464E-08)] - [InlineData(62.66017, -24.01712, 68.29556, 0.2865804, 0, 0.7975189, 0.3498302)] - public void Convert_CieLuv_to_Cmyk(float l, float u, float v, float c, float m, float y, float k) - { - // Arrange - var input = new CieLuv(l, u, v); - var expected = new Cmyk(c, m, y, k); - - Span inputSpan = new CieLuv[5]; - inputSpan.Fill(input); - - Span actualSpan = new Cmyk[5]; - - // Act - var actual = Converter.ToCmyk(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } -} diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndCieXyyConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndCieXyyConversionTests.cs deleted file mode 100644 index 270db9d205..0000000000 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndCieXyyConversionTests.cs +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion; - -namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion; - -/// -/// Tests - conversions. -/// -public class CmykAndCieXyyConversionTests -{ - private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0002F); - private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 0, 0, 0, 0.3127266, 0.3290231, 1)] - [InlineData(0.360555, 0.1036901, 0.818514, 0.274615, 0.3628971, 0.5289949, 0.3118104)] - public void Convert_Cmyk_to_CieXyy(float c, float m, float y, float k, float x, float y2, float yl) - { - // Arrange - var input = new Cmyk(c, m, y, k); - var expected = new CieXyy(x, y2, yl); - - Span inputSpan = new Cmyk[5]; - inputSpan.Fill(input); - - Span actualSpan = new CieXyy[5]; - - // Act - var actual = Converter.ToCieXyy(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0.3127266, 0.3290231, 1, 0, 0, 0, 5.960464E-08)] - [InlineData(0.3628971, 0.5289949, 0.3118104, 0.2865805, 0, 0.7975187, 0.3498302)] - public void Convert_CieXyy_to_Cmyk(float x, float y2, float yl, float c, float m, float y, float k) - { - // Arrange - var input = new CieXyy(x, y2, yl); - var expected = new Cmyk(c, m, y, k); - - Span inputSpan = new CieXyy[5]; - inputSpan.Fill(input); - - Span actualSpan = new Cmyk[5]; - - // Act - var actual = Converter.ToCmyk(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } -} diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndCieXyzConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndCieXyzConversionTests.cs deleted file mode 100644 index 972948c71d..0000000000 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndCieXyzConversionTests.cs +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion; - -namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion; - -/// -/// Tests - conversions. -/// -public class CmykAndCieXyzConversionTests -{ - private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0002F); - private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 0, 0, 0, 0.9504699, 1, 1.08883)] - [InlineData(0.360555, 0.1036901, 0.818514, 0.274615, 0.2139058, 0.3118104, 0.0637231)] - public void Convert_Cmyk_to_CieXyz(float c, float m, float y, float k, float x, float y2, float z) - { - // Arrange - var input = new Cmyk(c, m, y, k); - var expected = new CieXyz(x, y2, z); - - Span inputSpan = new Cmyk[5]; - inputSpan.Fill(input); - - Span actualSpan = new CieXyz[5]; - - // Act - var actual = Converter.ToCieXyz(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0.9504699, 1, 1.08883, 1.192093E-07, 0, 0, 5.960464E-08)] - [InlineData(0.2139058, 0.3118104, 0.0637231, 0.2865805, 0, 0.7975187, 0.3498302)] - public void Convert_CieXyz_to_Cmyk(float x, float y2, float z, float c, float m, float y, float k) - { - // Arrange - var input = new CieXyz(x, y2, z); - var expected = new Cmyk(c, m, y, k); - - Span inputSpan = new CieXyz[5]; - inputSpan.Fill(input); - - Span actualSpan = new Cmyk[5]; - - // Act - var actual = Converter.ToCmyk(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } -} diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndHslConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndHslConversionTests.cs deleted file mode 100644 index 2b00942aca..0000000000 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndHslConversionTests.cs +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion; - -namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion; - -/// -/// Tests - conversions. -/// -public class CmykAndHslConversionTests -{ - private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0002F); - private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 0, 0, 0, 0, 0, 1)] - [InlineData(0.360555, 0.1036901, 0.818514, 0.274615, 81.56041, 0.6632275, 0.3909085)] - public void Convert_Cmyk_to_Hsl(float c, float m, float y, float k, float h, float s, float l) - { - // Arrange - var input = new Cmyk(c, m, y, k); - var expected = new Hsl(h, s, l); - - Span inputSpan = new Cmyk[5]; - inputSpan.Fill(input); - - Span actualSpan = new Hsl[5]; - - // Act - var actual = ColorSpaceConverter.ToHsl(input); - ColorSpaceConverter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 0, 1, 0, 0, 0, 0)] - [InlineData(81.56041, 0.6632275, 0.3909085, 0.2865805, 0, 0.7975187, 0.3498302)] - public void Convert_Hsl_to_Cmyk(float h, float s, float l, float c, float m, float y, float k) - { - // Arrange - var input = new Hsl(h, s, l); - var expected = new Cmyk(c, m, y, k); - - Span inputSpan = new Hsl[5]; - inputSpan.Fill(input); - - Span actualSpan = new Cmyk[5]; - - // Act - var actual = ColorSpaceConverter.ToCmyk(input); - ColorSpaceConverter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } -} diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndHsvConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndHsvConversionTests.cs deleted file mode 100644 index f158fb5f9e..0000000000 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndHsvConversionTests.cs +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion; - -namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion; - -/// -/// Tests - conversions. -/// -public class CmykAndHsvConversionTests -{ - private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0002F); - private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 0, 0, 0, 0, 0, 1)] - [InlineData(0.360555, 0.1036901, 0.818514, 0.274615, 81.56041, 0.7975187, 0.6501698)] - public void Convert_Cmyk_to_Hsv(float c, float m, float y, float k, float h, float s, float v) - { - // Arrange - var input = new Cmyk(c, m, y, k); - var expected = new Hsv(h, s, v); - - Span inputSpan = new Cmyk[5]; - inputSpan.Fill(input); - - Span actualSpan = new Hsv[5]; - - // Act - var actual = ColorSpaceConverter.ToHsv(input); - ColorSpaceConverter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 0, 1, 0, 0, 0, 0)] - [InlineData(81.56041, 0.7975187, 0.6501698, 0.2865805, 0, 0.7975187, 0.3498302)] - public void Convert_Hsv_to_Cmyk(float h, float s, float v, float c, float m, float y, float k) - { - // Arrange - var input = new Hsv(h, s, v); - var expected = new Cmyk(c, m, y, k); - - Span inputSpan = new Hsv[5]; - inputSpan.Fill(input); - - Span actualSpan = new Cmyk[5]; - - // Act - var actual = ColorSpaceConverter.ToCmyk(input); - ColorSpaceConverter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } -} diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndHunterLabConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndHunterLabConversionTests.cs deleted file mode 100644 index 9832a0d715..0000000000 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndHunterLabConversionTests.cs +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion; - -namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion; - -/// -/// Tests - conversions. -/// -public class CmykAndHunterLabConversionTests -{ - private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0002F); - private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 0, 0, 0, 99.99999, 0, -1.66893E-05)] - [InlineData(0.360555, 0.1036901, 0.818514, 0.274615, 55.66742, -27.21679, 31.73834)] - public void Convert_Cmyk_to_HunterLab(float c, float m, float y, float k, float l, float a, float b) - { - // Arrange - var input = new Cmyk(c, m, y, k); - var expected = new HunterLab(l, a, b); - - Span inputSpan = new Cmyk[5]; - inputSpan.Fill(input); - - Span actualSpan = new HunterLab[5]; - - // Act - var actual = Converter.ToHunterLab(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(99.99999, 0, -1.66893E-05, 1.192093E-07, 1.192093E-07, 0, 5.960464E-08)] - [InlineData(55.66742, -27.21679, 31.73834, 0.2865806, 0, 0.7975186, 0.3498301)] - public void Convert_HunterLab_to_Cmyk(float l, float a, float b, float c, float m, float y, float k) - { - // Arrange - var input = new HunterLab(l, a, b); - var expected = new Cmyk(c, m, y, k); - - Span inputSpan = new HunterLab[5]; - inputSpan.Fill(input); - - Span actualSpan = new Cmyk[5]; - - // Act - var actual = Converter.ToCmyk(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } -} diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndYCbCrConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndYCbCrConversionTests.cs deleted file mode 100644 index 1e8bc52e2f..0000000000 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndYCbCrConversionTests.cs +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion; - -namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion; - -/// -/// Tests - conversions. -/// -public class CmykAndYCbCrConversionTests -{ - private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0002F); - private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 0, 0, 0, 255, 128, 128)] - [InlineData(0.360555, 0.1036901, 0.818514, 0.274615, 136.5134, 69.90555, 114.9948)] - public void Convert_Cmyk_to_YCbCr(float c, float m, float y, float k, float y2, float cb, float cr) - { - // Arrange - var input = new Cmyk(c, m, y, k); - var expected = new YCbCr(y2, cb, cr); - - Span inputSpan = new Cmyk[5]; - inputSpan.Fill(input); - - Span actualSpan = new YCbCr[5]; - - // Act - var actual = ColorSpaceConverter.ToYCbCr(input); - ColorSpaceConverter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(255, 128, 128, 0, 0, 0, 5.960464E-08)] - [InlineData(136.5134, 69.90555, 114.9948, 0.2891567, 0, 0.7951807, 0.3490196)] - public void Convert_YCbCr_to_Cmyk(float y2, float cb, float cr, float c, float m, float y, float k) - { - // Arrange - var input = new YCbCr(y2, cb, cr); - var expected = new Cmyk(c, m, y, k); - - Span inputSpan = new YCbCr[5]; - inputSpan.Fill(input); - - Span actualSpan = new Cmyk[5]; - - // Act - var actual = Converter.ToCmyk(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } -} diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/ColorConverterAdaptTest.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/ColorConverterAdaptTest.cs deleted file mode 100644 index bbebf96b32..0000000000 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/ColorConverterAdaptTest.cs +++ /dev/null @@ -1,178 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion; - -namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion; - -/// -/// Tests methods. -/// Test data generated using: -/// -/// -/// -public class ColorConverterAdaptTest -{ - private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0001F); - - [Theory] - [InlineData(0, 0, 0, 0, 0, 0)] - [InlineData(1, 1, 1, 1, 1, 1)] - [InlineData(0.206162, 0.260277, 0.746717, 0.220000, 0.130000, 0.780000)] - public void Adapt_RGB_WideGamutRGB_To_sRGB(float r1, float g1, float b1, float r2, float g2, float b2) - { - // Arrange - var input = new Rgb(r1, g1, b1, RgbWorkingSpaces.WideGamutRgb); - var expected = new Rgb(r2, g2, b2, RgbWorkingSpaces.SRgb); - var options = new ColorSpaceConverterOptions { TargetRgbWorkingSpace = RgbWorkingSpaces.SRgb }; - var converter = new ColorSpaceConverter(options); - - // Action - Rgb actual = converter.Adapt(input); - - // Assert - Assert.Equal(expected.WorkingSpace, actual.WorkingSpace, ColorSpaceComparer); - Assert.Equal(expected, actual, ColorSpaceComparer); - } - - [Theory] - [InlineData(0, 0, 0, 0, 0, 0)] - [InlineData(1, 1, 1, 1, 1, 1)] - [InlineData(0.220000, 0.130000, 0.780000, 0.206162, 0.260277, 0.746717)] - public void Adapt_RGB_SRGB_To_WideGamutRGB(float r1, float g1, float b1, float r2, float g2, float b2) - { - // Arrange - var input = new Rgb(r1, g1, b1, RgbWorkingSpaces.SRgb); - var expected = new Rgb(r2, g2, b2, RgbWorkingSpaces.WideGamutRgb); - var options = new ColorSpaceConverterOptions { TargetRgbWorkingSpace = RgbWorkingSpaces.WideGamutRgb }; - var converter = new ColorSpaceConverter(options); - - // Action - Rgb actual = converter.Adapt(input); - - // Assert - Assert.Equal(expected.WorkingSpace, actual.WorkingSpace, ColorSpaceComparer); - Assert.Equal(expected, actual, ColorSpaceComparer); - } - - [Theory] - [InlineData(0, 0, 0, 0, 0, 0)] - [InlineData(22, 33, 1, 22.269869, 32.841164, 1.633926)] - public void Adapt_Lab_D65_To_D50(float l1, float a1, float b1, float l2, float a2, float b2) - { - // Arrange - var input = new CieLab(l1, a1, b1, Illuminants.D65); - var expected = new CieLab(l2, a2, b2); - var options = new ColorSpaceConverterOptions { TargetLabWhitePoint = Illuminants.D50 }; - var converter = new ColorSpaceConverter(options); - - // Action - CieLab actual = converter.Adapt(input); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - } - - [Theory] - [InlineData(0, 0, 0, 0, 0, 0)] - [InlineData(0.5, 0.5, 0.5, 0.510286, 0.501489, 0.378970)] - public void Adapt_Xyz_D65_To_D50_Bradford(float x1, float y1, float z1, float x2, float y2, float z2) - { - // Arrange - var input = new CieXyz(x1, y1, z1); - var expected = new CieXyz(x2, y2, z2); - var options = new ColorSpaceConverterOptions { WhitePoint = Illuminants.D50 }; - var converter = new ColorSpaceConverter(options); - - // Action - CieXyz actual = converter.Adapt(input, Illuminants.D65); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - } - - [Theory] - [InlineData(0, 0, 0, 0, 0, 0)] - [InlineData(0.5, 0.5, 0.5, 0.507233, 0.500000, 0.378943)] - public void Adapt_Xyz_D65_To_D50_XyzScaling(float x1, float y1, float z1, float x2, float y2, float z2) - { - // Arrange - var input = new CieXyz(x1, y1, z1); - var expected = new CieXyz(x2, y2, z2); - var options = new ColorSpaceConverterOptions - { - ChromaticAdaptation = new VonKriesChromaticAdaptation(LmsAdaptationMatrix.XyzScaling), - WhitePoint = Illuminants.D50 - }; - - var converter = new ColorSpaceConverter(options); - - // Action - CieXyz actual = converter.Adapt(input, Illuminants.D65); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - } - - [Theory] - [InlineData(0, 0, 0, 0, 0, 0)] - [InlineData(22, 33, 1, 22.1090755, 32.2102661, 1.153463)] - public void Adapt_HunterLab_D65_To_D50(float l1, float a1, float b1, float l2, float a2, float b2) - { - // Arrange - var input = new HunterLab(l1, a1, b1, Illuminants.D65); - var expected = new HunterLab(l2, a2, b2); - var options = new ColorSpaceConverterOptions { TargetLabWhitePoint = Illuminants.D50 }; - var converter = new ColorSpaceConverter(options); - - // Action - HunterLab actual = converter.Adapt(input); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - } - - [Theory] - [InlineData(0, 0, 0, 0, 0, 0)] - [InlineData(22, 33, 1, 22, 33, 0.9999999)] - public void Adapt_CieLchuv_D65_To_D50_XyzScaling(float l1, float c1, float h1, float l2, float c2, float h2) - { - // Arrange - var input = new CieLchuv(l1, c1, h1, Illuminants.D65); - var expected = new CieLchuv(l2, c2, h2); - var options = new ColorSpaceConverterOptions - { - ChromaticAdaptation = new VonKriesChromaticAdaptation(LmsAdaptationMatrix.XyzScaling), - TargetLabWhitePoint = Illuminants.D50 - }; - var converter = new ColorSpaceConverter(options); - - // Action - CieLchuv actual = converter.Adapt(input); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - } - - [Theory] - [InlineData(22, 33, 1, 22, 33, 0.9999999)] - public void Adapt_CieLch_D65_To_D50_XyzScaling(float l1, float c1, float h1, float l2, float c2, float h2) - { - // Arrange - var input = new CieLch(l1, c1, h1, Illuminants.D65); - var expected = new CieLch(l2, c2, h2); - var options = new ColorSpaceConverterOptions - { - ChromaticAdaptation = new VonKriesChromaticAdaptation(LmsAdaptationMatrix.XyzScaling), - TargetLabWhitePoint = Illuminants.D50 - }; - var converter = new ColorSpaceConverter(options); - - // Action - CieLch actual = converter.Adapt(input); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - } -} diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/RgbAndCieXyzConversionTest.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/RgbAndCieXyzConversionTest.cs deleted file mode 100644 index 0119f4f3a4..0000000000 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/RgbAndCieXyzConversionTest.cs +++ /dev/null @@ -1,170 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion; - -namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion; - -/// -/// Tests - conversions. -/// -/// -/// Test data generated using: -/// -/// -public class RgbAndCieXyzConversionTest -{ - private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0001F); - - /// - /// Tests conversion from () - /// to (default sRGB working space). - /// - [Theory] - [InlineData(0.96422, 1.00000, 0.82521, 1, 1, 1)] - [InlineData(0.00000, 1.00000, 0.00000, 0, 1, 0)] - [InlineData(0.96422, 0.00000, 0.00000, 1, 0, 0.292064)] - [InlineData(0.00000, 0.00000, 0.82521, 0, 0.181415, 1)] - [InlineData(0, 0, 0, 0, 0, 0)] - [InlineData(0.297676, 0.267854, 0.045504, 0.720315, 0.509999, 0.168112)] - public void Convert_XYZ_D50_to_SRGB(float x, float y, float z, float r, float g, float b) - { - // Arrange - var input = new CieXyz(x, y, z); - var options = new ColorSpaceConverterOptions { WhitePoint = Illuminants.D50, TargetRgbWorkingSpace = RgbWorkingSpaces.SRgb }; - var converter = new ColorSpaceConverter(options); - var expected = new Rgb(r, g, b); - - Span inputSpan = new CieXyz[5]; - inputSpan.Fill(input); - - Span actualSpan = new Rgb[5]; - - // Act - var actual = converter.ToRgb(input); - converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(Rgb.DefaultWorkingSpace, actual.WorkingSpace, ColorSpaceComparer); - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } - - /// - /// Tests conversion - /// from () - /// to (default sRGB working space). - /// - [Theory] - [InlineData(0.950470, 1.000000, 1.088830, 1, 1, 1)] - [InlineData(0, 1.000000, 0, 0, 1, 0)] - [InlineData(0.950470, 0, 0, 1, 0, 0.254967)] - [InlineData(0, 0, 1.088830, 0, 0.235458, 1)] - [InlineData(0, 0, 0, 0, 0, 0)] - [InlineData(0.297676, 0.267854, 0.045504, 0.754903, 0.501961, 0.099998)] - public void Convert_XYZ_D65_to_SRGB(float x, float y, float z, float r, float g, float b) - { - // Arrange - var input = new CieXyz(x, y, z); - var options = new ColorSpaceConverterOptions { WhitePoint = Illuminants.D65, TargetRgbWorkingSpace = RgbWorkingSpaces.SRgb }; - var converter = new ColorSpaceConverter(options); - var expected = new Rgb(r, g, b); - - Span inputSpan = new CieXyz[5]; - inputSpan.Fill(input); - - Span actualSpan = new Rgb[5]; - - // Act - var actual = converter.ToRgb(input); - converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(Rgb.DefaultWorkingSpace, actual.WorkingSpace, ColorSpaceComparer); - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } - - /// - /// Tests conversion from (default sRGB working space) - /// to (). - /// - [Theory] - [InlineData(1, 1, 1, 0.964220, 1.000000, 0.825210)] - [InlineData(0, 0, 0, 0, 0, 0)] - [InlineData(1, 0, 0, 0.436075, 0.222504, 0.013932)] - [InlineData(0, 1, 0, 0.385065, 0.716879, 0.0971045)] - [InlineData(0, 0, 1, 0.143080, 0.060617, 0.714173)] - [InlineData(0.754902, 0.501961, 0.100000, 0.315757, 0.273323, 0.035506)] - public void Convert_SRGB_to_XYZ_D50(float r, float g, float b, float x, float y, float z) - { - // Arrange - var input = new Rgb(r, g, b); - var options = new ColorSpaceConverterOptions { WhitePoint = Illuminants.D50 }; - var converter = new ColorSpaceConverter(options); - var expected = new CieXyz(x, y, z); - - Span inputSpan = new Rgb[5]; - inputSpan.Fill(input); - - Span actualSpan = new CieXyz[5]; - - // Act - var actual = converter.ToCieXyz(input); - converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } - - /// - /// Tests conversion from (default sRGB working space) - /// to (). - /// - [Theory] - [InlineData(1, 1, 1, 0.950470, 1.000000, 1.088830)] - [InlineData(0, 0, 0, 0, 0, 0)] - [InlineData(1, 0, 0, 0.412456, 0.212673, 0.019334)] - [InlineData(0, 1, 0, 0.357576, 0.715152, 0.119192)] - [InlineData(0, 0, 1, 0.1804375, 0.072175, 0.950304)] - [InlineData(0.754902, 0.501961, 0.100000, 0.297676, 0.267854, 0.045504)] - public void Convert_SRGB_to_XYZ_D65(float r, float g, float b, float x, float y, float z) - { - // Arrange - var input = new Rgb(r, g, b); - var options = new ColorSpaceConverterOptions { WhitePoint = Illuminants.D65 }; - var converter = new ColorSpaceConverter(options); - var expected = new CieXyz(x, y, z); - - Span inputSpan = new Rgb[5]; - inputSpan.Fill(input); - - Span actualSpan = new CieXyz[5]; - - // Act - var actual = converter.ToCieXyz(input); - converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } -} diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/RgbAndYCbCrConversionTest.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/RgbAndYCbCrConversionTest.cs deleted file mode 100644 index eb4eb0bbff..0000000000 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/RgbAndYCbCrConversionTest.cs +++ /dev/null @@ -1,83 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion; - -namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion; - -/// -/// Tests - conversions. -/// -/// -/// Test data generated mathematically -/// -public class RgbAndYCbCrConversionTest -{ - private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); - private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.001F); - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(255, 128, 128, 1, 1, 1)] - [InlineData(0, 128, 128, 0, 0, 0)] - [InlineData(128, 128, 128, 0.502, 0.502, 0.502)] - public void Convert_YCbCr_To_Rgb(float y, float cb, float cr, float r, float g, float b) - { - // Arrange - var input = new YCbCr(y, cb, cr); - var expected = new Rgb(r, g, b); - - Span inputSpan = new YCbCr[5]; - inputSpan.Fill(input); - - Span actualSpan = new Rgb[5]; - - // Act - var actual = Converter.ToRgb(input); - Converter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(Rgb.DefaultWorkingSpace, actual.WorkingSpace, ColorSpaceComparer); - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } - - /// - /// Tests conversion from to . - /// - [Theory] - [InlineData(0, 0, 0, 0, 128, 128)] - [InlineData(1, 1, 1, 255, 128, 128)] - [InlineData(0.5, 0.5, 0.5, 127.5, 128, 128)] - [InlineData(1, 0, 0, 76.245, 84.972, 255)] - public void Convert_Rgb_To_YCbCr(float r, float g, float b, float y, float cb, float cr) - { - // Arrange - var input = new Rgb(r, g, b); - var expected = new YCbCr(y, cb, cr); - - Span inputSpan = new Rgb[5]; - inputSpan.Fill(input); - - Span actualSpan = new YCbCr[5]; - - // Act - var actual = ColorSpaceConverter.ToYCbCr(input); - ColorSpaceConverter.Convert(inputSpan, actualSpan); - - // Assert - Assert.Equal(expected, actual, ColorSpaceComparer); - - for (int i = 0; i < actualSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } -} diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/VonKriesChromaticAdaptationTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/VonKriesChromaticAdaptationTests.cs deleted file mode 100644 index 9e33ad1689..0000000000 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/VonKriesChromaticAdaptationTests.cs +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion; - -namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion; - -public class VonKriesChromaticAdaptationTests -{ - private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0001F); - public static readonly TheoryData WhitePoints = new TheoryData - { - { CieLuv.DefaultWhitePoint, CieLab.DefaultWhitePoint }, - { CieLuv.DefaultWhitePoint, CieLuv.DefaultWhitePoint } - }; - - [Theory] - [MemberData(nameof(WhitePoints))] - public void SingleAndBulkTransformYieldIdenticalResults(CieXyz sourceWhitePoint, CieXyz destinationWhitePoint) - { - var adaptation = new VonKriesChromaticAdaptation(); - var input = new CieXyz(1, 0, 1); - CieXyz expected = adaptation.Transform(input, sourceWhitePoint, destinationWhitePoint); - - Span inputSpan = new CieXyz[5]; - inputSpan.Fill(input); - - Span actualSpan = new CieXyz[5]; - - adaptation.Transform(inputSpan, actualSpan, sourceWhitePoint, destinationWhitePoint); - - for (int i = 0; i < inputSpan.Length; i++) - { - Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); - } - } -} diff --git a/tests/ImageSharp.Tests/Colorspaces/LinearRgbTests.cs b/tests/ImageSharp.Tests/Colorspaces/LinearRgbTests.cs deleted file mode 100644 index ff2d151344..0000000000 --- a/tests/ImageSharp.Tests/Colorspaces/LinearRgbTests.cs +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using System.Numerics; -using SixLabors.ImageSharp.ColorSpaces; - -namespace SixLabors.ImageSharp.Tests.Colorspaces; - -/// -/// Tests the struct. -/// -public class LinearRgbTests -{ - [Fact] - public void LinearRgbConstructorAssignsFields() - { - const float r = .75F; - const float g = .64F; - const float b = .87F; - var rgb = new LinearRgb(r, g, b); - - Assert.Equal(r, rgb.R); - Assert.Equal(g, rgb.G); - Assert.Equal(b, rgb.B); - } - - [Fact] - public void LinearRgbEquality() - { - var x = default(LinearRgb); - var y = new LinearRgb(Vector3.One); - - Assert.True(default(LinearRgb) == default(LinearRgb)); - Assert.False(default(LinearRgb) != default(LinearRgb)); - Assert.Equal(default(LinearRgb), default(LinearRgb)); - Assert.Equal(new LinearRgb(1, 0, 1), new LinearRgb(1, 0, 1)); - Assert.Equal(new LinearRgb(Vector3.One), new LinearRgb(Vector3.One)); - Assert.False(x.Equals(y)); - Assert.False(x.Equals((object)y)); - Assert.False(x.GetHashCode().Equals(y.GetHashCode())); - } -} diff --git a/tests/ImageSharp.Tests/Formats/Gif/GifDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Gif/GifDecoderTests.cs index ee108b9d96..f4e6487a57 100644 --- a/tests/ImageSharp.Tests/Formats/Gif/GifDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Gif/GifDecoderTests.cs @@ -204,6 +204,17 @@ public class GifDecoderTests image.CompareToReferenceOutputMultiFrame(provider, ImageComparer.Exact); } + // https://github.com/SixLabors/ImageSharp/issues/2758 + [Theory] + [WithFile(TestImages.Gif.Issues.Issue2758, PixelTypes.Rgba32)] + public void Issue2758_BadDescriptorDimensions(TestImageProvider provider) + where TPixel : unmanaged, IPixel + { + using Image image = provider.GetImage(); + image.DebugSaveMultiFrame(provider); + image.CompareToReferenceOutputMultiFrame(provider, ImageComparer.Exact); + } + // https://github.com/SixLabors/ImageSharp/issues/405 [Theory] [WithFile(TestImages.Gif.Issues.BadAppExtLength, PixelTypes.Rgba32)] diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs index ef9f48a890..7aabdaa588 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs @@ -3,11 +3,10 @@ using System.Runtime.Intrinsics.Arm; using System.Runtime.Intrinsics.X86; -using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion; +using SixLabors.ImageSharp.ColorProfiles; using SixLabors.ImageSharp.Formats.Jpeg.Components; using SixLabors.ImageSharp.Memory; -using SixLabors.ImageSharp.Tests.Colorspaces.Conversion; +using SixLabors.ImageSharp.Tests.ColorProfiles; using SixLabors.ImageSharp.Tests.TestUtilities; using Xunit.Abstractions; @@ -24,9 +23,9 @@ public class JpegColorConverterTests private const HwIntrinsics IntrinsicsConfig = HwIntrinsics.AllowAll | HwIntrinsics.DisableAVX2; - private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new(epsilon: Precision); + private static readonly ApproximateColorProfileComparer ColorSpaceComparer = new(epsilon: Precision); - private static readonly ColorSpaceConverter ColorSpaceConverter = new(); + private static readonly ColorProfileConverter ColorSpaceConverter = new(); public static readonly TheoryData Seeds = new() { 1, 2, 3 }; @@ -38,7 +37,7 @@ public class JpegColorConverterTests [Fact] public void GetConverterThrowsExceptionOnInvalidColorSpace() { - JpegColorSpace invalidColorSpace = (JpegColorSpace)(-1); + const JpegColorSpace invalidColorSpace = (JpegColorSpace)(-1); Assert.Throws(() => JpegColorConverterBase.GetConverter(invalidColorSpace, 8)); } @@ -46,7 +45,7 @@ public class JpegColorConverterTests public void GetConverterThrowsExceptionOnInvalidPrecision() { // Valid precisions: 8 & 12 bit - int invalidPrecision = 9; + const int invalidPrecision = 9; Assert.Throws(() => JpegColorConverterBase.GetConverter(JpegColorSpace.YCbCr, invalidPrecision)); } @@ -428,7 +427,8 @@ public class JpegColorConverterTests [Theory] [MemberData(nameof(Seeds))] public void FromYCbCrArm(int seed) => - this.TestConversionToRgb(new JpegColorConverterBase.YCbCrArm(8), + this.TestConversionToRgb( + new JpegColorConverterBase.YCbCrArm(8), 3, seed, new JpegColorConverterBase.YCbCrScalar(8)); @@ -436,7 +436,8 @@ public class JpegColorConverterTests [Theory] [MemberData(nameof(Seeds))] public void FromRgbToYCbCrArm(int seed) => - this.TestConversionFromRgb(new JpegColorConverterBase.YCbCrArm(8), + this.TestConversionFromRgb( + new JpegColorConverterBase.YCbCrArm(8), 3, seed, new JpegColorConverterBase.YCbCrScalar(8), @@ -502,7 +503,8 @@ public class JpegColorConverterTests [Theory] [MemberData(nameof(Seeds))] public void FromGrayscaleArm(int seed) => - this.TestConversionToRgb(new JpegColorConverterBase.GrayscaleArm(8), + this.TestConversionToRgb( + new JpegColorConverterBase.GrayscaleArm(8), 1, seed, new JpegColorConverterBase.GrayscaleScalar(8)); @@ -510,7 +512,8 @@ public class JpegColorConverterTests [Theory] [MemberData(nameof(Seeds))] public void FromRgbToGrayscaleArm(int seed) => - this.TestConversionFromRgb(new JpegColorConverterBase.GrayscaleArm(8), + this.TestConversionFromRgb( + new JpegColorConverterBase.GrayscaleArm(8), 1, seed, new JpegColorConverterBase.GrayscaleScalar(8), @@ -556,7 +559,8 @@ public class JpegColorConverterTests [Theory] [MemberData(nameof(Seeds))] public void FromYccKArm64(int seed) => - this.TestConversionToRgb(new JpegColorConverterBase.YccKArm64(8), + this.TestConversionToRgb( + new JpegColorConverterBase.YccKArm64(8), 4, seed, new JpegColorConverterBase.YccKScalar(8)); @@ -564,7 +568,8 @@ public class JpegColorConverterTests [Theory] [MemberData(nameof(Seeds))] public void FromRgbToYccKArm64(int seed) => - this.TestConversionFromRgb(new JpegColorConverterBase.YccKArm64(8), + this.TestConversionFromRgb( + new JpegColorConverterBase.YccKArm64(8), 4, seed, new JpegColorConverterBase.YccKScalar(8), @@ -617,9 +622,9 @@ public class JpegColorConverterTests int componentCount, int seed) { - var rnd = new Random(seed); + Random rnd = new(seed); - var buffers = new Buffer2D[componentCount]; + Buffer2D[] buffers = new Buffer2D[componentCount]; for (int i = 0; i < componentCount; i++) { float[] values = new float[length]; @@ -630,8 +635,8 @@ public class JpegColorConverterTests } // no need to dispose when buffer is not array owner - var memory = new Memory(values); - var source = MemoryGroup.Wrap(memory); + Memory memory = new(values); + MemoryGroup source = MemoryGroup.Wrap(memory); buffers[i] = new Buffer2D(source, values.Length, 1); } @@ -786,9 +791,9 @@ public class JpegColorConverterTests float y = values.Component0[i]; float cb = values.Component1[i]; float cr = values.Component2[i]; - Rgb expected = ColorSpaceConverter.ToRgb(new YCbCr(y, cb, cr)); + Rgb expected = ColorSpaceConverter.Convert(new YCbCr(y, cb, cr)); - Rgb actual = new(result.Component0[i], result.Component1[i], result.Component2[i]); + Rgb actual = Rgb.Clamp(new(result.Component0[i], result.Component1[i], result.Component2[i])); bool equal = ColorSpaceComparer.Equals(expected, actual); Assert.True(equal, $"Colors {expected} and {actual} are not equal at index {i}"); @@ -810,9 +815,9 @@ public class JpegColorConverterTests r /= MaxColorChannelValue; g /= MaxColorChannelValue; b /= MaxColorChannelValue; - var expected = new Rgb(r, g, b); + Rgb expected = Rgb.Clamp(new(r, g, b)); - var actual = new Rgb(result.Component0[i], result.Component1[i], result.Component2[i]); + Rgb actual = Rgb.Clamp(new(result.Component0[i], result.Component1[i], result.Component2[i])); bool equal = ColorSpaceComparer.Equals(expected, actual); Assert.True(equal, $"Colors {expected} and {actual} are not equal at index {i}"); @@ -823,9 +828,9 @@ public class JpegColorConverterTests float r = values.Component0[i] / MaxColorChannelValue; float g = values.Component1[i] / MaxColorChannelValue; float b = values.Component2[i] / MaxColorChannelValue; - var expected = new Rgb(r, g, b); + Rgb expected = Rgb.Clamp(new(r, g, b)); - var actual = new Rgb(result.Component0[i], result.Component1[i], result.Component2[i]); + Rgb actual = Rgb.Clamp(new(result.Component0[i], result.Component1[i], result.Component2[i])); bool equal = ColorSpaceComparer.Equals(expected, actual); Assert.True(equal, $"Colors {expected} and {actual} are not equal at index {i}"); @@ -834,9 +839,9 @@ public class JpegColorConverterTests private static void ValidateGrayScale(in JpegColorConverterBase.ComponentValues values, in JpegColorConverterBase.ComponentValues result, int i) { float y = values.Component0[i] / MaxColorChannelValue; - var expected = new Rgb(y, y, y); + Rgb expected = Rgb.Clamp(new(y, y, y)); - var actual = new Rgb(result.Component0[i], result.Component0[i], result.Component0[i]); + Rgb actual = Rgb.Clamp(new(result.Component0[i], result.Component0[i], result.Component0[i])); bool equal = ColorSpaceComparer.Equals(expected, actual); Assert.True(equal, $"Colors {expected} and {actual} are not equal at index {i}"); @@ -852,9 +857,9 @@ public class JpegColorConverterTests float r = c * k / MaxColorChannelValue; float g = m * k / MaxColorChannelValue; float b = y * k / MaxColorChannelValue; - var expected = new Rgb(r, g, b); + Rgb expected = Rgb.Clamp(new(r, g, b)); - var actual = new Rgb(result.Component0[i], result.Component1[i], result.Component2[i]); + Rgb actual = Rgb.Clamp(new(result.Component0[i], result.Component1[i], result.Component2[i])); bool equal = ColorSpaceComparer.Equals(expected, actual); Assert.True(equal, $"Colors {expected} and {actual} are not equal at index {i}"); diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Metadata.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Metadata.cs index cbb2befcd4..3c88d8cbe9 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Metadata.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Metadata.cs @@ -8,6 +8,7 @@ using SixLabors.ImageSharp.Metadata; using SixLabors.ImageSharp.Metadata.Profiles.Exif; using SixLabors.ImageSharp.Metadata.Profiles.Icc; using SixLabors.ImageSharp.PixelFormats; +using SixLabors.ImageSharp.Processing; using SixLabors.ImageSharp.Tests.TestUtilities; // ReSharper disable InconsistentNaming @@ -438,6 +439,33 @@ public partial class JpegDecoderTests Assert.Equal(expectedComment, metadata.Comments.ElementAtOrDefault(0).ToString()); image.DebugSave(provider); image.CompareToOriginal(provider); + + } + + // https://github.com/SixLabors/ImageSharp/issues/2758 + [Theory] + [WithFile(TestImages.Jpeg.Issues.Issue2758, PixelTypes.L8)] + public void Issue2758_DecodeWorks(TestImageProvider provider) + where TPixel : unmanaged, IPixel + { + using Image image = provider.GetImage(JpegDecoder.Instance); + + Assert.Equal(59787, image.Width); + Assert.Equal(511, image.Height); + + JpegMetadata meta = image.Metadata.GetJpegMetadata(); + + // Quality determination should be between 1-100. + Assert.Equal(15, meta.LuminanceQuality); + Assert.Equal(1, meta.ChrominanceQuality); + + // We want to test the encoder to ensure the determined values can be encoded but not by encoding + // the full size image as it would be too slow. + // We will crop the image to a smaller size and then encode it. + image.Mutate(x => x.Crop(new(0, 0, 100, 100))); + + using MemoryStream ms = new(); + image.Save(ms, new JpegEncoder()); } private static void VerifyEncodedStrings(ExifProfile exif) diff --git a/tests/ImageSharp.Tests/ImageSharp.Tests.csproj b/tests/ImageSharp.Tests/ImageSharp.Tests.csproj index a389c8ab8c..41e6e525f8 100644 --- a/tests/ImageSharp.Tests/ImageSharp.Tests.csproj +++ b/tests/ImageSharp.Tests/ImageSharp.Tests.csproj @@ -39,7 +39,7 @@ Do not update or consolidate BenchmarkDotNet. https://github.com/dotnet/arcade/issues/8483 --> - + diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.cs b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.cs index 68c282d8a1..32b62fc03d 100644 --- a/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.cs @@ -5,7 +5,7 @@ using System.Buffers; using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -using SixLabors.ImageSharp.ColorSpaces.Companding; +using SixLabors.ImageSharp.ColorProfiles.Companding; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Tests.Common; @@ -161,12 +161,12 @@ public abstract class PixelOperationsTests : MeasureFixture [MemberData(nameof(ArraySizesData))] public void FromCompandedScaledVector4(int count) { - void SourceAction(ref Vector4 v) => SRgbCompanding.Expand(ref v); + void SourceAction(ref Vector4 v) => v = SRgbCompanding.Expand(v); - void ExpectedAction(ref Vector4 v) => SRgbCompanding.Compress(ref v); + void ExpectedAction(ref Vector4 v) => v = SRgbCompanding.Compress(v); - Vector4[] source = CreateVector4TestData(count, (ref Vector4 v) => SourceAction(ref v)); - TPixel[] expected = CreateScaledExpectedPixelData(source, (ref Vector4 v) => ExpectedAction(ref v)); + Vector4[] source = CreateVector4TestData(count, SourceAction); + TPixel[] expected = CreateScaledExpectedPixelData(source, ExpectedAction); TestOperation( source, @@ -261,7 +261,7 @@ public abstract class PixelOperationsTests : MeasureFixture { void SourceAction(ref Vector4 v) { - SRgbCompanding.Expand(ref v); + v = SRgbCompanding.Expand(v); if (this.HasUnassociatedAlpha) { @@ -276,11 +276,11 @@ public abstract class PixelOperationsTests : MeasureFixture Numerics.UnPremultiply(ref v); } - SRgbCompanding.Compress(ref v); + v = SRgbCompanding.Compress(v); } - Vector4[] source = CreateVector4TestData(count, (ref Vector4 v) => SourceAction(ref v)); - TPixel[] expected = CreateScaledExpectedPixelData(source, (ref Vector4 v) => ExpectedAction(ref v)); + Vector4[] source = CreateVector4TestData(count, SourceAction); + TPixel[] expected = CreateScaledExpectedPixelData(source, ExpectedAction); TestOperation( source, @@ -385,10 +385,10 @@ public abstract class PixelOperationsTests : MeasureFixture { } - void ExpectedAction(ref Vector4 v) => SRgbCompanding.Expand(ref v); + void ExpectedAction(ref Vector4 v) => v = SRgbCompanding.Expand(v); - TPixel[] source = CreateScaledPixelTestData(count, (ref Vector4 v) => SourceAction(ref v)); - Vector4[] expected = CreateExpectedScaledVector4Data(source, (ref Vector4 v) => ExpectedAction(ref v)); + TPixel[] source = CreateScaledPixelTestData(count, SourceAction); + Vector4[] expected = CreateExpectedScaledVector4Data(source, ExpectedAction); TestOperation( source, @@ -410,8 +410,8 @@ public abstract class PixelOperationsTests : MeasureFixture void ExpectedAction(ref Vector4 v) => Numerics.Premultiply(ref v); - TPixel[] source = CreatePixelTestData(count, (ref Vector4 v) => SourceAction(ref v)); - Vector4[] expected = CreateExpectedVector4Data(source, (ref Vector4 v) => ExpectedAction(ref v)); + TPixel[] source = CreatePixelTestData(count, SourceAction); + Vector4[] expected = CreateExpectedVector4Data(source, ExpectedAction); TestOperation( source, @@ -429,7 +429,7 @@ public abstract class PixelOperationsTests : MeasureFixture void ExpectedAction(ref Vector4 v) => Numerics.Premultiply(ref v); - TPixel[] source = CreateScaledPixelTestData(count, (ref Vector4 v) => SourceAction(ref v)); + TPixel[] source = CreateScaledPixelTestData(count, SourceAction); Vector4[] expected = CreateExpectedScaledVector4Data(source, (ref Vector4 v) => ExpectedAction(ref v)); TestOperation( @@ -452,12 +452,12 @@ public abstract class PixelOperationsTests : MeasureFixture void ExpectedAction(ref Vector4 v) { - SRgbCompanding.Expand(ref v); + v = SRgbCompanding.Expand(v); Numerics.Premultiply(ref v); } - TPixel[] source = CreateScaledPixelTestData(count, (ref Vector4 v) => SourceAction(ref v)); - Vector4[] expected = CreateExpectedScaledVector4Data(source, (ref Vector4 v) => ExpectedAction(ref v)); + TPixel[] source = CreateScaledPixelTestData(count, SourceAction); + Vector4[] expected = CreateExpectedScaledVector4Data(source, ExpectedAction); TestOperation( source, diff --git a/tests/ImageSharp.Tests/Processing/Processors/Transforms/AffineTransformTests.cs b/tests/ImageSharp.Tests/Processing/Processors/Transforms/AffineTransformTests.cs index 2ed003fdd2..ab97dfbf6a 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Transforms/AffineTransformTests.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Transforms/AffineTransformTests.cs @@ -249,6 +249,35 @@ public class AffineTransformTests image.CompareToReferenceOutput(ValidatorComparer, provider, testOutputDetails: radians); } + [Fact] + public void TransformRotationDoesNotOffset() + { + Rgba32 background = Color.DimGray.ToPixel(); + Rgba32 marker = Color.Aqua.ToPixel(); + + using Image img = new(100, 100, background); + img[0, 0] = marker; + + img.Mutate(c => c.Rotate(180)); + + Assert.Equal(marker, img[99, 99]); + + using Image img2 = new(100, 100, background); + img2[0, 0] = marker; + + img2.Mutate( + c => + c.Transform(new AffineTransformBuilder().AppendRotationDegrees(180), KnownResamplers.NearestNeighbor)); + + using Image img3 = new(100, 100, background); + img3[0, 0] = marker; + + img3.Mutate(c => c.Transform(new AffineTransformBuilder().AppendRotationDegrees(180))); + + ImageComparer.Exact.VerifySimilarity(img, img2); + ImageComparer.Exact.VerifySimilarity(img, img3); + } + private static IResampler GetResampler(string name) { PropertyInfo property = typeof(KnownResamplers).GetTypeInfo().GetProperty(name) diff --git a/tests/ImageSharp.Tests/Processing/Transforms/ProjectiveTransformTests.cs b/tests/ImageSharp.Tests/Processing/Transforms/ProjectiveTransformTests.cs index a744a0ecc6..4aec530364 100644 --- a/tests/ImageSharp.Tests/Processing/Transforms/ProjectiveTransformTests.cs +++ b/tests/ImageSharp.Tests/Processing/Transforms/ProjectiveTransformTests.cs @@ -185,6 +185,35 @@ public class ProjectiveTransformTests image.CompareToReferenceOutput(ValidatorComparer, provider, testOutputDetails: radians); } + [Fact] + public void TransformRotationDoesNotOffset() + { + Rgba32 background = Color.DimGray.ToPixel(); + Rgba32 marker = Color.Aqua.ToPixel(); + + using Image img = new(100, 100, background); + img[0, 0] = marker; + + img.Mutate(c => c.Rotate(180)); + + Assert.Equal(marker, img[99, 99]); + + using Image img2 = new(100, 100, background); + img2[0, 0] = marker; + + img2.Mutate( + c => + c.Transform(new ProjectiveTransformBuilder().AppendRotationDegrees(180), KnownResamplers.NearestNeighbor)); + + using Image img3 = new(100, 100, background); + img3[0, 0] = marker; + + img3.Mutate(c => c.Transform(new AffineTransformBuilder().AppendRotationDegrees(180))); + + ImageComparer.Exact.VerifySimilarity(img, img2); + ImageComparer.Exact.VerifySimilarity(img, img3); + } + private static IResampler GetResampler(string name) { PropertyInfo property = typeof(KnownResamplers).GetTypeInfo().GetProperty(name); diff --git a/tests/ImageSharp.Tests/Processing/Transforms/TransformBuilderTestBase.cs b/tests/ImageSharp.Tests/Processing/Transforms/TransformBuilderTestBase.cs index c17fd23799..9d256efc1c 100644 --- a/tests/ImageSharp.Tests/Processing/Transforms/TransformBuilderTestBase.cs +++ b/tests/ImageSharp.Tests/Processing/Transforms/TransformBuilderTestBase.cs @@ -97,7 +97,7 @@ public abstract class TransformBuilderTestBase this.AppendRotationDegrees(builder, degrees); // TODO: We should also test CreateRotationMatrixDegrees() (and all TransformUtils stuff!) for correctness - Matrix3x2 matrix = TransformUtils.CreateRotationMatrixDegrees(degrees, size); + Matrix3x2 matrix = TransformUtils.CreateRotationTransformMatrixDegrees(degrees, size); var position = new Vector2(x, y); var expected = Vector2.Transform(position, matrix); @@ -151,7 +151,7 @@ public abstract class TransformBuilderTestBase this.AppendSkewDegrees(builder, degreesX, degreesY); - Matrix3x2 matrix = TransformUtils.CreateSkewMatrixDegrees(degreesX, degreesY, size); + Matrix3x2 matrix = TransformUtils.CreateSkewTransformMatrixDegrees(degreesX, degreesY, size); var position = new Vector2(x, y); var expected = Vector2.Transform(position, matrix); diff --git a/tests/ImageSharp.Tests/TestImages.cs b/tests/ImageSharp.Tests/TestImages.cs index 8937799e1b..36f2a7a503 100644 --- a/tests/ImageSharp.Tests/TestImages.cs +++ b/tests/ImageSharp.Tests/TestImages.cs @@ -321,6 +321,7 @@ public static class TestImages public const string Issue2517 = "Jpg/issues/issue2517-bad-d7.jpg"; public const string Issue2067_CommentMarker = "Jpg/issues/issue-2067-comment.jpg"; public const string Issue2638 = "Jpg/issues/Issue2638.jpg"; + public const string Issue2758 = "Jpg/issues/issue-2758.jpg"; public static class Fuzz { @@ -531,6 +532,7 @@ public static class TestImages public const string Issue2450_A = "Gif/issues/issue_2450.gif"; public const string Issue2450_B = "Gif/issues/issue_2450_2.gif"; public const string Issue2198 = "Gif/issues/issue_2198.gif"; + public const string Issue2758 = "Gif/issues/issue_2758.gif"; } public static readonly string[] Animated = diff --git a/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_RotateScaleTranslate_Rgba32_TestPattern100x50_R(0)_S(1,1)_T(-20,-10).png b/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_RotateScaleTranslate_Rgba32_TestPattern100x50_R(0)_S(1,1)_T(-20,-10).png index d2ee69ce84..e8edb57b9b 100644 --- a/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_RotateScaleTranslate_Rgba32_TestPattern100x50_R(0)_S(1,1)_T(-20,-10).png +++ b/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_RotateScaleTranslate_Rgba32_TestPattern100x50_R(0)_S(1,1)_T(-20,-10).png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b6b13fd15f767271628930510b9a00cc71c8dbe37158cdee7459e8184b2c254b -size 689 +oid sha256:8dc4da0a0c727f2c95bbfdcc7710ca612b008dca97dfc5101175c384c010641b +size 770 diff --git a/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_RotateScaleTranslate_Rgba32_TestPattern100x50_R(0)_S(1,1)_T(0,0).png b/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_RotateScaleTranslate_Rgba32_TestPattern100x50_R(0)_S(1,1)_T(0,0).png index b3dc8be7f7..20fa4e18fc 100644 --- a/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_RotateScaleTranslate_Rgba32_TestPattern100x50_R(0)_S(1,1)_T(0,0).png +++ b/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_RotateScaleTranslate_Rgba32_TestPattern100x50_R(0)_S(1,1)_T(0,0).png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:5c186653c2431d706175ac59b06637852942d18a9177b21772d3ab511c563202 -size 723 +oid sha256:5ec2dd66678dc1a0ae3bd4bf6667fbb8ceb8a8af63ca878c490545e303c9d1ad +size 851 diff --git a/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_RotateScaleTranslate_Rgba32_TestPattern100x50_R(0)_S(1,1)_T(20,10).png b/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_RotateScaleTranslate_Rgba32_TestPattern100x50_R(0)_S(1,1)_T(20,10).png index f00a63f90d..beb117e113 100644 --- a/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_RotateScaleTranslate_Rgba32_TestPattern100x50_R(0)_S(1,1)_T(20,10).png +++ b/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_RotateScaleTranslate_Rgba32_TestPattern100x50_R(0)_S(1,1)_T(20,10).png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:291e1044a062943cc91840cd252e7cc4722d8f5bc59386597c6c2aac5565b5f4 -size 757 +oid sha256:febfdb0554e69f7fe363bca5aaff4b0a5347d216b29a0ba8cbebe92aa8678015 +size 892 diff --git a/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_RotateScaleTranslate_Rgba32_TestPattern100x50_R(0)_S(1,2)_T(0,0).png b/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_RotateScaleTranslate_Rgba32_TestPattern100x50_R(0)_S(1,2)_T(0,0).png index 1b361c4674..da8e446c02 100644 --- a/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_RotateScaleTranslate_Rgba32_TestPattern100x50_R(0)_S(1,2)_T(0,0).png +++ b/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_RotateScaleTranslate_Rgba32_TestPattern100x50_R(0)_S(1,2)_T(0,0).png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d8f2167445c7ca069b0f33b56f4e758e9929ff5753d076c987cf53c5d7cc3bc2 -size 3318 +oid sha256:b66a5f9d8a7f3f2a78b868bec6c7d1deea927b82d81aa6d1677e0461a3920dc9 +size 3800 diff --git a/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_RotateScaleTranslate_Rgba32_TestPattern100x50_R(0)_S(2,1)_T(0,0).png b/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_RotateScaleTranslate_Rgba32_TestPattern100x50_R(0)_S(2,1)_T(0,0).png index 7a8fe20870..4c45ba8c6c 100644 --- a/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_RotateScaleTranslate_Rgba32_TestPattern100x50_R(0)_S(2,1)_T(0,0).png +++ b/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_RotateScaleTranslate_Rgba32_TestPattern100x50_R(0)_S(2,1)_T(0,0).png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:462eaba7681f5a43f3012f8b6445180173b398c932a3cd8ec2e15cb1df9d9c4e -size 4327 +oid sha256:d5fdc46ee866e088e0ec3221145a3d2d954a0bcb6d25cbb4d538978272f34949 +size 4871 diff --git a/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_RotateScaleTranslate_Rgba32_TestPattern100x50_R(50)_S(1,1)_T(-20,-10).png b/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_RotateScaleTranslate_Rgba32_TestPattern100x50_R(50)_S(1,1)_T(-20,-10).png index 49c7795fe5..2ba0560e65 100644 --- a/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_RotateScaleTranslate_Rgba32_TestPattern100x50_R(50)_S(1,1)_T(-20,-10).png +++ b/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_RotateScaleTranslate_Rgba32_TestPattern100x50_R(50)_S(1,1)_T(-20,-10).png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:2ef489dc0837b382ad7c7ead6b7c7042dfbfba39902d4cc81b5f3805d5b03967 -size 9175 +oid sha256:1b926c8335eca5530d8704739cecae0799cc651139daedb1f88ac85b0ee1bd5d +size 9484 diff --git a/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_RotateScaleTranslate_Rgba32_TestPattern100x50_R(50)_S(1,1)_T(0,0).png b/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_RotateScaleTranslate_Rgba32_TestPattern100x50_R(50)_S(1,1)_T(0,0).png index ad39ebb12c..d141a2e28c 100644 --- a/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_RotateScaleTranslate_Rgba32_TestPattern100x50_R(50)_S(1,1)_T(0,0).png +++ b/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_RotateScaleTranslate_Rgba32_TestPattern100x50_R(50)_S(1,1)_T(0,0).png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:9d1fb97a28b5f754150343a3dc3c6974ac9abbb1577a44d88db61f0169983db0 -size 11083 +oid sha256:7f79389f79d91ac6749f21c27a592edfd2cff6efbb1d46296a26ae60d4e721f8 +size 10103 diff --git a/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_RotateScaleTranslate_Rgba32_TestPattern100x50_R(50)_S(1,1)_T(20,10).png b/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_RotateScaleTranslate_Rgba32_TestPattern100x50_R(50)_S(1,1)_T(20,10).png index 20d15c665d..d01fcb4a49 100644 --- a/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_RotateScaleTranslate_Rgba32_TestPattern100x50_R(50)_S(1,1)_T(20,10).png +++ b/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_RotateScaleTranslate_Rgba32_TestPattern100x50_R(50)_S(1,1)_T(20,10).png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c78c6310b6b716e9fdb1605b5b356fa7e1b0fbed9f6e6ff0d705d5152ce52665 -size 11148 +oid sha256:322c7e061f8565efdc19642e27353ec3073ee43d8c17fbef8c13be3bb60d11dc +size 10190 diff --git a/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_RotateScaleTranslate_Rgba32_TestPattern100x50_R(50)_S(1.1,1.3)_T(30,-20).png b/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_RotateScaleTranslate_Rgba32_TestPattern100x50_R(50)_S(1.1,1.3)_T(30,-20).png index 713ce31038..171080746b 100644 --- a/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_RotateScaleTranslate_Rgba32_TestPattern100x50_R(50)_S(1.1,1.3)_T(30,-20).png +++ b/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_RotateScaleTranslate_Rgba32_TestPattern100x50_R(50)_S(1.1,1.3)_T(30,-20).png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b4b00b7801fd844035d9235f3d1163587e9847001b918b2d971ea7e917485371 -size 13683 +oid sha256:544e7bac188d0869f98ec075fa0e73ab831e4dafe40c1520dce194df6a53c9b8 +size 12737 diff --git a/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_RotateScaleTranslate_Rgba32_TestPattern100x50_R(50)_S(1.5,1.5)_T(0,0).png b/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_RotateScaleTranslate_Rgba32_TestPattern100x50_R(50)_S(1.5,1.5)_T(0,0).png index df59e96932..07c65142a4 100644 --- a/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_RotateScaleTranslate_Rgba32_TestPattern100x50_R(50)_S(1.5,1.5)_T(0,0).png +++ b/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_RotateScaleTranslate_Rgba32_TestPattern100x50_R(50)_S(1.5,1.5)_T(0,0).png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:0b6f27c2361cc100b6928195522e0c8e76ee3ceeda814bd036d0636957024c9f -size 22761 +oid sha256:2ccc08769974e4088702d2c95fd274af7e02095955953b424a6313d656a77735 +size 19974 diff --git a/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_RotateScaleTranslate_Rgba32_TestPattern100x50__original.png b/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_RotateScaleTranslate_Rgba32_TestPattern100x50__original.png index a6ff73cf83..20fa4e18fc 100644 --- a/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_RotateScaleTranslate_Rgba32_TestPattern100x50__original.png +++ b/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_RotateScaleTranslate_Rgba32_TestPattern100x50__original.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:99d6c1d6b092a2feba2aebe2e09c521c3cc9682f3d748927cdc3cbaa38448b28 -size 710 +oid sha256:5ec2dd66678dc1a0ae3bd4bf6667fbb8ceb8a8af63ca878c490545e303c9d1ad +size 851 diff --git a/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_RotateScale_ManuallyCentered_Rgba32_TestPattern96x96_R(50)_S(0.8).png b/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_RotateScale_ManuallyCentered_Rgba32_TestPattern96x96_R(50)_S(0.8).png index 27a25224d3..84fffa468f 100644 --- a/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_RotateScale_ManuallyCentered_Rgba32_TestPattern96x96_R(50)_S(0.8).png +++ b/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_RotateScale_ManuallyCentered_Rgba32_TestPattern96x96_R(50)_S(0.8).png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ad5beec2c4a09ef8c4718bb39bda5b2d0bfcccfa4634b7458ac748d2fda498fe -size 11738 +oid sha256:c1179b300b35d526bab148833ab6240f1207b8ade36674b1f47cc5a2d47a084c +size 10603 diff --git a/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_WithSampler_Rgba32_TestPattern150x150_Bicubic.png b/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_WithSampler_Rgba32_TestPattern150x150_Bicubic.png index a909194b0b..1f1d530517 100644 --- a/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_WithSampler_Rgba32_TestPattern150x150_Bicubic.png +++ b/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_WithSampler_Rgba32_TestPattern150x150_Bicubic.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:04a3b84c668758b586f4d998f080ef96b09f726b0298b28f5dd3d739b0e90744 -size 13138 +oid sha256:f666fe67ee4a1c7152fc6190affba95ea4cbd857d96bac0968e5f1fd89792d32 +size 13486 diff --git a/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_WithSampler_Rgba32_TestPattern150x150_Box.png b/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_WithSampler_Rgba32_TestPattern150x150_Box.png index 5a8c0f2faa..0ce7ad5625 100644 --- a/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_WithSampler_Rgba32_TestPattern150x150_Box.png +++ b/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_WithSampler_Rgba32_TestPattern150x150_Box.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:21f13832d15b9491e8b73711b3081fa56c08ca69bd9b165c323dec0ba4e6f99f -size 11358 +oid sha256:5b05406a1d95f0709a7aaab7c1f57ba161b7907b76746f61788cfe527796a489 +size 4131 diff --git a/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_WithSampler_Rgba32_TestPattern150x150_CatmullRom.png b/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_WithSampler_Rgba32_TestPattern150x150_CatmullRom.png index a909194b0b..e93934b48d 100644 --- a/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_WithSampler_Rgba32_TestPattern150x150_CatmullRom.png +++ b/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_WithSampler_Rgba32_TestPattern150x150_CatmullRom.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:04a3b84c668758b586f4d998f080ef96b09f726b0298b28f5dd3d739b0e90744 -size 13138 +oid sha256:be52d36cc8f616a781c8b1416ca0bf6207b9acd580e9c06e1ee5ad434d48ab38 +size 13481 diff --git a/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_WithSampler_Rgba32_TestPattern150x150_Hermite.png b/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_WithSampler_Rgba32_TestPattern150x150_Hermite.png index 7bfe765533..2a68a381d4 100644 --- a/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_WithSampler_Rgba32_TestPattern150x150_Hermite.png +++ b/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_WithSampler_Rgba32_TestPattern150x150_Hermite.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:829f7e7315a5a0cc3e88115529305ddb0c53a104863a8a66f6ad1f2efc440109 -size 12231 +oid sha256:33c99b8f0fb5d10a273a90946767f93ab6cd2dd1942f9829d695987db30dccfa +size 12488 diff --git a/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_WithSampler_Rgba32_TestPattern150x150_Lanczos2.png b/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_WithSampler_Rgba32_TestPattern150x150_Lanczos2.png index e248b6d918..08f89da07e 100644 --- a/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_WithSampler_Rgba32_TestPattern150x150_Lanczos2.png +++ b/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_WithSampler_Rgba32_TestPattern150x150_Lanczos2.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:6ea7ca66c31474c0bb9673a0d85c1c7465e387ebabf4e2d1e8f9daebfc7c8f34 -size 13956 +oid sha256:af2c0201c59065a500ae985e9b7ca164e5bcb4ce2d8d8305103398830472e07c +size 14206 diff --git a/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_WithSampler_Rgba32_TestPattern150x150_Lanczos3.png b/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_WithSampler_Rgba32_TestPattern150x150_Lanczos3.png index 5c81a5f5da..85d4871036 100644 --- a/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_WithSampler_Rgba32_TestPattern150x150_Lanczos3.png +++ b/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_WithSampler_Rgba32_TestPattern150x150_Lanczos3.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:6dd98ac441f3c20ea999f058c7b21601d5981d46e9b77709c25f2930a64edb93 -size 17148 +oid sha256:4cef17988c4a3a667dede3dd86ed61d0507a84e5b846f52459683fd04e5a396a +size 17297 diff --git a/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_WithSampler_Rgba32_TestPattern150x150_Lanczos5.png b/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_WithSampler_Rgba32_TestPattern150x150_Lanczos5.png index 1647aae60d..347cbf089f 100644 --- a/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_WithSampler_Rgba32_TestPattern150x150_Lanczos5.png +++ b/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_WithSampler_Rgba32_TestPattern150x150_Lanczos5.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d5c4772d9b9dc57c4b5d47450ec9d02d96e40656cf2015f171b5425945f8a598 -size 18726 +oid sha256:9699a81572c03c2bc47d8bbdd1d64df26f87df3d4ad59fb6f164f6e82786d91d +size 18853 diff --git a/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_WithSampler_Rgba32_TestPattern150x150_Lanczos8.png b/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_WithSampler_Rgba32_TestPattern150x150_Lanczos8.png index 3949197248..69fe0b1355 100644 --- a/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_WithSampler_Rgba32_TestPattern150x150_Lanczos8.png +++ b/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_WithSampler_Rgba32_TestPattern150x150_Lanczos8.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:bb025c4470cec1b0d6544924e46b84cbdb90d75da5d0f879f2c7d7ec9875dee2 -size 20574 +oid sha256:4fb1f59c5393debdff9bd4b7a6c222b7a0686e6d5ef24363e3d5c94ba9b5bc27 +size 20725 diff --git a/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_WithSampler_Rgba32_TestPattern150x150_MitchellNetravali.png b/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_WithSampler_Rgba32_TestPattern150x150_MitchellNetravali.png index da8413be52..0fa8cf0c06 100644 --- a/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_WithSampler_Rgba32_TestPattern150x150_MitchellNetravali.png +++ b/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_WithSampler_Rgba32_TestPattern150x150_MitchellNetravali.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c4abaa06827cb779026f8fbb655692bdd8adab37ae5b00c3ae18ebea456eb8d9 -size 13459 +oid sha256:8ffa8ca6a60de9fe26a191edc2127886c61c072c1aa2b91fe3125512fe40e1b3 +size 13848 diff --git a/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_WithSampler_Rgba32_TestPattern150x150_NearestNeighbor.png b/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_WithSampler_Rgba32_TestPattern150x150_NearestNeighbor.png index 06c6bfa22e..36e409ecb9 100644 --- a/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_WithSampler_Rgba32_TestPattern150x150_NearestNeighbor.png +++ b/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_WithSampler_Rgba32_TestPattern150x150_NearestNeighbor.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:37332e56f71506663b00deacc52adaa7574167565e395217b493d235965b29b9 -size 11563 +oid sha256:abf1d0f323795c0aaff0ff8b488d9866c5b2f7c64aad83701cb1f60e22668b0e +size 4161 diff --git a/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_WithSampler_Rgba32_TestPattern150x150_Robidoux.png b/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_WithSampler_Rgba32_TestPattern150x150_Robidoux.png index 5bdf261405..f8f102e4c8 100644 --- a/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_WithSampler_Rgba32_TestPattern150x150_Robidoux.png +++ b/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_WithSampler_Rgba32_TestPattern150x150_Robidoux.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3435ade8f7988779280820342e16881b049f717735d2218ac5a971a1bd807db1 -size 13448 +oid sha256:9b0f3c41248138bd501ae844e5b54fb9f49e5d22bab9b2ef0a0654034708b99f +size 14027 diff --git a/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_WithSampler_Rgba32_TestPattern150x150_RobidouxSharp.png b/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_WithSampler_Rgba32_TestPattern150x150_RobidouxSharp.png index 0e2dbf2565..fc46cad7c0 100644 --- a/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_WithSampler_Rgba32_TestPattern150x150_RobidouxSharp.png +++ b/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_WithSampler_Rgba32_TestPattern150x150_RobidouxSharp.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f0098aa45e820544dd16a58396fa70860886b7d79900916ed97376a8328a5ff2 -size 13367 +oid sha256:6a3f839d64984b9fda4125c6643f4699add6f95373a2194c5726ed3740565a47 +size 13725 diff --git a/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_WithSampler_Rgba32_TestPattern150x150_Spline.png b/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_WithSampler_Rgba32_TestPattern150x150_Spline.png index 27ed945dc8..58e879d4e3 100644 --- a/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_WithSampler_Rgba32_TestPattern150x150_Spline.png +++ b/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_WithSampler_Rgba32_TestPattern150x150_Spline.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7729495277b80a42e24dd8f40cdd8a280443575710fb4e199e4871c28b558271 -size 14253 +oid sha256:2ac143bc73612cecfffbec049a7b68234e7bf7581e680c3f996a977c6d671cc1 +size 14865 diff --git a/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_WithSampler_Rgba32_TestPattern150x150_Triangle.png b/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_WithSampler_Rgba32_TestPattern150x150_Triangle.png index 90c47e96d7..fa25146d9c 100644 --- a/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_WithSampler_Rgba32_TestPattern150x150_Triangle.png +++ b/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_WithSampler_Rgba32_TestPattern150x150_Triangle.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a2304c234b93bdabaa018263dec70e62090ad1bbb7005ef62643b88600a863fb -size 12157 +oid sha256:4eb9dab20d5a03c0adde05a9b741d9e1b0fb8c3d79054a8bc5788de496e5c7f8 +size 12420 diff --git a/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_WithSampler_Rgba32_TestPattern150x150_Welch.png b/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_WithSampler_Rgba32_TestPattern150x150_Welch.png index 581b229500..dc8ea690c2 100644 --- a/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_WithSampler_Rgba32_TestPattern150x150_Welch.png +++ b/tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_WithSampler_Rgba32_TestPattern150x150_Welch.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:54b0da9646b7f4cf83df784d69dfbec48e0bdc1788d70a9872817543f72f57c1 -size 16829 +oid sha256:0f56ee78cc2fd698ac8ea84912648f0b49d4b4d66b439f6976447c56a44c2998 +size 16909 diff --git a/tests/Images/External/ReferenceOutput/Drawing/DrawImageTests/DrawTransformed.png b/tests/Images/External/ReferenceOutput/Drawing/DrawImageTests/DrawTransformed.png index c04521ebc7..17238cf2f7 100644 --- a/tests/Images/External/ReferenceOutput/Drawing/DrawImageTests/DrawTransformed.png +++ b/tests/Images/External/ReferenceOutput/Drawing/DrawImageTests/DrawTransformed.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:233d8c6c9e101dddf5d210d47c7a20807f8f956738289068ea03b774258ef8c6 -size 182754 +oid sha256:00836a98742d177a2376af32d8d858fcf9f26a4da5a311dd5faf5cd80f233c0b +size 184397 diff --git a/tests/Images/External/ReferenceOutput/GifDecoderTests/Issue2012BadMinCode_Rgba32_issue2012_drona1.png b/tests/Images/External/ReferenceOutput/GifDecoderTests/Issue2012BadMinCode_Rgba32_issue2012_drona1.png index cdba9277b1..b07e806620 100644 --- a/tests/Images/External/ReferenceOutput/GifDecoderTests/Issue2012BadMinCode_Rgba32_issue2012_drona1.png +++ b/tests/Images/External/ReferenceOutput/GifDecoderTests/Issue2012BadMinCode_Rgba32_issue2012_drona1.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a3a24c066895fd3a76649da376485cbc1912d6a3ae15369575f523e66364b3b6 -size 141563 +oid sha256:588d055a93c7b4fdb62e8b77f3ae08753a9e8990151cb0523f5e761996189b70 +size 142244 diff --git a/tests/Images/External/ReferenceOutput/GifDecoderTests/Issue2758_BadDescriptorDimensions_Rgba32_issue_2758.gif/00.png b/tests/Images/External/ReferenceOutput/GifDecoderTests/Issue2758_BadDescriptorDimensions_Rgba32_issue_2758.gif/00.png new file mode 100644 index 0000000000..f63cc98ada --- /dev/null +++ b/tests/Images/External/ReferenceOutput/GifDecoderTests/Issue2758_BadDescriptorDimensions_Rgba32_issue_2758.gif/00.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4f39b23217f1d095eeb8eed5ccea36be813c307a60ef4b1942e9f74028451c38 +size 81944 diff --git a/tests/Images/External/ReferenceOutput/GifDecoderTests/Issue2758_BadDescriptorDimensions_Rgba32_issue_2758.gif/01.png b/tests/Images/External/ReferenceOutput/GifDecoderTests/Issue2758_BadDescriptorDimensions_Rgba32_issue_2758.gif/01.png new file mode 100644 index 0000000000..f63cc98ada --- /dev/null +++ b/tests/Images/External/ReferenceOutput/GifDecoderTests/Issue2758_BadDescriptorDimensions_Rgba32_issue_2758.gif/01.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4f39b23217f1d095eeb8eed5ccea36be813c307a60ef4b1942e9f74028451c38 +size 81944 diff --git a/tests/Images/External/ReferenceOutput/GifDecoderTests/IssueTooLargeLzwBits_Rgba32_issue_2743.gif/07.png b/tests/Images/External/ReferenceOutput/GifDecoderTests/IssueTooLargeLzwBits_Rgba32_issue_2743.gif/07.png index 75cf685e43..efba40c99d 100644 --- a/tests/Images/External/ReferenceOutput/GifDecoderTests/IssueTooLargeLzwBits_Rgba32_issue_2743.gif/07.png +++ b/tests/Images/External/ReferenceOutput/GifDecoderTests/IssueTooLargeLzwBits_Rgba32_issue_2743.gif/07.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:489642f0c81fd12e97007fe6feb11b0e93e351199a922ce038069a3782ad0722 -size 135 +oid sha256:5016a323018f09e292165ad5392d82dcbad5e79c2b6b93aff3322dffff80b309 +size 126 diff --git a/tests/Images/External/ReferenceOutput/Transforms/RotateTests/Rotate_WithAngle_TestPattern100x50_-170.png b/tests/Images/External/ReferenceOutput/Transforms/RotateTests/Rotate_WithAngle_TestPattern100x50_-170.png index e5ac34ff9d..a9289abd0d 100644 --- a/tests/Images/External/ReferenceOutput/Transforms/RotateTests/Rotate_WithAngle_TestPattern100x50_-170.png +++ b/tests/Images/External/ReferenceOutput/Transforms/RotateTests/Rotate_WithAngle_TestPattern100x50_-170.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:964e8e5c160d7cd57e3b1fc584a39c1c8c61b835ff6af8264ec0631175286fca -size 10794 +oid sha256:801067dfb19b2a9a1fbd14b771e780b475c21f3ccdc1e709bbc20d62061ad1d1 +size 8782 diff --git a/tests/Images/External/ReferenceOutput/Transforms/RotateTests/Rotate_WithAngle_TestPattern100x50_-50.png b/tests/Images/External/ReferenceOutput/Transforms/RotateTests/Rotate_WithAngle_TestPattern100x50_-50.png index 5b2ecebd6c..43fcd5df5e 100644 --- a/tests/Images/External/ReferenceOutput/Transforms/RotateTests/Rotate_WithAngle_TestPattern100x50_-50.png +++ b/tests/Images/External/ReferenceOutput/Transforms/RotateTests/Rotate_WithAngle_TestPattern100x50_-50.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:2997d51c4ca534df2561f2c3bf1801f04631277b4259e25d9ef3fc164212f722 -size 11223 +oid sha256:ccbdd3dcdbc888923e85495fbd7837478cca813be6ecece63ee645bdf39d436f +size 10325 diff --git a/tests/Images/External/ReferenceOutput/Transforms/RotateTests/Rotate_WithAngle_TestPattern100x50_170.png b/tests/Images/External/ReferenceOutput/Transforms/RotateTests/Rotate_WithAngle_TestPattern100x50_170.png index d620913d41..9a7f9866da 100644 --- a/tests/Images/External/ReferenceOutput/Transforms/RotateTests/Rotate_WithAngle_TestPattern100x50_170.png +++ b/tests/Images/External/ReferenceOutput/Transforms/RotateTests/Rotate_WithAngle_TestPattern100x50_170.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e8bd1219a9363bcc8dc088fb0a0a17c5e1914d418c89f4affc3fb9abf236f705 -size 10725 +oid sha256:60d1be2ffa6d50f97561b92efe8d0c0337f9c121582e38c9ab9af75be8eed32d +size 8539 diff --git a/tests/Images/External/ReferenceOutput/Transforms/RotateTests/Rotate_WithAngle_TestPattern100x50_50.png b/tests/Images/External/ReferenceOutput/Transforms/RotateTests/Rotate_WithAngle_TestPattern100x50_50.png index ad39ebb12c..d141a2e28c 100644 --- a/tests/Images/External/ReferenceOutput/Transforms/RotateTests/Rotate_WithAngle_TestPattern100x50_50.png +++ b/tests/Images/External/ReferenceOutput/Transforms/RotateTests/Rotate_WithAngle_TestPattern100x50_50.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:9d1fb97a28b5f754150343a3dc3c6974ac9abbb1577a44d88db61f0169983db0 -size 11083 +oid sha256:7f79389f79d91ac6749f21c27a592edfd2cff6efbb1d46296a26ae60d4e721f8 +size 10103 diff --git a/tests/Images/External/ReferenceOutput/Transforms/RotateTests/Rotate_WithAngle_TestPattern50x100_-170.png b/tests/Images/External/ReferenceOutput/Transforms/RotateTests/Rotate_WithAngle_TestPattern50x100_-170.png index 8b15fa6c4e..1d27e23958 100644 --- a/tests/Images/External/ReferenceOutput/Transforms/RotateTests/Rotate_WithAngle_TestPattern50x100_-170.png +++ b/tests/Images/External/ReferenceOutput/Transforms/RotateTests/Rotate_WithAngle_TestPattern50x100_-170.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:5e62ccc2cca36898a01445ef03361b84ff19aa1c0498e9dcbf21703dc1c009dd -size 11278 +oid sha256:75fb59ea2947efb1abf73cd824e54b6e8f6271343bd2fdadb005b29476988921 +size 9423 diff --git a/tests/Images/External/ReferenceOutput/Transforms/RotateTests/Rotate_WithAngle_TestPattern50x100_-50.png b/tests/Images/External/ReferenceOutput/Transforms/RotateTests/Rotate_WithAngle_TestPattern50x100_-50.png index 8bb5f272bc..628d0c889c 100644 --- a/tests/Images/External/ReferenceOutput/Transforms/RotateTests/Rotate_WithAngle_TestPattern50x100_-50.png +++ b/tests/Images/External/ReferenceOutput/Transforms/RotateTests/Rotate_WithAngle_TestPattern50x100_-50.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f8f1f14a3c32d8d7e0406c2cf9480aa78dcef7bf223966e80f620680ef68375c -size 12064 +oid sha256:9c2d94791af40e001fc44b23eeecac7a606492c747b22ede0cdc7069ef121cb8 +size 11193 diff --git a/tests/Images/External/ReferenceOutput/Transforms/RotateTests/Rotate_WithAngle_TestPattern50x100_170.png b/tests/Images/External/ReferenceOutput/Transforms/RotateTests/Rotate_WithAngle_TestPattern50x100_170.png index 6245b32266..0e927cfbd0 100644 --- a/tests/Images/External/ReferenceOutput/Transforms/RotateTests/Rotate_WithAngle_TestPattern50x100_170.png +++ b/tests/Images/External/ReferenceOutput/Transforms/RotateTests/Rotate_WithAngle_TestPattern50x100_170.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7756d2402f4cf7d221d832d921fcff80fef6a36da5373cd9cb46b8e0f00e2fb1 -size 11273 +oid sha256:016de6e82b6fb03fd55168ea7fc12ab245d0e0387ca7c32d3ef1158a85a8facd +size 9330 diff --git a/tests/Images/External/ReferenceOutput/Transforms/RotateTests/Rotate_WithAngle_TestPattern50x100_50.png b/tests/Images/External/ReferenceOutput/Transforms/RotateTests/Rotate_WithAngle_TestPattern50x100_50.png index 28435befbc..ac4d473624 100644 --- a/tests/Images/External/ReferenceOutput/Transforms/RotateTests/Rotate_WithAngle_TestPattern50x100_50.png +++ b/tests/Images/External/ReferenceOutput/Transforms/RotateTests/Rotate_WithAngle_TestPattern50x100_50.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d49ac2a6529959eb2a5d257c804ba576f9426fafe918c7fb267fc397477666dd -size 12051 +oid sha256:9219cc118fe7195b730cbe2e6407cde54e6f4c7930a71b7418bc7c273aa4120c +size 11050 diff --git a/tests/Images/External/ReferenceOutput/Transforms/SkewTests/Skew_IsNotBoundToSinglePixelType_Bgra32_TestPattern100x50_-20_-10.png b/tests/Images/External/ReferenceOutput/Transforms/SkewTests/Skew_IsNotBoundToSinglePixelType_Bgra32_TestPattern100x50_-20_-10.png index 163cc401df..147f9c9897 100644 --- a/tests/Images/External/ReferenceOutput/Transforms/SkewTests/Skew_IsNotBoundToSinglePixelType_Bgra32_TestPattern100x50_-20_-10.png +++ b/tests/Images/External/ReferenceOutput/Transforms/SkewTests/Skew_IsNotBoundToSinglePixelType_Bgra32_TestPattern100x50_-20_-10.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d56651460aa5c942d800f2c92f0934f4c53b0f83e6fe8a2eb891a85bd9d93542 -size 10244 +oid sha256:2b243340f372220033b349a96cbd7ecd732395fa15e4d1ed62048d2031c42794 +size 8398 diff --git a/tests/Images/External/ReferenceOutput/Transforms/SkewTests/Skew_IsNotBoundToSinglePixelType_Bgra32_TestPattern100x50_20_10.png b/tests/Images/External/ReferenceOutput/Transforms/SkewTests/Skew_IsNotBoundToSinglePixelType_Bgra32_TestPattern100x50_20_10.png index d080ba778d..d1252cb2c4 100644 --- a/tests/Images/External/ReferenceOutput/Transforms/SkewTests/Skew_IsNotBoundToSinglePixelType_Bgra32_TestPattern100x50_20_10.png +++ b/tests/Images/External/ReferenceOutput/Transforms/SkewTests/Skew_IsNotBoundToSinglePixelType_Bgra32_TestPattern100x50_20_10.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d2912a3cd8088e9ad5e4e33b7c85825aedf9f910c32abbe78f3560510024b770 -size 10141 +oid sha256:fdd2745aba2f09bb4a09e881339fe62774ce5658902aa9d83b3a1e0718260084 +size 8694 diff --git a/tests/Images/External/ReferenceOutput/Transforms/SkewTests/Skew_IsNotBoundToSinglePixelType_Rgb24_TestPattern100x50_-20_-10.png b/tests/Images/External/ReferenceOutput/Transforms/SkewTests/Skew_IsNotBoundToSinglePixelType_Rgb24_TestPattern100x50_-20_-10.png index 058b229a2c..235e95d8fc 100644 --- a/tests/Images/External/ReferenceOutput/Transforms/SkewTests/Skew_IsNotBoundToSinglePixelType_Rgb24_TestPattern100x50_-20_-10.png +++ b/tests/Images/External/ReferenceOutput/Transforms/SkewTests/Skew_IsNotBoundToSinglePixelType_Rgb24_TestPattern100x50_-20_-10.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:58aea9e0fb398d84dc2f27e1b06ad53d195f2dd06bb1f489c6e51fae5724867d -size 7478 +oid sha256:281bd00550ab1cf9b05011750e6de330cdd42a8644ecf3b7c176bd5c6e94c59b +size 6098 diff --git a/tests/Images/External/ReferenceOutput/Transforms/SkewTests/Skew_IsNotBoundToSinglePixelType_Rgb24_TestPattern100x50_20_10.png b/tests/Images/External/ReferenceOutput/Transforms/SkewTests/Skew_IsNotBoundToSinglePixelType_Rgb24_TestPattern100x50_20_10.png index 899864e537..3b63f58f36 100644 --- a/tests/Images/External/ReferenceOutput/Transforms/SkewTests/Skew_IsNotBoundToSinglePixelType_Rgb24_TestPattern100x50_20_10.png +++ b/tests/Images/External/ReferenceOutput/Transforms/SkewTests/Skew_IsNotBoundToSinglePixelType_Rgb24_TestPattern100x50_20_10.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:49b3eaeedfdd1c90b5ec48bf07e387d6cac8062ba15826971c22868b29ecb769 -size 7462 +oid sha256:e755ed61d7eab2c297f4b6592366b54ac801cbdb3d920741dfdd04dfaf73f9b9 +size 6086 diff --git a/tests/Images/External/ReferenceOutput/Transforms/SkewTests/Skew_WorksWithAllResamplers_ducky_Bicubic.png b/tests/Images/External/ReferenceOutput/Transforms/SkewTests/Skew_WorksWithAllResamplers_ducky_Bicubic.png index 0e0106041a..340455428a 100644 --- a/tests/Images/External/ReferenceOutput/Transforms/SkewTests/Skew_WorksWithAllResamplers_ducky_Bicubic.png +++ b/tests/Images/External/ReferenceOutput/Transforms/SkewTests/Skew_WorksWithAllResamplers_ducky_Bicubic.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e27f9c12e743d3bcc328dc7e5708c738c5a8ccba3ac99a465bb2fbc045afdc45 -size 28062 +oid sha256:8e8afa56c5abb0e4b5895f35415db1178d041120d9f8306902f554cfaaada88d +size 26540 diff --git a/tests/Images/External/ReferenceOutput/Transforms/SkewTests/Skew_WorksWithAllResamplers_ducky_Box.png b/tests/Images/External/ReferenceOutput/Transforms/SkewTests/Skew_WorksWithAllResamplers_ducky_Box.png index 8f9dd4e74f..9ef7866924 100644 --- a/tests/Images/External/ReferenceOutput/Transforms/SkewTests/Skew_WorksWithAllResamplers_ducky_Box.png +++ b/tests/Images/External/ReferenceOutput/Transforms/SkewTests/Skew_WorksWithAllResamplers_ducky_Box.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3dfbc7ca2c42fba08daff44f29fdc64f76cb5515ee8f0fd5798270ed64fdeb27 -size 26282 +oid sha256:a2c174ef54b68f025352e25800f655fe3b94a0d3f75cb48bd2ac0e8d6931faf8 +size 24827 diff --git a/tests/Images/External/ReferenceOutput/Transforms/SkewTests/Skew_WorksWithAllResamplers_ducky_CatmullRom.png b/tests/Images/External/ReferenceOutput/Transforms/SkewTests/Skew_WorksWithAllResamplers_ducky_CatmullRom.png index 65e094dc1f..14f7748537 100644 --- a/tests/Images/External/ReferenceOutput/Transforms/SkewTests/Skew_WorksWithAllResamplers_ducky_CatmullRom.png +++ b/tests/Images/External/ReferenceOutput/Transforms/SkewTests/Skew_WorksWithAllResamplers_ducky_CatmullRom.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ad0e7cf115b2057fa223c45340f67b1659be6f6acefad32e0b02ca35327ffdf8 -size 28052 +oid sha256:6b56ceae2f350a1402beecc5b5e2930be1011a95fbf224cccf73b96f3931b646 +size 26531 diff --git a/tests/Images/External/ReferenceOutput/Transforms/SkewTests/Skew_WorksWithAllResamplers_ducky_Hermite.png b/tests/Images/External/ReferenceOutput/Transforms/SkewTests/Skew_WorksWithAllResamplers_ducky_Hermite.png index 6d1eb77e19..c8204eacf3 100644 --- a/tests/Images/External/ReferenceOutput/Transforms/SkewTests/Skew_WorksWithAllResamplers_ducky_Hermite.png +++ b/tests/Images/External/ReferenceOutput/Transforms/SkewTests/Skew_WorksWithAllResamplers_ducky_Hermite.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7ca5e0729371222626d711a3f425c602198f5b51c8629e59027e37d63fadf5fa -size 25870 +oid sha256:049ee7fc2bb758609a64149c338bfae2eab44755f53e6b7c25a5e8b8725ed8ac +size 24416 diff --git a/tests/Images/External/ReferenceOutput/Transforms/SkewTests/Skew_WorksWithAllResamplers_ducky_Lanczos2.png b/tests/Images/External/ReferenceOutput/Transforms/SkewTests/Skew_WorksWithAllResamplers_ducky_Lanczos2.png index 9098e51bee..2bc57092a2 100644 --- a/tests/Images/External/ReferenceOutput/Transforms/SkewTests/Skew_WorksWithAllResamplers_ducky_Lanczos2.png +++ b/tests/Images/External/ReferenceOutput/Transforms/SkewTests/Skew_WorksWithAllResamplers_ducky_Lanczos2.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:bf1df2d5b53bc779f01e6ad32ca502cd5fb40826cb1fbf5ddc55b769f68e0d8c -size 28060 +oid sha256:72c487a2fa3d608021b26a4d6b4517f8548fdcfc62fbafdd8649015dbec8ff87 +size 26504 diff --git a/tests/Images/External/ReferenceOutput/Transforms/SkewTests/Skew_WorksWithAllResamplers_ducky_Lanczos3.png b/tests/Images/External/ReferenceOutput/Transforms/SkewTests/Skew_WorksWithAllResamplers_ducky_Lanczos3.png index 00f4e8d925..fee364e217 100644 --- a/tests/Images/External/ReferenceOutput/Transforms/SkewTests/Skew_WorksWithAllResamplers_ducky_Lanczos3.png +++ b/tests/Images/External/ReferenceOutput/Transforms/SkewTests/Skew_WorksWithAllResamplers_ducky_Lanczos3.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f21b8a574beb978befbb44e65def5a4d818fbca6be211cccc455fd819c278531 -size 34325 +oid sha256:099733c9d4490c86cfbb10a016e2dd073539a95f9d5ff9018cf9b5be5404fa13 +size 33435 diff --git a/tests/Images/External/ReferenceOutput/Transforms/SkewTests/Skew_WorksWithAllResamplers_ducky_Lanczos5.png b/tests/Images/External/ReferenceOutput/Transforms/SkewTests/Skew_WorksWithAllResamplers_ducky_Lanczos5.png index 69afe9a6fd..30325ccc6f 100644 --- a/tests/Images/External/ReferenceOutput/Transforms/SkewTests/Skew_WorksWithAllResamplers_ducky_Lanczos5.png +++ b/tests/Images/External/ReferenceOutput/Transforms/SkewTests/Skew_WorksWithAllResamplers_ducky_Lanczos5.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:5ced1fc39a97381af2ef369b94351a96930a58052343dcaa464b12da1747906f -size 37066 +oid sha256:27f2a2b21f8ae878e15120ea5a4a983bde7984b3468dc8426055885efc278fe6 +size 35547 diff --git a/tests/Images/External/ReferenceOutput/Transforms/SkewTests/Skew_WorksWithAllResamplers_ducky_Lanczos8.png b/tests/Images/External/ReferenceOutput/Transforms/SkewTests/Skew_WorksWithAllResamplers_ducky_Lanczos8.png index 53e0dfa079..ff81256a70 100644 --- a/tests/Images/External/ReferenceOutput/Transforms/SkewTests/Skew_WorksWithAllResamplers_ducky_Lanczos8.png +++ b/tests/Images/External/ReferenceOutput/Transforms/SkewTests/Skew_WorksWithAllResamplers_ducky_Lanczos8.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b60fa32cf39ee70103d8498e5dc751fe2d5801fa30ff9f0948376fac64cb1021 -size 41427 +oid sha256:6b5cbe60e26e123e5a5cdf5a4e88305340f76d32a9c64a220c1fa7512f84e786 +size 39442 diff --git a/tests/Images/External/ReferenceOutput/Transforms/SkewTests/Skew_WorksWithAllResamplers_ducky_MitchellNetravali.png b/tests/Images/External/ReferenceOutput/Transforms/SkewTests/Skew_WorksWithAllResamplers_ducky_MitchellNetravali.png index 9216e2f17b..263dd7426d 100644 --- a/tests/Images/External/ReferenceOutput/Transforms/SkewTests/Skew_WorksWithAllResamplers_ducky_MitchellNetravali.png +++ b/tests/Images/External/ReferenceOutput/Transforms/SkewTests/Skew_WorksWithAllResamplers_ducky_MitchellNetravali.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ce56cc11a369838e011a796cc380f9f06ca915a845e5b6b0425cb7366f162a5c -size 27303 +oid sha256:102cceb79acb1dfd7ec8887b4906e33456c774d48320d1624b3c73975d26f145 +size 25981 diff --git a/tests/Images/External/ReferenceOutput/Transforms/SkewTests/Skew_WorksWithAllResamplers_ducky_NearestNeighbor.png b/tests/Images/External/ReferenceOutput/Transforms/SkewTests/Skew_WorksWithAllResamplers_ducky_NearestNeighbor.png index 8f9dd4e74f..9ef7866924 100644 --- a/tests/Images/External/ReferenceOutput/Transforms/SkewTests/Skew_WorksWithAllResamplers_ducky_NearestNeighbor.png +++ b/tests/Images/External/ReferenceOutput/Transforms/SkewTests/Skew_WorksWithAllResamplers_ducky_NearestNeighbor.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3dfbc7ca2c42fba08daff44f29fdc64f76cb5515ee8f0fd5798270ed64fdeb27 -size 26282 +oid sha256:a2c174ef54b68f025352e25800f655fe3b94a0d3f75cb48bd2ac0e8d6931faf8 +size 24827 diff --git a/tests/Images/External/ReferenceOutput/Transforms/SkewTests/Skew_WorksWithAllResamplers_ducky_Robidoux.png b/tests/Images/External/ReferenceOutput/Transforms/SkewTests/Skew_WorksWithAllResamplers_ducky_Robidoux.png index 79ef7ef283..85bbd5ec38 100644 --- a/tests/Images/External/ReferenceOutput/Transforms/SkewTests/Skew_WorksWithAllResamplers_ducky_Robidoux.png +++ b/tests/Images/External/ReferenceOutput/Transforms/SkewTests/Skew_WorksWithAllResamplers_ducky_Robidoux.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:9ce82b69d9dde2621a3d54647e7a659d440e2f9b0102831773a97abca4bcfa4c -size 27248 +oid sha256:e61629aeefac7e0a1a6b46b44ad86ed4a5ba0908bb3febc18bb5f9f3ded1c08d +size 25751 diff --git a/tests/Images/External/ReferenceOutput/Transforms/SkewTests/Skew_WorksWithAllResamplers_ducky_RobidouxSharp.png b/tests/Images/External/ReferenceOutput/Transforms/SkewTests/Skew_WorksWithAllResamplers_ducky_RobidouxSharp.png index 823f471f2a..f200a5f955 100644 --- a/tests/Images/External/ReferenceOutput/Transforms/SkewTests/Skew_WorksWithAllResamplers_ducky_RobidouxSharp.png +++ b/tests/Images/External/ReferenceOutput/Transforms/SkewTests/Skew_WorksWithAllResamplers_ducky_RobidouxSharp.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:71d45938ec05003c5dcae0962ac6847041410123ba1dc2debbbf41e22ac2d91a -size 27519 +oid sha256:45b1b48e1df393f4c435189c71a6bd3bccfe7a055d76d414a8d0c009b59fa0a0 +size 26145 diff --git a/tests/Images/External/ReferenceOutput/Transforms/SkewTests/Skew_WorksWithAllResamplers_ducky_Spline.png b/tests/Images/External/ReferenceOutput/Transforms/SkewTests/Skew_WorksWithAllResamplers_ducky_Spline.png index 23766e557a..434bb32a81 100644 --- a/tests/Images/External/ReferenceOutput/Transforms/SkewTests/Skew_WorksWithAllResamplers_ducky_Spline.png +++ b/tests/Images/External/ReferenceOutput/Transforms/SkewTests/Skew_WorksWithAllResamplers_ducky_Spline.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:75bd6138967d8795d0be7fe2e76c889718276924d702349105003c24f08957e2 -size 25559 +oid sha256:d6d186f9e547f658b719bc033e3b110d64cf2a02caecc510d4e2f88359e69746 +size 24176 diff --git a/tests/Images/External/ReferenceOutput/Transforms/SkewTests/Skew_WorksWithAllResamplers_ducky_Triangle.png b/tests/Images/External/ReferenceOutput/Transforms/SkewTests/Skew_WorksWithAllResamplers_ducky_Triangle.png index 33e7b6ef1e..e3be1ffe5a 100644 --- a/tests/Images/External/ReferenceOutput/Transforms/SkewTests/Skew_WorksWithAllResamplers_ducky_Triangle.png +++ b/tests/Images/External/ReferenceOutput/Transforms/SkewTests/Skew_WorksWithAllResamplers_ducky_Triangle.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b280a880b864a14225fd433378dede02cfad897059939cebbe0e04659de6d5a9 -size 25382 +oid sha256:339b3299984f1450f1a8200e487964c0338b511b82e459d67a3583d0bd46b805 +size 24013 diff --git a/tests/Images/External/ReferenceOutput/Transforms/SkewTests/Skew_WorksWithAllResamplers_ducky_Welch.png b/tests/Images/External/ReferenceOutput/Transforms/SkewTests/Skew_WorksWithAllResamplers_ducky_Welch.png index a170cc2cb0..7dbeeaf357 100644 --- a/tests/Images/External/ReferenceOutput/Transforms/SkewTests/Skew_WorksWithAllResamplers_ducky_Welch.png +++ b/tests/Images/External/ReferenceOutput/Transforms/SkewTests/Skew_WorksWithAllResamplers_ducky_Welch.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3c94d6ae8ad8ddab17a5ad1cfc73e711912a3f13e6bd3dfe9e5f0c8ec2c004af -size 33257 +oid sha256:5335c6184829fdc405475bd34d2fae60cf6d5ae050b4d671ac5dd25242ff1368 +size 31888 diff --git a/tests/Images/Input/Gif/issues/issue_2758.gif b/tests/Images/Input/Gif/issues/issue_2758.gif new file mode 100644 index 0000000000..17db9fa132 --- /dev/null +++ b/tests/Images/Input/Gif/issues/issue_2758.gif @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:13e9374181c7536d1d2ecb514753a5290c0ec06234ca079c6c8c8a832586b668 +size 199 diff --git a/tests/Images/Input/Jpg/issues/issue-2758.jpg b/tests/Images/Input/Jpg/issues/issue-2758.jpg new file mode 100644 index 0000000000..48ee1159ec --- /dev/null +++ b/tests/Images/Input/Jpg/issues/issue-2758.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f32a238b57b7073f7442f8ae7efd6ba3ae4cda30d57e6666fb8a1eaa27108558 +size 1412