diff --git a/src/ImageSharp/ColorProfiles/ColorProfileConverterExtensionsIcc.cs b/src/ImageSharp/ColorProfiles/ColorProfileConverterExtensionsIcc.cs index b19133789..7e954bdf1 100644 --- a/src/ImageSharp/ColorProfiles/ColorProfileConverterExtensionsIcc.cs +++ b/src/ImageSharp/ColorProfiles/ColorProfileConverterExtensionsIcc.cs @@ -39,6 +39,7 @@ internal static class ColorProfileConverterExtensionsIcc TargetWhitePoint = new CieXyz(converter.Options.TargetIccProfile.Header.PcsIlluminant), }); + // output of Matrix TRC calculator is descaled XYZ, needs to be re-scaled to be used as PCS Vector4 sourcePcs = sourceParams.Converter.Calculate(source.ToScaledVector4()); Vector4 targetPcs; @@ -56,6 +57,7 @@ internal static class ColorProfileConverterExtensionsIcc } // Convert to the target space. + // input to Matrix TRC calculator is descaled XYZ, need to descale PCS before use return TTo.FromScaledVector4(targetParams.Converter.Calculate(targetPcs)); } diff --git a/src/ImageSharp/ColorProfiles/Icc/Calculators/LutEntryCalculator.cs b/src/ImageSharp/ColorProfiles/Icc/Calculators/LutEntryCalculator.cs index c52aeefa4..c97578ee3 100644 --- a/src/ImageSharp/ColorProfiles/Icc/Calculators/LutEntryCalculator.cs +++ b/src/ImageSharp/ColorProfiles/Icc/Calculators/LutEntryCalculator.cs @@ -37,7 +37,7 @@ internal class LutEntryCalculator : IVector4Calculator { if (this.doTransform) { - value = Vector4.Transform(value, Matrix4x4.Transpose(this.matrix)); + value = Vector4.Transform(value, this.matrix); } value = CalculateLut(this.inputCurve, value); diff --git a/tests/ImageSharp.Tests/TestDataIcc/Conversion/IccConversionDataLutEntry.cs b/tests/ImageSharp.Tests/TestDataIcc/Conversion/IccConversionDataLutEntry.cs index 03ce06efd..40f54ea74 100644 --- a/tests/ImageSharp.Tests/TestDataIcc/Conversion/IccConversionDataLutEntry.cs +++ b/tests/ImageSharp.Tests/TestDataIcc/Conversion/IccConversionDataLutEntry.cs @@ -12,27 +12,37 @@ public class IccConversionDataLutEntry private static readonly IccLut Lut32 = CreateLut(32); private static readonly IccLut LutIdentity = CreateIdentityLut(0, 1); + // test cases were originally calculated unaware that + // IccConversionDataMatrix.Matrix3x3Random is actually the row-major transposed matrix + // of the typical column-major matrix + public static float[,] TestMatrix = + { + { 0.1f, 0.4f, 0.7f }, + { 0.2f, 0.5f, 0.8f }, + { 0.3f, 0.6f, 0.9f } + }; + private static readonly IccLut8TagDataEntry Lut8 = new( - new[] { Lut256, Lut256 }, + [Lut256, Lut256], IccConversionDataClut.Clut2x1, - new[] { Lut256 }); + [Lut256]); private static readonly IccLut16TagDataEntry Lut16 = new( - new[] { Lut32, Lut32 }, + [Lut32, Lut32], IccConversionDataClut.Clut2x1, - new[] { LutIdentity }); + [LutIdentity]); private static readonly IccLut8TagDataEntry Lut8Matrix = new( - IccConversionDataMatrix.Matrix3x3Random, - new[] { Lut256, Lut256, Lut256 }, + TestMatrix, + [Lut256, Lut256, Lut256], IccConversionDataClut.Clut3x1, - new[] { Lut256 }); + [Lut256]); private static readonly IccLut16TagDataEntry Lut16Matrix = new( - IccConversionDataMatrix.Matrix3x3Random, - new[] { Lut32, Lut32, Lut32 }, + TestMatrix, + [Lut32, Lut32, Lut32], IccConversionDataClut.Clut3x1, - new[] { LutIdentity }); + [LutIdentity]); private static IccLut CreateLut(int length) { @@ -45,17 +55,17 @@ public class IccConversionDataLutEntry return new IccLut(values); } - private static IccLut CreateIdentityLut(float min, float max) => new(new[] { min, max }); + private static IccLut CreateIdentityLut(float min, float max) => new([min, max]); public static object[][] Lut8ConversionTestData = - { - new object[] { Lut8, new Vector4(0.2f, 0.3f, 0, 0), new Vector4(0.4578933760499877f, 0, 0, 0) }, - new object[] { Lut8Matrix, new Vector4(0.21f, 0.31f, 0.41f, 0), new Vector4(0.40099657491875312f, 0, 0, 0) }, - }; + [ + [Lut8, new Vector4(0.2f, 0.3f, 0, 0), new Vector4(0.4578933760499877f, 0, 0, 0)], + [Lut8Matrix, new Vector4(0.21f, 0.31f, 0.41f, 0), new Vector4(0.40099657491875312f, 0, 0, 0)] + ]; public static object[][] Lut16ConversionTestData = - { - new object[] { Lut16, new Vector4(0.2f, 0.3f, 0, 0), new Vector4(0.3543750030529918f, 0, 0, 0) }, - new object[] { Lut16Matrix, new Vector4(0.21f, 0.31f, 0.41f, 0), new Vector4(0.29739562389689594f, 0, 0, 0) }, - }; + [ + [Lut16, new Vector4(0.2f, 0.3f, 0, 0), new Vector4(0.3543750030529918f, 0, 0, 0)], + [Lut16Matrix, new Vector4(0.21f, 0.31f, 0.41f, 0), new Vector4(0.29739562389689594f, 0, 0, 0)] + ]; }