diff --git a/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.Icc.cs b/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.Icc.cs index 25632212c6..a69e0b21cd 100644 --- a/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.Icc.cs +++ b/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.Icc.cs @@ -22,6 +22,40 @@ public partial class PngDecoderTests Assert.Throws(() => Image.Load(options, pngData)); } + /// + /// Three-channel LUT conversion remains supported. + /// + [Fact] + public void Decode_IccLutWithSupportedChannelCount_ConvertsPixels() + { + byte[] pngData = BuildPng(BuildLut16Profile(3, 3, 2, 2, 2)); + DecoderOptions options = new() { ColorProfileHandling = ColorProfileHandling.Convert }; + + using Image image = Image.Load(options, pngData); + Assert.Equal(new Size(16, 16), image.Size); + + // Every CLUT node contains a nonzero XYZ value, even though the encoded pixels are black. + Assert.NotEqual(default(Rgb24), image[0, 0]); + } + + /// + /// Preserving a profile does not impose the converter's four-component storage limit on the parser. + /// + /// The number of output channels in the LUT. + [Theory] + [InlineData(3)] + [InlineData(15)] + public void Decode_IccLut_Preserve_RetainsChannels(int outputChannels) + { + byte[] pngData = BuildPng(BuildLut16Profile(3, outputChannels, 2, 2, 2)); + DecoderOptions options = new() { ColorProfileHandling = ColorProfileHandling.Preserve }; + + using Image image = Image.Load(options, pngData); + IccLut16TagDataEntry entry = Assert.IsType(Assert.Single(image.Metadata.IccProfile.Entries)); + Assert.Equal(outputChannels, entry.OutputValues.Length); + Assert.Equal(default(Rgb24), image[0, 0]); + } + private static byte[] BuildLut16Profile(int inputChannels, int outputChannels, int clutPoints, int inputTableLength, int outputTableLength) { using MemoryStream stream = new(); diff --git a/tests/ImageSharp.Tests/Metadata/Profiles/ICC/DataReader/IccDataReaderLutTests.cs b/tests/ImageSharp.Tests/Metadata/Profiles/ICC/DataReader/IccDataReaderLutTests.cs index 055756e96b..530da5594b 100644 --- a/tests/ImageSharp.Tests/Metadata/Profiles/ICC/DataReader/IccDataReaderLutTests.cs +++ b/tests/ImageSharp.Tests/Metadata/Profiles/ICC/DataReader/IccDataReaderLutTests.cs @@ -63,6 +63,26 @@ public class IccDataReaderLutTests Assert.Throws(() => CreateReader(new byte[8]).ReadClutF32(15, 15, gridPointCount)); } + /// + /// A complete profile header and element table do not make absent CLUT values readable. + /// + [Fact] + public void ReadTagDataEntry_WithTruncatedClut_RejectsMissingValues() + { + // A2B0 starts at byte 144; its element at byte 168 declares a 15-channel, three-point grid. + byte[] data = Convert.FromHexString( + "000000C874657374040000006D6E74725247422058595A200000000000000000000000006163737000000000000000000000" + + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + + "00000000000000000000000000000000000000000000000000000000000000014132423000000090000000386D7065740000" + + "000000000000000000010000001800000020636C7574000F000F030303030303030303030303030303000000000000000000"); + + IccDataReader reader = new(data); + IccTagTableEntry tag = new(IccProfileTag.AToB0, 144, 56); + + Assert.Throws(() => reader.ReadTagDataEntry(tag)); + Assert.Empty(new IccProfile(data).Entries); + } + [Theory] [MemberData(nameof(IccTestDataLut.Lut8TestData), MemberType = typeof(IccTestDataLut))] internal void ReadLut8(byte[] data, IccLut expected)