From ca9c45e60134d38baae6d9698839c7a476155fc7 Mon Sep 17 00:00:00 2001 From: Dmitry Pentin Date: Sun, 6 Feb 2022 02:57:42 +0300 Subject: [PATCH] Fixed invalid non-interleaved single component jpeg scan parsing --- .../Components/Decoder/HuffmanScanDecoder.cs | 61 +++++++++++++++++-- 1 file changed, 57 insertions(+), 4 deletions(-) diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/HuffmanScanDecoder.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/HuffmanScanDecoder.cs index 2ae3ae86bc..cf2fd02908 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/HuffmanScanDecoder.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/HuffmanScanDecoder.cs @@ -148,11 +148,16 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder private void ParseBaselineData() { - if (this.componentsCount == this.frame.ComponentCount) + if (this.componentsCount != 1) { this.ParseBaselineDataInterleaved(); this.spectralConverter.CommitConversion(); } + else if (this.frame.ComponentCount == 1) + { + this.ParseBaselineDataSingleComponent(); + this.spectralConverter.CommitConversion(); + } else { this.ParseBaselineDataNonInterleaved(); @@ -161,7 +166,6 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder private void ParseBaselineDataInterleaved() { - // Interleaved int mcu = 0; int mcusPerColumn = this.frame.McusPerColumn; int mcusPerLine = this.frame.McusPerLine; @@ -198,7 +202,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder { if (buffer.NoData) { - // It is very likely that some spectral data was decoded before we encountered EOI marker + // It is very likely that some spectral data was decoded before we've encountered 'end of scan' // so we need to decode what's left and return (or maybe throw?) this.spectralConverter.ConvertStrideBaseline(); return; @@ -221,9 +225,12 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder this.HandleRestart(); } - // convert from spectral to actual pixels via given converter + // Convert from spectral to actual pixels via given converter this.spectralConverter.ConvertStrideBaseline(); } + + // Stride conversion must be sealed for stride conversion approach + this.spectralConverter.CommitConversion(); } private void ParseBaselineDataNonInterleaved() @@ -261,6 +268,52 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder } } + private void ParseBaselineDataSingleComponent() + { + JpegComponent component = this.frame.Components[0]; + int mcuLines = this.frame.McusPerColumn; + int w = component.WidthInBlocks; + int h = component.SamplingFactors.Height; + ref HuffmanTable dcHuffmanTable = ref this.dcHuffmanTables[component.DCHuffmanTableId]; + ref HuffmanTable acHuffmanTable = ref this.acHuffmanTables[component.ACHuffmanTableId]; + + ref HuffmanScanBuffer buffer = ref this.scanBuffer; + + for (int i = 0; i < mcuLines; i++) + { + this.cancellationToken.ThrowIfCancellationRequested(); + + // decode from binary to spectral + for (int j = 0; j < h; j++) + { + Span blockSpan = component.SpectralBlocks.DangerousGetRowSpan(j); + ref Block8x8 blockRef = ref MemoryMarshal.GetReference(blockSpan); + + for (int k = 0; k < w; k++) + { + if (buffer.NoData) + { + // It is very likely that some spectral data was decoded before we've encountered 'end of scan' + // so we need to decode what's left and return (or maybe throw?) + this.spectralConverter.ConvertStrideBaseline(); + return; + } + + this.DecodeBlockBaseline( + component, + ref Unsafe.Add(ref blockRef, k), + ref dcHuffmanTable, + ref acHuffmanTable); + + this.HandleRestart(); + } + } + + // Convert from spectral to actual pixels via given converter + this.spectralConverter.ConvertStrideBaseline(); + } + } + private void CheckProgressiveData() { // Validate successive scan parameters.