Browse Source

Migrate tests

pull/1567/head
James Jackson-South 1 year ago
parent
commit
fd2e8a90ad
  1. 12
      .editorconfig
  2. 7
      .gitattributes
  3. 2
      shared-infrastructure
  4. 63
      tests/ImageSharp.Tests/ColorProfiles/Icc/ColorProfileConverterTests.Icc.cs
  5. 35
      tests/ImageSharp.Tests/ColorProfiles/Icc/TestIccProfiles.cs
  6. 7
      tests/ImageSharp.Tests/ImageSharp.Tests.csproj
  7. 66
      tests/ImageSharp.Tests/Metadata/Profiles/ICC/IccProfileTests.cs

12
.editorconfig

@ -104,8 +104,8 @@ dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity:war
dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:warning
dotnet_style_parentheses_in_other_operators = always_for_clarity:suggestion
# Expression-level preferences
dotnet_style_object_initializer = true:warning
dotnet_style_collection_initializer = true:warning
dotnet_style_object_initializer = true:error
dotnet_style_collection_initializer = true:error
dotnet_style_explicit_tuple_names = true:warning
dotnet_style_prefer_inferred_tuple_names = true:warning
dotnet_style_prefer_inferred_anonymous_type_member_names = true:warning
@ -135,9 +135,9 @@ csharp_style_prefer_null_check_over_type_check = true:warning
# https://docs.microsoft.com/dotnet/fundamentals/code-analysis/style-rules/language-rules#c-style-rules
[*.{cs,csx,cake}]
# 'var' preferences
csharp_style_var_for_built_in_types = false:warning
csharp_style_var_when_type_is_apparent = false:warning
csharp_style_var_elsewhere = false:warning
csharp_style_var_for_built_in_types = false:error
csharp_style_var_when_type_is_apparent = false:error
csharp_style_var_elsewhere = false:error
# Expression-bodied members
csharp_style_expression_bodied_methods = true:warning
csharp_style_expression_bodied_constructors = true:warning
@ -160,7 +160,7 @@ csharp_style_pattern_local_over_anonymous_function = true:warning
csharp_style_deconstructed_variable_declaration = true:warning
csharp_style_prefer_index_operator = true:warning
csharp_style_prefer_range_operator = true:warning
csharp_style_implicit_object_creation_when_type_is_apparent = true:warning
csharp_style_implicit_object_creation_when_type_is_apparent = true:error
# "Null" checking preferences
csharp_style_throw_expression = true:warning
csharp_style_conditional_delegate_call = true:warning

7
.gitattributes

@ -136,3 +136,10 @@
*.ico filter=lfs diff=lfs merge=lfs -text
*.cur filter=lfs diff=lfs merge=lfs -text
*.ani filter=lfs diff=lfs merge=lfs -text
*.heic filter=lfs diff=lfs merge=lfs -text
*.hif filter=lfs diff=lfs merge=lfs -text
*.avif filter=lfs diff=lfs merge=lfs -text
###############################################################################
# Handle ICC files by git lfs
###############################################################################
*.icc filter=lfs diff=lfs merge=lfs -text

2
shared-infrastructure

@ -1 +1 @@
Subproject commit 1dbfb576c83507645265c79e03369b66cdc0379f
Subproject commit 5e13cde851a3d6e95d0dfdde2a57071f1efda9c3

63
tests/ImageSharp.Tests/ColorProfiles/Icc/ColorProfileConverterTests.Icc.cs

