@@ -18,11 +18,24 @@ internal class HuffmanScanDecoder
1818 {
1919 private readonly BufferedReadStream stream ;
2020
21- // Frame related
21+ /// <summary>
22+ /// <see cref="JpegFrame"/> instance containing decoding-related information.
23+ /// </summary>
2224 private JpegFrame frame ;
25+
26+ /// <summary>
27+ /// Shortcut for <see cref="frame"/>.Components.
28+ /// </summary>
2329 private JpegComponent [ ] components ;
2430
25- // The restart interval.
31+ /// <summary>
32+ /// Number of component in the current scan.
33+ /// </summary>
34+ private int componentsCount ;
35+
36+ /// <summary>
37+ /// The reset interval determined by RST markers.
38+ /// </summary>
2639 private int restartInterval ;
2740
2841 // How many mcu's are left to do.
@@ -31,6 +44,16 @@ internal class HuffmanScanDecoder
3144 // The End-Of-Block countdown for ending the sequence prematurely when the remaining coefficients are zero.
3245 private int eobrun ;
3346
47+ /// <summary>
48+ /// The DC Huffman tables.
49+ /// </summary>
50+ private readonly HuffmanTable [ ] dcHuffmanTables ;
51+
52+ /// <summary>
53+ /// The AC Huffman tables
54+ /// </summary>
55+ private readonly HuffmanTable [ ] acHuffmanTables ;
56+
3457 // The unzig data.
3558 private ZigZag dctZigZag ;
3659
@@ -55,14 +78,16 @@ public HuffmanScanDecoder(
5578 this . stream = stream ;
5679 this . spectralConverter = converter ;
5780 this . cancellationToken = cancellationToken ;
58- }
5981
60- // huffman tables
61- public HuffmanTable [ ] DcHuffmanTables { get ; set ; }
62-
63- public HuffmanTable [ ] AcHuffmanTables { get ; set ; }
82+ // TODO: this is actually a variable value depending on component count
83+ const int maxTables = 4 ;
84+ this . dcHuffmanTables = new HuffmanTable [ maxTables ] ;
85+ this . acHuffmanTables = new HuffmanTable [ maxTables ] ;
86+ }
6487
65- // Reset interval
88+ /// <summary>
89+ /// Sets reset interval determined by RST markers.
90+ /// </summary>
6691 public int ResetInterval
6792 {
6893 set
@@ -72,9 +97,6 @@ public int ResetInterval
7297 }
7398 }
7499
75- // The number of interleaved components.
76- public int ComponentsLength { get ; set ; }
77-
78100 // The spectral selection start.
79101 public int SpectralStart { get ; set ; }
80102
@@ -90,10 +112,12 @@ public int ResetInterval
90112 /// <summary>
91113 /// Decodes the entropy coded data.
92114 /// </summary>
93- public void ParseEntropyCodedData ( )
115+ public void ParseEntropyCodedData ( int componentCount )
94116 {
95117 this . cancellationToken . ThrowIfCancellationRequested ( ) ;
96118
119+ this . componentsCount = componentCount ;
120+
97121 this . scanBuffer = new HuffmanScanBuffer ( this . stream ) ;
98122
99123 bool fullScan = this . frame . Progressive || this . frame . MultiScan ;
@@ -124,7 +148,7 @@ public void InjectFrameData(JpegFrame frame, IRawJpegData jpegData)
124148
125149 private void ParseBaselineData ( )
126150 {
127- if ( this . ComponentsLength == this . frame . ComponentCount )
151+ if ( this . componentsCount == this . frame . ComponentCount )
128152 {
129153 this . ParseBaselineDataInterleaved ( ) ;
130154 }
@@ -143,13 +167,13 @@ private void ParseBaselineDataInterleaved()
143167 ref HuffmanScanBuffer buffer = ref this . scanBuffer ;
144168
145169 // Pre-derive the huffman table to avoid in-loop checks.
146- for ( int i = 0 ; i < this . ComponentsLength ; i ++ )
170+ for ( int i = 0 ; i < this . componentsCount ; i ++ )
147171 {
148172 int order = this . frame . ComponentOrder [ i ] ;
149173 JpegComponent component = this . components [ order ] ;
150174
151- ref HuffmanTable dcHuffmanTable = ref this . DcHuffmanTables [ component . DCHuffmanTableId ] ;
152- ref HuffmanTable acHuffmanTable = ref this . AcHuffmanTables [ component . ACHuffmanTableId ] ;
175+ ref HuffmanTable dcHuffmanTable = ref this . dcHuffmanTables [ component . DCHuffmanTableId ] ;
176+ ref HuffmanTable acHuffmanTable = ref this . acHuffmanTables [ component . ACHuffmanTableId ] ;
153177 dcHuffmanTable . Configure ( ) ;
154178 acHuffmanTable . Configure ( ) ;
155179 }
@@ -163,13 +187,13 @@ private void ParseBaselineDataInterleaved()
163187 {
164188 // Scan an interleaved mcu... process components in order
165189 int mcuCol = mcu % mcusPerLine ;
166- for ( int k = 0 ; k < this . ComponentsLength ; k ++ )
190+ for ( int k = 0 ; k < this . componentsCount ; k ++ )
167191 {
168192 int order = this . frame . ComponentOrder [ k ] ;
169193 JpegComponent component = this . components [ order ] ;
170194
171- ref HuffmanTable dcHuffmanTable = ref this . DcHuffmanTables [ component . DCHuffmanTableId ] ;
172- ref HuffmanTable acHuffmanTable = ref this . AcHuffmanTables [ component . ACHuffmanTableId ] ;
195+ ref HuffmanTable dcHuffmanTable = ref this . dcHuffmanTables [ component . DCHuffmanTableId ] ;
196+ ref HuffmanTable acHuffmanTable = ref this . acHuffmanTables [ component . ACHuffmanTableId ] ;
173197
174198 int h = component . HorizontalSamplingFactor ;
175199 int v = component . VerticalSamplingFactor ;
@@ -221,8 +245,8 @@ private void ParseBaselineDataNonInterleaved()
221245 int w = component . WidthInBlocks ;
222246 int h = component . HeightInBlocks ;
223247
224- ref HuffmanTable dcHuffmanTable = ref this . DcHuffmanTables [ component . DCHuffmanTableId ] ;
225- ref HuffmanTable acHuffmanTable = ref this . AcHuffmanTables [ component . ACHuffmanTableId ] ;
248+ ref HuffmanTable dcHuffmanTable = ref this . dcHuffmanTables [ component . DCHuffmanTableId ] ;
249+ ref HuffmanTable acHuffmanTable = ref this . acHuffmanTables [ component . ACHuffmanTableId ] ;
226250 dcHuffmanTable . Configure ( ) ;
227251 acHuffmanTable . Configure ( ) ;
228252
@@ -272,7 +296,7 @@ private void CheckProgressiveData()
272296 }
273297
274298 // AC scans may have only one component.
275- if ( this . ComponentsLength != 1 )
299+ if ( this . componentsCount != 1 )
276300 {
277301 invalid = true ;
278302 }
@@ -304,7 +328,7 @@ private void ParseProgressiveData()
304328 {
305329 this . CheckProgressiveData ( ) ;
306330
307- if ( this . ComponentsLength == 1 )
331+ if ( this . componentsCount == 1 )
308332 {
309333 this . ParseProgressiveDataNonInterleaved ( ) ;
310334 }
@@ -323,11 +347,11 @@ private void ParseProgressiveDataInterleaved()
323347 ref HuffmanScanBuffer buffer = ref this . scanBuffer ;
324348
325349 // Pre-derive the huffman table to avoid in-loop checks.
326- for ( int k = 0 ; k < this . ComponentsLength ; k ++ )
350+ for ( int k = 0 ; k < this . componentsCount ; k ++ )
327351 {
328352 int order = this . frame . ComponentOrder [ k ] ;
329353 JpegComponent component = this . components [ order ] ;
330- ref HuffmanTable dcHuffmanTable = ref this . DcHuffmanTables [ component . DCHuffmanTableId ] ;
354+ ref HuffmanTable dcHuffmanTable = ref this . dcHuffmanTables [ component . DCHuffmanTableId ] ;
331355 dcHuffmanTable . Configure ( ) ;
332356 }
333357
@@ -338,11 +362,11 @@ private void ParseProgressiveDataInterleaved()
338362 // Scan an interleaved mcu... process components in order
339363 int mcuRow = mcu / mcusPerLine ;
340364 int mcuCol = mcu % mcusPerLine ;
341- for ( int k = 0 ; k < this . ComponentsLength ; k ++ )
365+ for ( int k = 0 ; k < this . componentsCount ; k ++ )
342366 {
343367 int order = this . frame . ComponentOrder [ k ] ;
344368 JpegComponent component = this . components [ order ] ;
345- ref HuffmanTable dcHuffmanTable = ref this . DcHuffmanTables [ component . DCHuffmanTableId ] ;
369+ ref HuffmanTable dcHuffmanTable = ref this . dcHuffmanTables [ component . DCHuffmanTableId ] ;
346370
347371 int h = component . HorizontalSamplingFactor ;
348372 int v = component . VerticalSamplingFactor ;
@@ -390,7 +414,7 @@ private void ParseProgressiveDataNonInterleaved()
390414
391415 if ( this . SpectralStart == 0 )
392416 {
393- ref HuffmanTable dcHuffmanTable = ref this . DcHuffmanTables [ component . DCHuffmanTableId ] ;
417+ ref HuffmanTable dcHuffmanTable = ref this . dcHuffmanTables [ component . DCHuffmanTableId ] ;
394418 dcHuffmanTable . Configure ( ) ;
395419
396420 for ( int j = 0 ; j < h ; j ++ )
@@ -418,7 +442,7 @@ ref Unsafe.Add(ref blockRef, i),
418442 }
419443 else
420444 {
421- ref HuffmanTable acHuffmanTable = ref this . AcHuffmanTables [ component . ACHuffmanTableId ] ;
445+ ref HuffmanTable acHuffmanTable = ref this . acHuffmanTables [ component . ACHuffmanTableId ] ;
422446 acHuffmanTable . Configure ( ) ;
423447
424448 for ( int j = 0 ; j < h ; j ++ )
@@ -722,5 +746,19 @@ private bool HandleRestart()
722746
723747 return false ;
724748 }
749+
750+ /// <summary>
751+ /// Build the huffman table using code lengths and code values.
752+ /// </summary>
753+ /// <param name="type">Table type.</param>
754+ /// <param name="index">Table index.</param>
755+ /// <param name="codeLengths">Code lengths.</param>
756+ /// <param name="values">Code values.</param>
757+ [ MethodImpl ( InliningOptions . ShortMethod ) ]
758+ public void BuildHuffmanTable ( int type , int index , ReadOnlySpan < byte > codeLengths , ReadOnlySpan < byte > values )
759+ {
760+ HuffmanTable [ ] tables = type == 0 ? this . dcHuffmanTables : this . acHuffmanTables ;
761+ tables [ index ] = new HuffmanTable ( codeLengths , values ) ;
762+ }
725763 }
726764}
0 commit comments