From 5f40590c884557b24222f3dae1b8b21c97999fb2 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Wed, 11 Jun 2025 14:04:11 +1000 Subject: [PATCH 1/2] Allow additional and undefined extra samples --- .../Formats/Tiff/TiffDecoderOptionsParser.cs | 20 ++++++++++--------- .../Formats/Tiff/TiffExtraSampleType.cs | 8 +++++++- .../Formats/Tiff/TiffDecoderTests.cs | 5 +++++ tests/ImageSharp.Tests/TestImages.cs | 1 + 4 files changed, 24 insertions(+), 10 deletions(-) diff --git a/src/ImageSharp/Formats/Tiff/TiffDecoderOptionsParser.cs b/src/ImageSharp/Formats/Tiff/TiffDecoderOptionsParser.cs index 5a5c2b3e51..db349b8b69 100644 --- a/src/ImageSharp/Formats/Tiff/TiffDecoderOptionsParser.cs +++ b/src/ImageSharp/Formats/Tiff/TiffDecoderOptionsParser.cs @@ -25,20 +25,22 @@ internal static class TiffDecoderOptionsParser /// True, if the image uses tiles. Otherwise the images has strip's. public static bool VerifyAndParse(this TiffDecoderCore options, ExifProfile exifProfile, TiffFrameMetadata frameMetadata) { - IExifValue extraSamplesExifValue = exifProfile.GetValueInternal(ExifTag.ExtraSamples); - if (extraSamplesExifValue is not null) + if (exifProfile.TryGetValue(ExifTag.ExtraSamples, out IExifValue samples)) { - short[] extraSamples = (short[])extraSamplesExifValue.GetValue(); - if (extraSamples.Length != 1) + // We only support a single sample pertaining to alpha data. + // Other information is discarded. + TiffExtraSampleType sampleType = (TiffExtraSampleType)samples.Value[0]; + if (sampleType is TiffExtraSampleType.CorelDrawUnassociatedAlphaData) { - TiffThrowHelper.ThrowNotSupported("ExtraSamples is only supported with one extra sample for alpha data."); + // According to libtiff, this CorelDRAW-specific value indicates unassociated alpha. + // Patch required for compatibility with malformed CorelDRAW-generated TIFFs. + // https://libtiff.gitlab.io/libtiff/releases/v3.9.0beta.html + sampleType = TiffExtraSampleType.UnassociatedAlphaData; } - TiffExtraSampleType extraSamplesType = (TiffExtraSampleType)extraSamples[0]; - options.ExtraSamplesType = extraSamplesType; - if (extraSamplesType is not (TiffExtraSampleType.UnassociatedAlphaData or TiffExtraSampleType.AssociatedAlphaData)) + if (sampleType is (TiffExtraSampleType.UnassociatedAlphaData or TiffExtraSampleType.AssociatedAlphaData)) { - TiffThrowHelper.ThrowNotSupported("Decoding Tiff images with ExtraSamples is not supported with UnspecifiedData."); + options.ExtraSamplesType = sampleType; } } diff --git a/src/ImageSharp/Formats/Tiff/TiffExtraSampleType.cs b/src/ImageSharp/Formats/Tiff/TiffExtraSampleType.cs index 484fc993b0..72d56e2c38 100644 --- a/src/ImageSharp/Formats/Tiff/TiffExtraSampleType.cs +++ b/src/ImageSharp/Formats/Tiff/TiffExtraSampleType.cs @@ -22,5 +22,11 @@ internal enum TiffExtraSampleType /// The extra data is unassociated alpha data is transparency information that logically exists independent of an image; /// it is commonly called a soft matte. /// - UnassociatedAlphaData = 2 + UnassociatedAlphaData = 2, + + /// + /// A CorelDRAW-specific value observed in damaged files, indicating unassociated alpha. + /// Not part of the official TIFF specification; patched in ImageSharp for compatibility. + /// + CorelDrawUnassociatedAlphaData = 999 } diff --git a/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs index 839334449d..d66a8def41 100644 --- a/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs @@ -772,4 +772,9 @@ public void TiffDecoder_Decode_Resize(TestImageProvider provider testOutputDetails: details, appendPixelTypeToFileName: false); } + + [Theory] + [WithFile(ExtraSamplesUnspecified, PixelTypes.Rgba32)] + public void TiffDecoder_CanDecode_ExtraSamplesUnspecified(TestImageProvider provider) + where TPixel : unmanaged, IPixel => TestTiffDecoder(provider); } diff --git a/tests/ImageSharp.Tests/TestImages.cs b/tests/ImageSharp.Tests/TestImages.cs index 5a7c2e66ea..6021de15cc 100644 --- a/tests/ImageSharp.Tests/TestImages.cs +++ b/tests/ImageSharp.Tests/TestImages.cs @@ -1112,6 +1112,7 @@ public static class Tiff public const string Issues2587 = "Tiff/Issues/Issue2587.tiff"; public const string JpegCompressedGray0000539558 = "Tiff/Issues/JpegCompressedGray-0000539558.tiff"; public const string Tiled0000023664 = "Tiff/Issues/tiled-0000023664.tiff"; + public const string ExtraSamplesUnspecified = "Tiff/Issues/ExtraSamplesUnspecified.tif"; public const string SmallRgbDeflate = "Tiff/rgb_small_deflate.tiff"; public const string SmallRgbLzw = "Tiff/rgb_small_lzw.tiff"; From 379cc6289151f5f3b7f6833526a0261d568c2895 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Wed, 11 Jun 2025 14:33:35 +1000 Subject: [PATCH 2/2] Create ExtraSamplesUnspecified.tif --- tests/Images/Input/Tiff/Issues/ExtraSamplesUnspecified.tif | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 tests/Images/Input/Tiff/Issues/ExtraSamplesUnspecified.tif diff --git a/tests/Images/Input/Tiff/Issues/ExtraSamplesUnspecified.tif b/tests/Images/Input/Tiff/Issues/ExtraSamplesUnspecified.tif new file mode 100644 index 0000000000..b5835c1ed8 --- /dev/null +++ b/tests/Images/Input/Tiff/Issues/ExtraSamplesUnspecified.tif @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:71d28f17d2d56481faa4d241fae882eae4f8303c70f85bc3759f6a0c2074979e +size 1426558