@ -0,0 +1,63 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using SixLabors.ImageSharp.ColorProfiles;
using Wacton.Unicolour;
using Wacton.Unicolour.Icc;
namespace SixLabors.ImageSharp.Tests.ColorProfiles.Icc;
public class ColorProfileConverterTests
{
[Theory]
[InlineData(TestIccProfiles.Fogra39, TestIccProfiles.Fogra39)]
[InlineData(TestIccProfiles.Fogra39, TestIccProfiles.Swop2006)]
[InlineData(TestIccProfiles.Swop2006, TestIccProfiles.Fogra39)]
[InlineData(TestIccProfiles.Swop2006, TestIccProfiles.Swop2006)]
public void CanConvertCmykIccProfiles(string sourceProfileName, string targetProfileName)
{
Cmyk input = new(GetNormalizedRandomValue(), GetNormalizedRandomValue(), GetNormalizedRandomValue(), GetNormalizedRandomValue());
ColorProfileConverter converter = new(new ColorConversionOptions
{
SourceIccProfile = TestIccProfiles.GetProfile(sourceProfileName),
TargetIccProfile = TestIccProfiles.GetProfile(targetProfileName),
});
Cmyk expectedTargetValues = GetExpectedTargetCmyk(sourceProfileName, targetProfileName, input);
Cmyk actualTargetValues = converter.Convert<Cmyk, Cmyk>(input);
const double tolerance = 0.0000005;
Assert.Equal(expectedTargetValues.C, actualTargetValues.C, tolerance);
Assert.Equal(expectedTargetValues.M, actualTargetValues.M, tolerance);
Assert.Equal(expectedTargetValues.Y, actualTargetValues.Y, tolerance);
Assert.Equal(expectedTargetValues.K, actualTargetValues.K, tolerance);
}
private static Cmyk GetExpectedTargetCmyk(string sourceProfileName, string targetProfileName, Cmyk sourceCmyk)
{
Wacton.Unicolour.Configuration sourceConfig = TestIccProfiles.GetUnicolourConfiguration(sourceProfileName);
Wacton.Unicolour.Configuration targetConfig = TestIccProfiles.GetUnicolourConfiguration(targetProfileName);
Channels channels = new(sourceCmyk.C, sourceCmyk.M, sourceCmyk.Y, sourceCmyk.K);
Unicolour source = new(sourceConfig, channels);
ColourSpace pcs = sourceConfig.Icc.Profile!.Header.Pcs == "Lab " ? ColourSpace.Lab : ColourSpace.Xyz;
ColourTriplet pcsTriplet = pcs == ColourSpace.Lab ? source.Lab.Triplet : source.Xyz.Triplet;
Unicolour target = new(targetConfig, pcs, pcsTriplet.Tuple);
double[] targetCmyk = target.Icc.Values;
return new Cmyk((float)targetCmyk[0], (float)targetCmyk[1], (float)targetCmyk[2], (float)targetCmyk[3]);
}
private static float GetNormalizedRandomValue()
{
// Generate a random value between 0 (inclusive) and 1 (exclusive).
double value = Random.Shared.NextDouble();
// If the random value is exactly 0, return 0F to ensure inclusivity at the lower bound.
// For non-zero values, add a small increment (0.0000001F) to ensure the range
// is inclusive at the upper bound while retaining precision.
// Clamp the result between 0 and 1 to ensure it does not exceed the bounds.
return value == 0 ? 0F : Math.Clamp((float)value + 0.0000001F, 0, 1);
}
}

35
tests/ImageSharp.Tests/ColorProfiles/Icc/TestIccProfiles.cs

@ -0,0 +1,35 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Collections.Concurrent;
using SixLabors.ImageSharp.Metadata.Profiles.Icc;
using Wacton.Unicolour.Icc;
namespace SixLabors.ImageSharp.Tests.ColorProfiles.Icc;
internal static class TestIccProfiles
{
private static readonly ConcurrentDictionary<string, IccProfile> ProfileCache = new();
private static readonly ConcurrentDictionary<string, Wacton.Unicolour.Configuration> UnicolourConfigurationCache = new();
public const string Fogra39 = "Coated_Fogra39L_VIGC_300.icc";
public const string Swop2006 = "SWOP2006_Coated5v2.icc";
public static IccProfile GetProfile(string file)
=> ProfileCache.GetOrAdd(file, f => new IccProfile(File.ReadAllBytes(GetFullPath(f))));
public static Wacton.Unicolour.Configuration GetUnicolourConfiguration(string file)
=> UnicolourConfigurationCache.GetOrAdd(
file,
f =>
{
string p = GetFullPath(f);
bool b = File.Exists(p);
var profile = new Profile(p);
return new Wacton.Unicolour.Configuration(iccConfiguration: new(GetFullPath(f), Intent.Unspecified));
});
private static string GetFullPath(string file)
=> Path.GetFullPath(Path.Combine(".", "TestDataIcc", "Profiles", file));
}

7
tests/ImageSharp.Tests/ImageSharp.Tests.csproj

