Browse Source

Cover complete ICC CLUT payload and conversion controls

pull/3187/head
James Jackson-South 3 weeks ago
parent
commit
4b73eaad10
  1. 34
      tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.Icc.cs
  2. 20
      tests/ImageSharp.Tests/Metadata/Profiles/ICC/DataReader/IccDataReaderLutTests.cs

34
tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.Icc.cs

@ -22,6 +22,40 @@ public partial class PngDecoderTests
Assert.Throws<InvalidIccProfileException>(() => Image.Load(options, pngData)); Assert.Throws<InvalidIccProfileException>(() => Image.Load(options, pngData));
} }
/// <summary>
/// Three-channel LUT conversion remains supported.
/// </summary>
[Fact]
public void Decode_IccLutWithSupportedChannelCount_ConvertsPixels()
{
byte[] pngData = BuildPng(BuildLut16Profile(3, 3, 2, 2, 2));
DecoderOptions options = new() { ColorProfileHandling = ColorProfileHandling.Convert };
using Image<Rgb24> image = Image.Load<Rgb24>(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]);
}
/// <summary>
/// Preserving a profile does not impose the converter's four-component storage limit on the parser.
/// </summary>
/// <param name="outputChannels">The number of output channels in the LUT.</param>
[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<Rgb24> image = Image.Load<Rgb24>(options, pngData);
IccLut16TagDataEntry entry = Assert.IsType<IccLut16TagDataEntry>(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) private static byte[] BuildLut16Profile(int inputChannels, int outputChannels, int clutPoints, int inputTableLength, int outputTableLength)
{ {
using MemoryStream stream = new(); using MemoryStream stream = new();

20
tests/ImageSharp.Tests/Metadata/Profiles/ICC/DataReader/IccDataReaderLutTests.cs

@ -63,6 +63,26 @@ public class IccDataReaderLutTests
Assert.Throws<InvalidIccProfileException>(() => CreateReader(new byte[8]).ReadClutF32(15, 15, gridPointCount)); Assert.Throws<InvalidIccProfileException>(() => CreateReader(new byte[8]).ReadClutF32(15, 15, gridPointCount));
} }
/// <summary>
/// A complete profile header and element table do not make absent CLUT values readable.
/// </summary>
[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<InvalidIccProfileException>(() => reader.ReadTagDataEntry(tag));
Assert.Empty(new IccProfile(data).Entries);
}
[Theory] [Theory]
[MemberData(nameof(IccTestDataLut.Lut8TestData), MemberType = typeof(IccTestDataLut))] [MemberData(nameof(IccTestDataLut.Lut8TestData), MemberType = typeof(IccTestDataLut))]
internal void ReadLut8(byte[] data, IccLut expected) internal void ReadLut8(byte[] data, IccLut expected)

Loading…
Cancel
Save