mirror of https://github.com/SixLabors/ImageSharp
7 changed files with 114 additions and 78 deletions
@ -1 +1 @@ |
|||||
Subproject commit 1dbfb576c83507645265c79e03369b66cdc0379f |
Subproject commit 5e13cde851a3d6e95d0dfdde2a57071f1efda9c3 |
||||
@ -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); |
||||
|
} |
||||
|
} |
||||
@ -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)); |
||||
|
} |
||||
Loading…
Reference in new issue