From 6f45485203e61b6733c7eaf7015b453742d4679d Mon Sep 17 00:00:00 2001 From: Dmitry Pentin Date: Thu, 15 Jul 2021 18:33:54 +0300 Subject: [PATCH] Huffman tables are now handled by scan decoder, not decoder core --- .../Components/Decoder/HuffmanScanDecoder.cs | 54 +++++++++++++------ .../Formats/Jpeg/JpegDecoderCore.cs | 40 ++------------ 2 files changed, 42 insertions(+), 52 deletions(-) diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/HuffmanScanDecoder.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/HuffmanScanDecoder.cs index a09c7ada3e..97ec45ec1e 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/HuffmanScanDecoder.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/HuffmanScanDecoder.cs @@ -31,6 +31,16 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder // The End-Of-Block countdown for ending the sequence prematurely when the remaining coefficients are zero. private int eobrun; + /// + /// The DC Huffman tables. + /// + private readonly HuffmanTable[] dcHuffmanTables; + + /// + /// The AC Huffman tables + /// + private readonly HuffmanTable[] acHuffmanTables; + // The unzig data. private ZigZag dctZigZag; @@ -55,12 +65,12 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder this.stream = stream; this.spectralConverter = converter; this.cancellationToken = cancellationToken; - } - - // huffman tables - public HuffmanTable[] DcHuffmanTables { get; set; } - public HuffmanTable[] AcHuffmanTables { get; set; } + // TODO: this is actually a variable value depending on component count + const int maxTables = 4; + this.dcHuffmanTables = new HuffmanTable[maxTables]; + this.acHuffmanTables = new HuffmanTable[maxTables]; + } // Reset interval public int ResetInterval @@ -148,8 +158,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder int order = this.frame.ComponentOrder[i]; JpegComponent component = this.components[order]; - ref HuffmanTable dcHuffmanTable = ref this.DcHuffmanTables[component.DCHuffmanTableId]; - ref HuffmanTable acHuffmanTable = ref this.AcHuffmanTables[component.ACHuffmanTableId]; + ref HuffmanTable dcHuffmanTable = ref this.dcHuffmanTables[component.DCHuffmanTableId]; + ref HuffmanTable acHuffmanTable = ref this.acHuffmanTables[component.ACHuffmanTableId]; dcHuffmanTable.Configure(); acHuffmanTable.Configure(); } @@ -168,8 +178,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder int order = this.frame.ComponentOrder[k]; JpegComponent component = this.components[order]; - ref HuffmanTable dcHuffmanTable = ref this.DcHuffmanTables[component.DCHuffmanTableId]; - ref HuffmanTable acHuffmanTable = ref this.AcHuffmanTables[component.ACHuffmanTableId]; + ref HuffmanTable dcHuffmanTable = ref this.dcHuffmanTables[component.DCHuffmanTableId]; + ref HuffmanTable acHuffmanTable = ref this.acHuffmanTables[component.ACHuffmanTableId]; int h = component.HorizontalSamplingFactor; int v = component.VerticalSamplingFactor; @@ -221,8 +231,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder int w = component.WidthInBlocks; int h = component.HeightInBlocks; - ref HuffmanTable dcHuffmanTable = ref this.DcHuffmanTables[component.DCHuffmanTableId]; - ref HuffmanTable acHuffmanTable = ref this.AcHuffmanTables[component.ACHuffmanTableId]; + ref HuffmanTable dcHuffmanTable = ref this.dcHuffmanTables[component.DCHuffmanTableId]; + ref HuffmanTable acHuffmanTable = ref this.acHuffmanTables[component.ACHuffmanTableId]; dcHuffmanTable.Configure(); acHuffmanTable.Configure(); @@ -327,7 +337,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder { int order = this.frame.ComponentOrder[k]; JpegComponent component = this.components[order]; - ref HuffmanTable dcHuffmanTable = ref this.DcHuffmanTables[component.DCHuffmanTableId]; + ref HuffmanTable dcHuffmanTable = ref this.dcHuffmanTables[component.DCHuffmanTableId]; dcHuffmanTable.Configure(); } @@ -342,7 +352,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder { int order = this.frame.ComponentOrder[k]; JpegComponent component = this.components[order]; - ref HuffmanTable dcHuffmanTable = ref this.DcHuffmanTables[component.DCHuffmanTableId]; + ref HuffmanTable dcHuffmanTable = ref this.dcHuffmanTables[component.DCHuffmanTableId]; int h = component.HorizontalSamplingFactor; int v = component.VerticalSamplingFactor; @@ -390,7 +400,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder if (this.SpectralStart == 0) { - ref HuffmanTable dcHuffmanTable = ref this.DcHuffmanTables[component.DCHuffmanTableId]; + ref HuffmanTable dcHuffmanTable = ref this.dcHuffmanTables[component.DCHuffmanTableId]; dcHuffmanTable.Configure(); for (int j = 0; j < h; j++) @@ -418,7 +428,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder } else { - ref HuffmanTable acHuffmanTable = ref this.AcHuffmanTables[component.ACHuffmanTableId]; + ref HuffmanTable acHuffmanTable = ref this.acHuffmanTables[component.ACHuffmanTableId]; acHuffmanTable.Configure(); for (int j = 0; j < h; j++) @@ -722,5 +732,19 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder return false; } + + /// + /// Build the huffman table using code lengths and code values. + /// + /// Table type. + /// Table index. + /// Code lengths. + /// Code values. + [MethodImpl(InliningOptions.ShortMethod)] + public void BuildHuffmanTable(int type, int index, ReadOnlySpan codeLengths, ReadOnlySpan values) + { + HuffmanTable[] tables = type == 0 ? this.dcHuffmanTables : this.acHuffmanTables; + tables[index] = new HuffmanTable(codeLengths, values); + } } } diff --git a/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs b/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs index 922e9797cb..ee723f062e 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs @@ -42,16 +42,6 @@ namespace SixLabors.ImageSharp.Formats.Jpeg /// private readonly byte[] markerBuffer = new byte[2]; - /// - /// The DC Huffman tables. - /// - private HuffmanTable[] dcHuffmanTables; - - /// - /// The AC Huffman tables - /// - private HuffmanTable[] acHuffmanTables; - /// /// The reset interval determined by RST markers. /// @@ -270,14 +260,6 @@ namespace SixLabors.ImageSharp.Formats.Jpeg fileMarker = new JpegFileMarker(marker, (int)stream.Position - 2); this.QuantizationTables = new Block8x8F[4]; - // Only assign what we need - if (!metadataOnly) - { - const int maxTables = 4; - this.dcHuffmanTables = new HuffmanTable[maxTables]; - this.acHuffmanTables = new HuffmanTable[maxTables]; - } - // Break only when we discover a valid EOI marker. // https://github.com/SixLabors/ImageSharp/issues/695 while (fileMarker.Marker != JpegConstants.Markers.EOI @@ -392,8 +374,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg // Set large fields to null. this.Frame = null; - this.dcHuffmanTables = null; - this.acHuffmanTables = null; + this.scanDecoder = null; } /// @@ -996,8 +977,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg i += 17 + codeLengthSum; - this.BuildHuffmanTable( - tableType == 0 ? this.dcHuffmanTables : this.acHuffmanTables, + this.scanDecoder.BuildHuffmanTable( + tableType, tableIndex, codeLengthsSpan, huffmanValuesSpan); @@ -1071,10 +1052,6 @@ namespace SixLabors.ImageSharp.Formats.Jpeg // All the comments below are for separate refactoring PR // Main reason it's not fixed here is to make this commit less intrusive - // Huffman tables can be calculated directly in the scan decoder class - this.scanDecoder.DcHuffmanTables = this.dcHuffmanTables; - this.scanDecoder.AcHuffmanTables = this.acHuffmanTables; - // This can be injectd in DRI marker callback this.scanDecoder.ResetInterval = this.resetInterval; @@ -1090,17 +1067,6 @@ namespace SixLabors.ImageSharp.Formats.Jpeg this.scanDecoder.ParseEntropyCodedData(); } - /// - /// Builds the huffman tables - /// - /// The tables - /// The table index - /// The codelengths - /// The values - [MethodImpl(InliningOptions.ShortMethod)] - private void BuildHuffmanTable(HuffmanTable[] tables, int index, ReadOnlySpan codeLengths, ReadOnlySpan values) - => tables[index] = new HuffmanTable(codeLengths, values); - /// /// Reads a from the stream advancing it by two bytes ///