@ -32,11 +32,8 @@
<AutoGen>True</AutoGen>
<DependentUpon>PixelOperationsTests.Specialized.Generated.tt</DependentUpon>
</None>
<None Update="TestDataIcc\Profiles\Coated_Fogra39L_VIGC_300.icc">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="TestDataIcc\Profiles\SWOP2006_Coated5v2.icc">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
<None Update="TestDataIcc\Profiles\*">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>

66
tests/ImageSharp.Tests/Metadata/Profiles/ICC/IccProfileTests.cs

@ -1,11 +1,8 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using SixLabors.ImageSharp.ColorProfiles;
using SixLabors.ImageSharp.Metadata.Profiles.Icc;
using SixLabors.ImageSharp.Tests.TestDataIcc;
using Wacton.Unicolour;
using Wacton.Unicolour.Icc;
namespace SixLabors.ImageSharp.Tests.Metadata.Profiles.Icc;
@ -43,67 +40,4 @@ public class IccProfileTests
Assert.Equal(expected, result);
}
private const string Fogra39 = "Coated_Fogra39L_VIGC_300.icc";
private const string Swop2006 = "SWOP2006_Coated5v2.icc";
[Theory]
[InlineData(Fogra39, Fogra39)]
[InlineData(Fogra39, Swop2006)]
[InlineData(Swop2006, Fogra39)]
[InlineData(Swop2006, Swop2006)]
public void UnicolourComparison(string sourceProfileName, string targetProfileName)
{
string sourceIccFilepath = Path.Combine(".", "TestDataIcc", "Profiles", sourceProfileName);
string targetIccFilepath = Path.Combine(".", "TestDataIcc", "Profiles", targetProfileName);
// TODO: pass in specific values to test? use random values?
Cmyk input = new(0.8f, 0.6f, 0.4f, 0.2f);
Cmyk expectedTargetValues = GetExpectedTargetCmyk(sourceIccFilepath, targetIccFilepath, input);
ColorProfileConverter converter = new(new ColorConversionOptions
{
SourceIccProfile = new IccProfile(File.ReadAllBytes(sourceIccFilepath)),
TargetIccProfile = new IccProfile(File.ReadAllBytes(targetIccFilepath))
});
Cmyk actualTargetValues = converter.Convert<Cmyk, Cmyk>(input);
const double tolerance = 0.0000005;
Assert.Equal(expectedTargetValues.C, actualTargetValues.C, tolerance);
Assert.Equal(expectedTargetValues.M, actualTargetValues.M, tolerance);
Assert.Equal(expectedTargetValues.Y, actualTargetValues.Y, tolerance);
Assert.Equal(expectedTargetValues.K, actualTargetValues.K, tolerance);
}
private static Cmyk GetExpectedTargetCmyk(string sourceIccFilepath, string targetIccFilepath, Cmyk sourceCmyk)
{
Wacton.Unicolour.Configuration sourceConfig = GetUnicolourConfig(sourceIccFilepath);
Wacton.Unicolour.Configuration targetConfig = GetUnicolourConfig(targetIccFilepath);
Channels channels = new(sourceCmyk.C, sourceCmyk.M, sourceCmyk.Y, sourceCmyk.K);
Unicolour source = new(sourceConfig, channels);
ColourSpace pcs = sourceConfig.Icc.Profile!.Header.Pcs == "Lab " ? ColourSpace.Lab : ColourSpace.Xyz;
ColourTriplet pcsTriplet = pcs == ColourSpace.Lab ? source.Lab.Triplet : source.Xyz.Triplet;
Unicolour target = new(targetConfig, pcs, pcsTriplet.Tuple);
double[] targetCmyk = target.Icc.Values;
return new Cmyk((float)targetCmyk[0], (float)targetCmyk[1], (float)targetCmyk[2], (float)targetCmyk[3]);
}
// Unicolour configurations are relatively expensive to instantiate
private static readonly Dictionary<string, Wacton.Unicolour.Configuration> UnicolourConfigCache = new();
private static Wacton.Unicolour.Configuration GetUnicolourConfig(string iccFilepath)
{
Wacton.Unicolour.Configuration config;
if (UnicolourConfigCache.TryGetValue(iccFilepath, out config))
{
return config;
}
config = new Wacton.Unicolour.Configuration(iccConfiguration: new(iccFilepath, Intent.Unspecified));
UnicolourConfigCache.Add(iccFilepath, config);
return config;
}
}

Loading…
Cancel
Save