From 85ce6b6ca25b6e4dcd064a51451c1117ff4483b1 Mon Sep 17 00:00:00 2001 From: Marius Thesing Date: Tue, 16 Sep 2025 12:10:51 +0200 Subject: [PATCH] Backport #2926 to release/2.1.x --- src/ImageSharp/Formats/Png/PngDecoderCore.cs | 21 ++++++++++++++++--- .../Formats/Png/PngDecoderTests.cs | 10 +++++++++ tests/ImageSharp.Tests/TestImages.cs | 3 +++ .../CanDecode_Issue2924_Rgba32_Issue_2924.png | 3 +++ tests/Images/Input/Png/issues/Issue_2924.png | 3 +++ 5 files changed, 37 insertions(+), 3 deletions(-) create mode 100644 tests/Images/External/ReferenceOutput/PngDecoderTests/CanDecode_Issue2924_Rgba32_Issue_2924.png create mode 100644 tests/Images/Input/Png/issues/Issue_2924.png diff --git a/src/ImageSharp/Formats/Png/PngDecoderCore.cs b/src/ImageSharp/Formats/Png/PngDecoderCore.cs index d6c3256e06..be2f6848d3 100644 --- a/src/ImageSharp/Formats/Png/PngDecoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngDecoderCore.cs @@ -114,6 +114,11 @@ internal sealed class PngDecoderCore : IImageDecoderInternals /// private PngChunk? nextChunk; + /// + /// A value indicating whether the image data has been read. + /// + private bool hasImageData; + /// /// Initializes a new instance of the class. /// @@ -565,7 +570,11 @@ private void ReadScanlines(PngChunk chunk, ImageFrame image, Png where TPixel : unmanaged, IPixel { using var deframeStream = new ZlibInflateStream(this.currentStream, this.ReadNextDataChunk); - deframeStream.AllocateNewBytes(chunk.Length, true); + if (!deframeStream.AllocateNewBytes(chunk.Length, !this.hasImageData)) + { + return; + } + DeflateStream dataStream = deframeStream.CompressedStream; if (this.header.InterlaceMethod == PngInterlaceMode.Adam7) @@ -596,7 +605,7 @@ private void DecodePixelData(DeflateStream compressedStream, ImageFrame< int bytesRead = compressedStream.Read(scanlineSpan, this.currentRowBytesRead, this.bytesPerScanline - this.currentRowBytesRead); if (bytesRead <= 0) { - return; + goto EXIT; } this.currentRowBytesRead += bytesRead; @@ -635,6 +644,9 @@ private void DecodePixelData(DeflateStream compressedStream, ImageFrame< this.SwapScanlineBuffers(); this.currentRow++; } + + EXIT: + this.hasImageData = true; } /// @@ -672,7 +684,7 @@ private void DecodeInterlacedPixelData(DeflateStream compressedStream, I int bytesRead = compressedStream.Read(this.scanline.GetSpan(), this.currentRowBytesRead, bytesPerInterlaceScanline - this.currentRowBytesRead); if (bytesRead <= 0) { - return; + goto EXIT; } this.currentRowBytesRead += bytesRead; @@ -729,6 +741,9 @@ private void DecodeInterlacedPixelData(DeflateStream compressedStream, I pass = 0; break; } + + EXIT: + this.hasImageData = true; } } diff --git a/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs index c361b1deb4..6c2067eea9 100644 --- a/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs @@ -534,5 +534,15 @@ public void Decode_BadPalette(string file) string path = Path.GetFullPath(Path.Combine(TestEnvironment.InputImagesDirectoryFullPath, file)); using Image image = Image.Load(path); } + + [Theory] + [WithFile(TestImages.Png.Issue2924, PixelTypes.Rgba32)] + public void CanDecode_Issue2924(TestImageProvider provider) + where TPixel : unmanaged, IPixel + { + using Image image = provider.GetImage(PngDecoder); + image.DebugSave(provider); + image.CompareToReferenceOutput(provider); + } } } diff --git a/tests/ImageSharp.Tests/TestImages.cs b/tests/ImageSharp.Tests/TestImages.cs index 9210be394e..6387e36414 100644 --- a/tests/ImageSharp.Tests/TestImages.cs +++ b/tests/ImageSharp.Tests/TestImages.cs @@ -125,6 +125,9 @@ public static class Png // Discussion 1875: https://github.com/SixLabors/ImageSharp/discussions/1875 public const string Issue1875 = "Png/raw-profile-type-exif.png"; + // Issue 2924: https://github.com/SixLabors/ImageSharp/issues/2924 + public const string Issue2924 = "Png/issues/Issue_2924.png"; + public static class Bad { public const string MissingDataChunk = "Png/xdtn0g01.png"; diff --git a/tests/Images/External/ReferenceOutput/PngDecoderTests/CanDecode_Issue2924_Rgba32_Issue_2924.png b/tests/Images/External/ReferenceOutput/PngDecoderTests/CanDecode_Issue2924_Rgba32_Issue_2924.png new file mode 100644 index 0000000000..023f346e03 --- /dev/null +++ b/tests/Images/External/ReferenceOutput/PngDecoderTests/CanDecode_Issue2924_Rgba32_Issue_2924.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4347cd89196c09496288724afdd876b227063149bba33615c338ebb474a0cb19 +size 47260 diff --git a/tests/Images/Input/Png/issues/Issue_2924.png b/tests/Images/Input/Png/issues/Issue_2924.png new file mode 100644 index 0000000000..0454642190 --- /dev/null +++ b/tests/Images/Input/Png/issues/Issue_2924.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:fd366a2de522041c706729b01a6030df6c82a4e87ea3509cc78a47486f097044 +size 49376