diff --git a/src/ImageSharp/Formats/Tiff/TiffDecoderOptionsParser.cs b/src/ImageSharp/Formats/Tiff/TiffDecoderOptionsParser.cs index 26905965ee..5a5c2b3e51 100644 --- a/src/ImageSharp/Formats/Tiff/TiffDecoderOptionsParser.cs +++ b/src/ImageSharp/Formats/Tiff/TiffDecoderOptionsParser.cs @@ -139,8 +139,8 @@ public static bool VerifyAndParse(this TiffDecoderCore options, ExifProfile exif options.OldJpegCompressionStartOfImageMarker = jpegInterchangeFormatValue.Value; } - options.ParseColorType(exifProfile); options.ParseCompression(frameMetadata.Compression, exifProfile); + options.ParseColorType(exifProfile); bool isTiled = VerifyRequiredFieldsArePresent(exifProfile, frameMetadata, options.PlanarConfiguration); @@ -194,7 +194,9 @@ private static bool VerifyRequiredFieldsArePresent(ExifProfile exifProfile, Tiff } } - if (frameMetadata.BitsPerPixel == null) + // For BiColor compressed images, the BitsPerPixel value will be set explicitly to 1, so we don't throw in those cases. + // See: https://github.com/SixLabors/ImageSharp/issues/2587 + if (frameMetadata.BitsPerPixel == null && !IsBiColorCompression(frameMetadata.Compression)) { TiffThrowHelper.ThrowNotSupported("The TIFF BitsPerSample entry is missing which is required to decode the image!"); } @@ -570,6 +572,11 @@ private static void ParseCompression(this TiffDecoderCore options, TiffCompressi options.FaxCompressionOptions = FaxCompressionOptions.None; } + // Some encoders do not set the BitsPerSample correctly, so we set those values here to the required values: + // https://github.com/SixLabors/ImageSharp/issues/2587 + options.BitsPerSample = new TiffBitsPerSample(1, 0, 0); + options.BitsPerPixel = 1; + break; } @@ -585,12 +592,18 @@ private static void ParseCompression(this TiffDecoderCore options, TiffCompressi options.FaxCompressionOptions = FaxCompressionOptions.None; } + options.BitsPerSample = new TiffBitsPerSample(1, 0, 0); + options.BitsPerPixel = 1; + break; } case TiffCompression.Ccitt1D: { options.CompressionType = TiffDecoderCompressionType.HuffmanRle; + options.BitsPerSample = new TiffBitsPerSample(1, 0, 0); + options.BitsPerPixel = 1; + break; } @@ -645,4 +658,15 @@ private static void ParseCompression(this TiffDecoderCore options, TiffCompressi } } } + + private static bool IsBiColorCompression(TiffCompression? compression) + { + if (compression is TiffCompression.Ccitt1D or TiffCompression.CcittGroup3Fax or + TiffCompression.CcittGroup4Fax) + { + return true; + } + + return false; + } } diff --git a/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs index decc0069a5..ab49805a35 100644 --- a/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs @@ -665,6 +665,12 @@ public void TiffDecoder_CanDecode_Fax4CompressedWithStrips(TestImageProv public void TiffDecoder_CanDecode_TiledWithNonEqualWidthAndHeight(TestImageProvider provider) where TPixel : unmanaged, IPixel => TestTiffDecoder(provider); + // https://github.com/SixLabors/ImageSharp/issues/2587 + [Theory] + [WithFile(Issues2587, PixelTypes.Rgba32)] + public void TiffDecoder_CanDecode_BiColorWithMissingBitsPerSample(TestImageProvider provider) + where TPixel : unmanaged, IPixel => TestTiffDecoder(provider); + [Theory] [WithFile(JpegCompressedGray0000539558, PixelTypes.Rgba32)] public void TiffDecoder_ThrowsException_WithCircular_IFD_Offsets(TestImageProvider provider) diff --git a/tests/ImageSharp.Tests/TestImages.cs b/tests/ImageSharp.Tests/TestImages.cs index 6ad93adfbd..1675580c02 100644 --- a/tests/ImageSharp.Tests/TestImages.cs +++ b/tests/ImageSharp.Tests/TestImages.cs @@ -992,6 +992,7 @@ public static class Tiff public const string Issues2149 = "Tiff/Issues/Group4CompressionWithStrips.tiff"; public const string Issues2255 = "Tiff/Issues/Issue2255.png"; public const string Issues2435 = "Tiff/Issues/Issue2435.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"; diff --git a/tests/Images/Input/Tiff/Issues/Issue2587.tiff b/tests/Images/Input/Tiff/Issues/Issue2587.tiff new file mode 100644 index 0000000000..55368e1d3a --- /dev/null +++ b/tests/Images/Input/Tiff/Issues/Issue2587.tiff @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b5a245e4313bcf942d9a8ab7108946ddcadcf45d898b8a8986fc42a6e8c64dc2 +size 87746