diff --git a/src/ImageSharp/Formats/Jpeg/JpegConstants.cs b/src/ImageSharp/Formats/Jpeg/JpegConstants.cs index 8cc6ee81af..98c4025991 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegConstants.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegConstants.cs @@ -133,6 +133,11 @@ namespace SixLabors.ImageSharp.Formats.Jpeg /// public const byte APP15 = 0xEF; + /// + /// Define arithmetic coding conditioning marker. + /// + public const byte DAC = 0xCC; + /// /// The text comment marker /// @@ -173,6 +178,46 @@ namespace SixLabors.ImageSharp.Formats.Jpeg /// public const byte SOF2 = 0xC2; + /// + /// Start of Frame marker, non differential lossless, Huffman coding. + /// + public const byte SOF3 = 0xC3; + + /// + /// Start of Frame marker, differential lossless, Huffman coding. + /// + public const byte SOF7 = 0xC7; + + /// + /// Start of Frame marker, non-differential, arithmetic coding, Extended sequential DCT. + /// + public const byte SOF9 = 0xC9; + + /// + /// Start of Frame marker, non-differential, arithmetic coding, Progressive DCT. + /// + public const byte SOF10 = 0xCA; + + /// + /// Start of Frame marker, non-differential, arithmetic coding, Lossless (sequential). + /// + public const byte SOF11 = 0xCB; + + /// + /// Start of Frame marker, differential, arithmetic coding, Differential sequential DCT. + /// + public const byte SOF13 = 0xCD; + + /// + /// Start of Frame marker, differential, arithmetic coding, Differential progressive DCT. + /// + public const byte SOF14 = 0xCE; + + /// + /// Start of Frame marker, differential, arithmetic coding, Differential lossless (sequential). + /// + public const byte SOF15 = 0xCF; + /// /// Define Huffman Table(s) /// diff --git a/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs b/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs index e94b07faae..3810dd19c6 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs @@ -247,6 +247,20 @@ namespace SixLabors.ImageSharp.Formats.Jpeg this.ProcessStartOfFrameMarker(stream, remaining, fileMarker, metadataOnly); break; + case JpegConstants.Markers.SOF3: + case JpegConstants.Markers.SOF7: + JpegThrowHelper.ThrowNotSupportedException("Decoding lossless jpeg files is not supported."); + break; + + case JpegConstants.Markers.SOF9: + case JpegConstants.Markers.SOF10: + case JpegConstants.Markers.SOF11: + case JpegConstants.Markers.SOF13: + case JpegConstants.Markers.SOF14: + case JpegConstants.Markers.SOF15: + JpegThrowHelper.ThrowNotSupportedException("Decoding jpeg files with arithmetic coding is not supported."); + break; + case JpegConstants.Markers.SOS: if (!metadataOnly) { @@ -326,6 +340,10 @@ namespace SixLabors.ImageSharp.Formats.Jpeg case JpegConstants.Markers.COM: stream.Skip(remaining); break; + + case JpegConstants.Markers.DAC: + JpegThrowHelper.ThrowNotSupportedException("Decoding jpeg files with arithmetic coding is not supported."); + break; } } diff --git a/src/ImageSharp/Formats/Jpeg/JpegThrowHelper.cs b/src/ImageSharp/Formats/Jpeg/JpegThrowHelper.cs index 1b5362275d..b6c7e76268 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegThrowHelper.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegThrowHelper.cs @@ -8,6 +8,13 @@ namespace SixLabors.ImageSharp.Formats.Jpeg { internal static class JpegThrowHelper { + /// + /// Cold path optimization for throwing 's. + /// + /// The error message for the exception. + [MethodImpl(InliningOptions.ColdPath)] + public static void ThrowNotSupportedException(string errorMessage) => throw new NotSupportedException(errorMessage); + /// /// Cold path optimization for throwing 's. /// diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs index e8d307f909..6b1ce19e49 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs @@ -74,7 +74,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg byte[] bytes = TestFile.Create(TestImages.Jpeg.Progressive.Progress).Bytes; using var ms = new MemoryStream(bytes); using var bufferedStream = new BufferedReadStream(Configuration.Default, ms); - var decoder = new JpegDecoderCore(Configuration.Default, new JpegDecoder()); + using var decoder = new JpegDecoderCore(Configuration.Default, new JpegDecoder()); using Image image = decoder.Decode(bufferedStream, cancellationToken: default); // I don't know why these numbers are different. All I know is that the decoder works @@ -174,6 +174,19 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg await Assert.ThrowsAsync(async () => await Image.IdentifyAsync(config, "someFakeFile", cts.Token)); } + [Theory] + [WithFile(TestImages.Jpeg.Baseline.ArithmeticCoding, PixelTypes.Rgba32)] + [WithFile(TestImages.Jpeg.Baseline.ArithmeticCodingProgressive, PixelTypes.Rgba32)] + [WithFile(TestImages.Jpeg.Baseline.Lossless, PixelTypes.Rgba32)] + public void ThrowsNotSupported_WithUnsupportedJpegs(TestImageProvider provider) + where TPixel : unmanaged, IPixel + { + Assert.Throws(() => + { + using Image image = provider.GetImage(JpegDecoder); + }); + } + // https://github.com/SixLabors/ImageSharp/pull/1732 [Theory] [WithFile(TestImages.Jpeg.Issues.WrongColorSpace, PixelTypes.Rgba32)] diff --git a/tests/ImageSharp.Tests/TestImages.cs b/tests/ImageSharp.Tests/TestImages.cs index 1e12bb66ab..85c007c89f 100644 --- a/tests/ImageSharp.Tests/TestImages.cs +++ b/tests/ImageSharp.Tests/TestImages.cs @@ -200,6 +200,9 @@ namespace SixLabors.ImageSharp.Tests public const string App13WithEmptyIptc = "Jpg/baseline/iptc-psAPP13-wIPTCempty.jpg"; public const string HistogramEqImage = "Jpg/baseline/640px-Unequalized_Hawkes_Bay_NZ.jpg"; public const string ForestBridgeDifferentComponentsQuality = "Jpg/baseline/forest_bridge.jpg"; + public const string ArithmeticCoding = "Jpg/baseline/arithmetic_coding.jpg"; + public const string ArithmeticCodingProgressive = "Jpg/baseline/arithmetic_progressive.jpg"; + public const string Lossless = "Jpg/baseline/lossless.jpg"; public static readonly string[] All = { diff --git a/tests/Images/Input/Jpg/baseline/arithmetic_coding.jpg b/tests/Images/Input/Jpg/baseline/arithmetic_coding.jpg new file mode 100644 index 0000000000..3f57b7d7a7 --- /dev/null +++ b/tests/Images/Input/Jpg/baseline/arithmetic_coding.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:fec7012d9ae52a12c4617fd7526e506feee812fc67e923a76b2ca88c95f7a538 +size 3111 diff --git a/tests/Images/Input/Jpg/baseline/arithmetic_progressive.jpg b/tests/Images/Input/Jpg/baseline/arithmetic_progressive.jpg new file mode 100644 index 0000000000..06b3b684eb --- /dev/null +++ b/tests/Images/Input/Jpg/baseline/arithmetic_progressive.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3af237c172248d39c7b82c879de3d162e4dafaf36dc298add210740843edd33f +size 3129 diff --git a/tests/Images/Input/Jpg/baseline/lossless.jpg b/tests/Images/Input/Jpg/baseline/lossless.jpg new file mode 100644 index 0000000000..37091b73c2 --- /dev/null +++ b/tests/Images/Input/Jpg/baseline/lossless.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:8937e245885e1f280e1843ad48a4349ec1a3f71f86c954229cd44160aeeaaac4 +size 209584