mirror of https://github.com/SixLabors/ImageSharp
19 changed files with 524 additions and 114 deletions
@ -1 +1 @@ |
|||
Subproject commit a1d3ac20494631e3cc13132897573796b0e4ee6d |
|||
Subproject commit 7ac5703452348d9295db31fc0912c2bd9e419dc9 |
|||
@ -1,72 +0,0 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Six Labors Split License.
|
|||
|
|||
using System.Runtime.CompilerServices; |
|||
using System.Runtime.InteropServices; |
|||
|
|||
namespace SixLabors.ImageSharp.Tuples; |
|||
|
|||
/// <summary>
|
|||
/// Contains 8 element value tuples of various types.
|
|||
/// </summary>
|
|||
[StructLayout(LayoutKind.Sequential)] |
|||
internal struct Octet<T> |
|||
where T : unmanaged |
|||
{ |
|||
public T V0; |
|||
public T V1; |
|||
public T V2; |
|||
public T V3; |
|||
public T V4; |
|||
public T V5; |
|||
public T V6; |
|||
public T V7; |
|||
|
|||
/// <inheritdoc/>
|
|||
public override readonly string ToString() |
|||
{ |
|||
return $"Octet<{typeof(T)}>({this.V0},{this.V1},{this.V2},{this.V3},{this.V4},{this.V5},{this.V6},{this.V7})"; |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Extension methods for the <see cref="Octet{T}"/> type.
|
|||
/// </summary>
|
|||
internal static class OctetExtensions |
|||
{ |
|||
/// <summary>
|
|||
/// Loads the fields in a target <see cref="Octet{T}"/> of <see cref="uint"/> from one of <see cref="byte"/> type.
|
|||
/// </summary>
|
|||
/// <param name="destination">The target <see cref="Octet{T}"/> of <see cref="uint"/> instance.</param>
|
|||
/// <param name="source">The source <see cref="Octet{T}"/> of <see cref="byte"/> instance.</param>
|
|||
[MethodImpl(InliningOptions.ShortMethod)] |
|||
public static void LoadFrom(ref this Octet<uint> destination, ref Octet<byte> source) |
|||
{ |
|||
destination.V0 = source.V0; |
|||
destination.V1 = source.V1; |
|||
destination.V2 = source.V2; |
|||
destination.V3 = source.V3; |
|||
destination.V4 = source.V4; |
|||
destination.V5 = source.V5; |
|||
destination.V6 = source.V6; |
|||
destination.V7 = source.V7; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Loads the fields in a target <see cref="Octet{T}"/> of <see cref="byte"/> from one of <see cref="uint"/> type.
|
|||
/// </summary>
|
|||
/// <param name="destination">The target <see cref="Octet{T}"/> of <see cref="byte"/> instance.</param>
|
|||
/// <param name="source">The source <see cref="Octet{T}"/> of <see cref="uint"/> instance.</param>
|
|||
[MethodImpl(InliningOptions.ShortMethod)] |
|||
public static void LoadFrom(ref this Octet<byte> destination, ref Octet<uint> source) |
|||
{ |
|||
destination.V0 = (byte)source.V0; |
|||
destination.V1 = (byte)source.V1; |
|||
destination.V2 = (byte)source.V2; |
|||
destination.V3 = (byte)source.V3; |
|||
destination.V4 = (byte)source.V4; |
|||
destination.V5 = (byte)source.V5; |
|||
destination.V6 = (byte)source.V6; |
|||
destination.V7 = (byte)source.V7; |
|||
} |
|||
} |
|||
@ -0,0 +1,122 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Six Labors Split License.
|
|||
|
|||
using System.Numerics; |
|||
using SixLabors.ImageSharp.ColorProfiles; |
|||
using SixLabors.ImageSharp.ColorProfiles.WorkingSpaces; |
|||
|
|||
namespace SixLabors.ImageSharp.Tests.ColorProfiles; |
|||
|
|||
/// <summary>
|
|||
/// Tests the <see cref="RgbWorkingSpace"/> class.
|
|||
/// </summary>
|
|||
[Trait("Color", "Conversion")] |
|||
public class RgbWorkingSpaceTests |
|||
{ |
|||
private static readonly ApproximateFloatComparer TolerantComparer = new(1e-5F); |
|||
|
|||
public static readonly TheoryData<RgbWorkingSpace> WorkingSpaces = new() |
|||
{ |
|||
KnownRgbWorkingSpaces.SRgb, |
|||
KnownRgbWorkingSpaces.SRgbSimplified, |
|||
KnownRgbWorkingSpaces.Rec709, |
|||
KnownRgbWorkingSpaces.Rec2020, |
|||
KnownRgbWorkingSpaces.ECIRgbv2, |
|||
KnownRgbWorkingSpaces.AdobeRgb1998, |
|||
KnownRgbWorkingSpaces.ApplesRgb, |
|||
KnownRgbWorkingSpaces.BestRgb, |
|||
KnownRgbWorkingSpaces.BetaRgb, |
|||
KnownRgbWorkingSpaces.BruceRgb, |
|||
KnownRgbWorkingSpaces.CIERgb, |
|||
KnownRgbWorkingSpaces.ColorMatchRgb, |
|||
KnownRgbWorkingSpaces.DonRgb4, |
|||
KnownRgbWorkingSpaces.EktaSpacePS5, |
|||
KnownRgbWorkingSpaces.NTSCRgb, |
|||
KnownRgbWorkingSpaces.PALSECAMRgb, |
|||
KnownRgbWorkingSpaces.ProPhotoRgb, |
|||
KnownRgbWorkingSpaces.SMPTECRgb, |
|||
KnownRgbWorkingSpaces.WideGamutRgb |
|||
}; |
|||
|
|||
[Fact] |
|||
public void RgbWorkingSpaceEqualityRequiresSameConcreteType() |
|||
{ |
|||
RgbWorkingSpace sRgb = KnownRgbWorkingSpaces.SRgb; |
|||
RgbWorkingSpace sRgbSimplified = KnownRgbWorkingSpaces.SRgbSimplified; |
|||
RgbWorkingSpace rec709 = KnownRgbWorkingSpaces.Rec709; |
|||
|
|||
Assert.False(sRgb.Equals(sRgbSimplified)); |
|||
Assert.False(sRgbSimplified.Equals(sRgb)); |
|||
Assert.False(sRgb.Equals(rec709)); |
|||
Assert.False(rec709.Equals(sRgb)); |
|||
|
|||
Assert.NotEqual(sRgb.GetHashCode(), sRgbSimplified.GetHashCode()); |
|||
Assert.NotEqual(sRgb.GetHashCode(), rec709.GetHashCode()); |
|||
} |
|||
|
|||
[Fact] |
|||
public void RgbWorkingSpaceEqualityMatchesSameConcreteTypeValues() |
|||
{ |
|||
RgbWorkingSpace x = new SRgbWorkingSpace( |
|||
KnownRgbWorkingSpaces.SRgb.WhitePoint, |
|||
KnownRgbWorkingSpaces.SRgb.ChromaticityCoordinates); |
|||
|
|||
RgbWorkingSpace y = new SRgbWorkingSpace( |
|||
KnownRgbWorkingSpaces.SRgb.WhitePoint, |
|||
KnownRgbWorkingSpaces.SRgb.ChromaticityCoordinates); |
|||
|
|||
Assert.Equal(x, y); |
|||
Assert.Equal(x.GetHashCode(), y.GetHashCode()); |
|||
} |
|||
|
|||
[Fact] |
|||
public void GammaWorkingSpaceEqualityIncludesGamma() |
|||
{ |
|||
GammaWorkingSpace x = new( |
|||
2.2F, |
|||
KnownRgbWorkingSpaces.SRgbSimplified.WhitePoint, |
|||
KnownRgbWorkingSpaces.SRgbSimplified.ChromaticityCoordinates); |
|||
|
|||
GammaWorkingSpace y = new( |
|||
1.8F, |
|||
KnownRgbWorkingSpaces.SRgbSimplified.WhitePoint, |
|||
KnownRgbWorkingSpaces.SRgbSimplified.ChromaticityCoordinates); |
|||
|
|||
Assert.NotEqual(x, y); |
|||
Assert.NotEqual(x.GetHashCode(), y.GetHashCode()); |
|||
} |
|||
|
|||
[Theory] |
|||
[MemberData(nameof(WorkingSpaces))] |
|||
public void CompressAndExpand_RoundTripsWithTolerance(RgbWorkingSpace workingSpace) |
|||
{ |
|||
Vector4[] linear = |
|||
[ |
|||
new(0F, .001F, .18F, 1F), // Endpoint, below the sRGB breakpoint, common middle gray, and opaque alpha.
|
|||
new(.0031308F, .25F, .5F, .75F), // sRGB linear/gamma breakpoint with interior values and partial alpha.
|
|||
new(.75F, .5F, .25F, .5F), // Reversed interior values ensure channel order does not hide errors.
|
|||
new(1F, .8F, .2F, .25F) // Upper endpoint, high/low interior values, and low alpha.
|
|||
]; |
|||
|
|||
Vector4[] expectedCompressed = new Vector4[linear.Length]; |
|||
|
|||
for (int i = 0; i < linear.Length; i++) |
|||
{ |
|||
Vector4 compressed = workingSpace.Compress(linear[i]); |
|||
Vector4 expanded = workingSpace.Expand(compressed); |
|||
|
|||
expectedCompressed[i] = compressed; |
|||
|
|||
Assert.Equal(linear[i], expanded, TolerantComparer); |
|||
} |
|||
|
|||
Vector4[] actualCompressed = linear.ToArray(); |
|||
workingSpace.Compress(actualCompressed); |
|||
|
|||
Assert.Equal(expectedCompressed, actualCompressed, TolerantComparer); |
|||
|
|||
workingSpace.Expand(actualCompressed); |
|||
|
|||
Assert.Equal(linear, actualCompressed, TolerantComparer); |
|||
} |
|||
} |
|||
Loading…
Reference in new issue