Browse Source

Fix CMYK to RGB using TRCs

pull/1567/head
Wacton 1 year ago
parent
commit
369bf5ff82
  1. 6
      src/ImageSharp/ColorProfiles/ColorProfileConverterExtensionsIcc.cs
  2. 7
      src/ImageSharp/ColorProfiles/Icc/Calculators/ColorTrcCalculator.cs
  3. 9
      tests/ImageSharp.Tests/ColorProfiles/Icc/ColorProfileConverterTests.Icc.cs

6
src/ImageSharp/ColorProfiles/ColorProfileConverterExtensionsIcc.cs

@ -189,6 +189,9 @@ internal static class ColorProfileConverterExtensionsIcc
sourcePcs = sourceParams.Is16BitLutEntry ? LabV2ToLab(sourcePcs) : sourcePcs;
CieLab lab = CieLab.FromScaledVector4(sourcePcs);
CieXyz xyz = pcsConverter.Convert<CieLab, CieXyz>(in lab);
// DemoMaxICC clips negatives as part of IccUtil.cpp : icLabToXYZ > icICubeth
xyz = new CieXyz(Vector3.Clamp(xyz.ToVector3(), Vector3.Zero, new Vector3(float.MaxValue, float.MaxValue, float.MaxValue)));
return xyz.ToScaledVector4();
}
@ -258,6 +261,9 @@ internal static class ColorProfileConverterExtensionsIcc
sourcePcs = sourceParams.Is16BitLutEntry ? LabV2ToLab(sourcePcs) : sourcePcs;
CieLab lab = CieLab.FromScaledVector4(sourcePcs);
xyz = pcsConverter.Convert<CieLab, CieXyz>(in lab);
// DemoMaxICC clips negatives as part of IccUtil.cpp : icLabToXYZ > icICubeth
xyz = new CieXyz(Vector3.Clamp(xyz.ToVector3(), Vector3.Zero, new Vector3(float.MaxValue, float.MaxValue, float.MaxValue)));
break;
case IccColorSpaceType.CieXyz:
xyz = CieXyz.FromScaledVector4(sourcePcs);

7
src/ImageSharp/ColorProfiles/Icc/Calculators/ColorTrcCalculator.cs

@ -39,13 +39,16 @@ internal class ColorTrcCalculator : IVector4Calculator
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Vector4 Calculate(Vector4 value)
{
// uses the descaled XYZ as DemoMaxICC IccCmm.cpp : CIccXformMatrixTRC::Apply()
Vector4 xyz = new(CieXyz.FromScaledVector4(value).ToVector3(), 1);
if (this.toPcs)
{
value = this.curveCalculator.Calculate(value);
value = this.curveCalculator.Calculate(xyz);
return Vector4.Transform(value, this.matrix);
}
value = Vector4.Transform(value, this.matrix);
value = Vector4.Transform(xyz, this.matrix);
return this.curveCalculator.Calculate(value);
}
}

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

@ -80,9 +80,12 @@ public class ColorProfileConverterTests
Rgb actualRgb = converter.Convert<Cmyk, Rgb>(new Cmyk(new Vector4(input)));
Assert.Equal(expectedR, actualRgb.R);
Assert.Equal(expectedG, actualRgb.G);
Assert.Equal(expectedB, actualRgb.B);
// TODO: investigate lower tolerance than CanConvertCmykIccProfiles()
// currently assuming it's a rounding error in the process of gathering test data manually
const double tolerance = 0.0005;
Assert.Equal(expectedR, actualRgb.R, tolerance);
Assert.Equal(expectedG, actualRgb.G, tolerance);
Assert.Equal(expectedB, actualRgb.B, tolerance);
}
private static double[] GetExpectedTargetValues(string sourceProfile, string targetProfile, float[] input)

Loading…
Cancel
Save