private void DecodeBlocksAtMcuIndex(OrigJpegDecoderCore decoder, int mx, int my) { for (int scanIndex = 0; scanIndex < this.componentScanCount; scanIndex++) { this.ComponentIndex = this.pointers.ComponentScan[scanIndex].ComponentIndex; OrigComponent component = decoder.Components[this.ComponentIndex]; this.hi = component.HorizontalSamplingFactor; int vi = component.VerticalSamplingFactor; for (int j = 0; j < this.hi * vi; j++) { if (this.componentScanCount != 1) { this.bx = (this.hi * mx) + (j % this.hi); this.by = (vi * my) + (j / this.hi); } else { int q = decoder.MCUCountX * this.hi; this.bx = this.blockCounter % q; this.by = this.blockCounter / q; this.blockCounter++; if (this.bx * 8 >= decoder.ImageWidth || this.by * 8 >= decoder.ImageHeight) { continue; } } // Find the block at (bx,by) in the component's buffer: ref Block8x8 blockRefOnHeap = ref component.GetBlockReference(this.bx, this.by); // Copy block to stack this.data.Block = blockRefOnHeap; if (!decoder.InputProcessor.ReachedEOF) { this.DecodeBlock(decoder, scanIndex); } // Store the result block: blockRefOnHeap = this.data.Block; } }
/// <summary> /// Read Huffman data from Jpeg scans in <see cref="OrigJpegDecoderCore.InputStream"/>, /// and decode it as <see cref="Block8x8"/> into <see cref="OrigComponent.SpectralBlocks"/>. /// /// The blocks are traversed one MCU at a time. For 4:2:0 chroma /// subsampling, there are four Y 8x8 blocks in every 16x16 MCU. /// For a baseline 32x16 pixel image, the Y blocks visiting order is: /// 0 1 4 5 /// 2 3 6 7 /// For progressive images, the interleaved scans (those with component count > 1) /// are traversed as above, but non-interleaved scans are traversed left /// to right, top to bottom: /// 0 1 2 3 /// 4 5 6 7 /// Only DC scans (zigStart == 0) can be interleave AC scans must have /// only one component. /// To further complicate matters, for non-interleaved scans, there is no /// data for any blocks that are inside the image at the MCU level but /// outside the image at the pixel level. For example, a 24x16 pixel 4:2:0 /// progressive image consists of two 16x16 MCUs. The interleaved scans /// will process 8 Y blocks: /// 0 1 4 5 /// 2 3 6 7 /// The non-interleaved scans will process only 6 Y blocks: /// 0 1 2 /// 3 4 5 /// </summary> /// <param name="decoder">The <see cref="OrigJpegDecoderCore"/> instance</param> public void DecodeBlocks(OrigJpegDecoderCore decoder) { decoder.InputProcessor.ResetErrorState(); int blockCount = 0; int mcu = 0; byte expectedRst = OrigJpegConstants.Markers.RST0; for (int my = 0; my < decoder.MCUCountY; my++) { for (int mx = 0; mx < decoder.MCUCountX; mx++) { for (int scanIndex = 0; scanIndex < this.componentScanCount; scanIndex++) { this.ComponentIndex = this.pointers.ComponentScan[scanIndex].ComponentIndex; OrigComponent component = decoder.Components[this.ComponentIndex]; this.hi = component.HorizontalSamplingFactor; int vi = component.VerticalSamplingFactor; for (int j = 0; j < this.hi * vi; j++) { if (this.componentScanCount != 1) { this.bx = (this.hi * mx) + (j % this.hi); this.by = (vi * my) + (j / this.hi); } else { int q = decoder.MCUCountX * this.hi; this.bx = blockCount % q; this.by = blockCount / q; blockCount++; if (this.bx * 8 >= decoder.ImageWidth || this.by * 8 >= decoder.ImageHeight) { continue; } } // Find the block at (bx,by) in the component's buffer: ref Block8x8 blockRefOnHeap = ref component.GetBlockReference(this.bx, this.by); // Copy block to stack this.data.Block = blockRefOnHeap; if (!decoder.InputProcessor.ReachedEOF) { this.DecodeBlock(decoder, scanIndex); } // Store the result block: blockRefOnHeap = this.data.Block; } // for j } // for i mcu++; if (decoder.RestartInterval > 0 && mcu % decoder.RestartInterval == 0 && mcu < decoder.TotalMCUCount) { // A more sophisticated decoder could use RST[0-7] markers to resynchronize from corrupt input, // but this one assumes well-formed input, and hence the restart marker follows immediately. if (!decoder.InputProcessor.ReachedEOF) { decoder.InputProcessor.ReadFullUnsafe(decoder.Temp, 0, 2); if (decoder.InputProcessor.CheckEOFEnsureNoError()) { if (decoder.Temp[0] != 0xff || decoder.Temp[1] != expectedRst) { throw new ImageFormatException("Bad RST marker"); } expectedRst++; if (expectedRst == OrigJpegConstants.Markers.RST7 + 1) { expectedRst = OrigJpegConstants.Markers.RST0; } } } // Reset the Huffman decoder. decoder.InputProcessor.Bits = default(Bits); // Reset the DC components, as per section F.2.1.3.1. this.ResetDc(); // Reset the progressive decoder state, as per section G.1.2.2. this.eobRun = 0; } } // for mx }