diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/JFifMarker.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JFifMarker.cs index 42dcf7200..e13b26f9a 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/JFifMarker.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JFifMarker.cs @@ -26,16 +26,6 @@ internal readonly struct JFifMarker : IEquatable /// The vertical pixel density. private JFifMarker(byte majorVersion, byte minorVersion, byte densityUnits, short xDensity, short yDensity) { - if (xDensity <= 0) - { - JpegThrowHelper.ThrowInvalidImageContentException($"X-Density {xDensity} must be greater than 0."); - } - - if (yDensity <= 0) - { - JpegThrowHelper.ThrowInvalidImageContentException($"Y-Density {yDensity} must be greater than 0."); - } - this.MajorVersion = majorVersion; this.MinorVersion = minorVersion; @@ -64,12 +54,12 @@ internal readonly struct JFifMarker : IEquatable public PixelResolutionUnit DensityUnits { get; } /// - /// Gets the horizontal pixel density. Must not be zero. + /// Gets the horizontal pixel density. /// public short XDensity { get; } /// - /// Gets the vertical pixel density. Must not be zero. + /// Gets the vertical pixel density. /// public short YDensity { get; } @@ -88,12 +78,8 @@ internal readonly struct JFifMarker : IEquatable byte densityUnits = bytes[7]; short xDensity = (short)((bytes[8] << 8) | bytes[9]); short yDensity = (short)((bytes[10] << 8) | bytes[11]); - - if (xDensity > 0 && yDensity > 0) - { - marker = new JFifMarker(majorVersion, minorVersion, densityUnits, xDensity, yDensity); - return true; - } + marker = new JFifMarker(majorVersion, minorVersion, densityUnits, xDensity, yDensity); + return true; } marker = default; diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/SpectralConverter.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/SpectralConverter.cs index 0eb484b94..51d9bfbce 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/SpectralConverter.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/SpectralConverter.cs @@ -121,4 +121,10 @@ internal abstract class SpectralConverter return size; } + + /// + /// Gets a value indicating whether the converter has a pixel buffer. + /// + /// if the converter has a pixel buffer; otherwise, . + public abstract bool HasPixelBuffer(); } diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/SpectralConverter{TPixel}.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/SpectralConverter{TPixel}.cs index 4bb58d8a1..d6250127f 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/SpectralConverter{TPixel}.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/SpectralConverter{TPixel}.cs @@ -85,6 +85,12 @@ internal class SpectralConverter : SpectralConverter, IDisposable /// public Configuration Configuration { get; } + /// + /// Gets a value indicating whether the converter has a pixel buffer. + /// + /// if the converter has a pixel buffer; otherwise, . + public override bool HasPixelBuffer() => this.pixelBuffer is not null; + /// /// Gets converted pixel buffer. /// diff --git a/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs b/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs index 511ec1ba1..51de9ffbd 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs @@ -356,6 +356,18 @@ internal sealed class JpegDecoderCore : IRawJpegData, IImageDecoderInternals // to uint to avoid sign extension. if (stream.RemainingBytes < (uint)markerContentByteSize) { + if (metadataOnly && this.Metadata != null && this.Frame != null) + { + // We have enough data to decode the image, so we can stop parsing. + return; + } + + if (this.Metadata != null && this.Frame != null && spectralConverter.HasPixelBuffer()) + { + // We have enough data to decode the image, so we can stop parsing. + return; + } + JpegThrowHelper.ThrowNotEnoughBytesForMarker(fileMarker.Marker); } diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs index 1d5a7e0ff..425d12497 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs @@ -300,4 +300,15 @@ public partial class JpegDecoderTests image.DebugSave(provider); image.CompareToOriginal(provider); } + + // https://github.com/SixLabors/ImageSharp/issues/2315 + [Theory] + [WithFile(TestImages.Jpeg.Issues.Issue2315_NotEnoughBytes, PixelTypes.Rgba32)] + public void Issue2315_DecodeWorks(TestImageProvider provider) + where TPixel : unmanaged, IPixel + { + using Image image = provider.GetImage(JpegDecoder.Instance); + image.DebugSave(provider); + image.CompareToOriginal(provider); + } } diff --git a/tests/ImageSharp.Tests/Formats/Jpg/SpectralJpegTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/SpectralJpegTests.cs index 58347a072..805ee586a 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/SpectralJpegTests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/SpectralJpegTests.cs @@ -187,6 +187,8 @@ public class SpectralJpegTests } } + public override bool HasPixelBuffer() => throw new NotImplementedException(); + public override void InjectFrameData(JpegFrame frame, IRawJpegData jpegData) { this.frame = frame; diff --git a/tests/ImageSharp.Tests/TestImages.cs b/tests/ImageSharp.Tests/TestImages.cs index 29223b1fe..22a48ebee 100644 --- a/tests/ImageSharp.Tests/TestImages.cs +++ b/tests/ImageSharp.Tests/TestImages.cs @@ -281,6 +281,7 @@ public static class TestImages public const string ValidExifArgumentNullExceptionOnEncode = "Jpg/issues/Issue2087-exif-null-reference-on-encode.jpg"; public const string Issue2133_DeduceColorSpace = "Jpg/issues/Issue2133.jpg"; public const string Issue2136_ScanMarkerExtraneousBytes = "Jpg/issues/Issue2136-scan-segment-extraneous-bytes.jpg"; + public const string Issue2315_NotEnoughBytes = "Jpg/issues/issue-2315.jpg"; public static class Fuzz { diff --git a/tests/Images/Input/Jpg/issues/issue-2315.jpg b/tests/Images/Input/Jpg/issues/issue-2315.jpg new file mode 100644 index 000000000..fe3001edd --- /dev/null +++ b/tests/Images/Input/Jpg/issues/issue-2315.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f129b057efb499d492e9afcffdd98de62aac1e04b97a09a75b4799ba498cd3c1 +size 319056