diff --git a/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs b/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs index 83a828caaf..ccace190f9 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs @@ -753,10 +753,7 @@ internal sealed class JpegDecoderCore : IRawJpegData, IImageDecoderInternals Span temp = stackalloc byte[2 * 16 * 4]; stream.Read(temp, 0, JFifMarker.Length); - if (!JFifMarker.TryParse(temp, out this.jFif)) - { - JpegThrowHelper.ThrowNotSupportedException("Unknown App0 Marker - Expected JFIF."); - } + _ = JFifMarker.TryParse(temp, out this.jFif); remaining -= JFifMarker.Length; diff --git a/src/ImageSharp/Formats/Png/PngDecoderCore.cs b/src/ImageSharp/Formats/Png/PngDecoderCore.cs index 0957a7bd53..355a0bfcf7 100644 --- a/src/ImageSharp/Formats/Png/PngDecoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngDecoderCore.cs @@ -15,6 +15,7 @@ using SixLabors.ImageSharp.Formats.Png.Chunks; using SixLabors.ImageSharp.Formats.Png.Filters; using SixLabors.ImageSharp.IO; using SixLabors.ImageSharp.Memory; +using SixLabors.ImageSharp.Memory.Internals; using SixLabors.ImageSharp.Metadata; using SixLabors.ImageSharp.Metadata.Profiles.Exif; using SixLabors.ImageSharp.Metadata.Profiles.Icc; @@ -1873,6 +1874,11 @@ internal sealed class PngDecoderCore : IImageDecoderInternals [MethodImpl(InliningOptions.ShortMethod)] private IMemoryOwner ReadChunkData(int length) { + if (length == 0) + { + return new BasicArrayBuffer(Array.Empty()); + } + // We rent the buffer here to return it afterwards in Decode() IMemoryOwner buffer = this.configuration.MemoryAllocator.Allocate(length, AllocationOptions.Clean); 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 @@ internal static class TiffDecoderOptionsParser 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 @@ internal static class TiffDecoderOptionsParser } } - 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 @@ internal static class TiffDecoderOptionsParser 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 @@ internal static class TiffDecoderOptionsParser 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 @@ internal static class TiffDecoderOptionsParser } } } + + 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/Jpg/JpegDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs index eaa9f82cbb..deea9217f0 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs @@ -326,6 +326,17 @@ public partial class JpegDecoderTests image.CompareToOriginal(provider); } + // https://github.com/SixLabors/ImageSharp/discussions/2564 + [Theory] + [WithFile(TestImages.Jpeg.Issues.Issue2564, PixelTypes.Rgba32)] + public void Issue2564_DecodeWorks(TestImageProvider provider) + where TPixel : unmanaged, IPixel + { + using Image image = provider.GetImage(JpegDecoder.Instance); + image.DebugSave(provider); + image.CompareToOriginal(provider); + } + [Theory] [WithFile(TestImages.Jpeg.Issues.HangBadScan, PixelTypes.L8)] public void DecodeHang(TestImageProvider provider) diff --git a/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs index a2925d254e..5351af4fcc 100644 --- a/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs @@ -647,4 +647,13 @@ public partial class PngDecoderTests "Disco") .Dispose(); } + + [Fact] + public void Binary_PrematureEof() + { + using EofHitCounter eofHitCounter = EofHitCounter.RunDecoder(TestImages.Png.Bad.FlagOfGermany0000016446); + + Assert.True(eofHitCounter.EofHitCount <= 2); + Assert.Equal(new Size(200, 120), eofHitCounter.Image.Size); + } } 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 class TiffDecoderTests : TiffDecoderBaseTester 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..0d9fc55007 100644 --- a/tests/ImageSharp.Tests/TestImages.cs +++ b/tests/ImageSharp.Tests/TestImages.cs @@ -180,6 +180,8 @@ public static class TestImages // Invalid color type. public const string ColorTypeOne = "Png/xc1n0g08.png"; public const string ColorTypeNine = "Png/xc9n2c08.png"; + + public const string FlagOfGermany0000016446 = "Png/issues/flag_of_germany-0000016446.png"; } } @@ -302,6 +304,7 @@ public static class TestImages public const string Issue2334_NotEnoughBytesA = "Jpg/issues/issue-2334-a.jpg"; public const string Issue2334_NotEnoughBytesB = "Jpg/issues/issue-2334-b.jpg"; public const string Issue2478_JFXX = "Jpg/issues/issue-2478-jfxx.jpg"; + public const string Issue2564 = "Jpg/issues/issue-2564.jpg"; public const string HangBadScan = "Jpg/issues/Hang_C438A851.jpg"; public static class Fuzz @@ -992,6 +995,7 @@ public static class TestImages 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/Jpg/issues/issue-2564.jpg b/tests/Images/Input/Jpg/issues/issue-2564.jpg new file mode 100644 index 0000000000..2f0b581032 --- /dev/null +++ b/tests/Images/Input/Jpg/issues/issue-2564.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:08f215c777b6fe8e315f18b7f93611c90fa86fefb8e3d37181890afb3068d8bd +size 939150 diff --git a/tests/Images/Input/Png/issues/flag_of_germany-0000016446.png b/tests/Images/Input/Png/issues/flag_of_germany-0000016446.png new file mode 100644 index 0000000000..cb8b5bc941 --- /dev/null +++ b/tests/Images/Input/Png/issues/flag_of_germany-0000016446.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:64633823874512ff9f37bd321184d548816e97b8898622ae7d912b59f3099a35 +size 16446 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