/// <summary> /// Dequantize, perform the inverse DCT and store the blocks to the into the corresponding <see cref="JpegPixelArea"/> instances. /// </summary> /// <param name="decoder">The <see cref="JpegDecoderCore"/> instance</param> public void ProcessAllBlocks(JpegDecoderCore decoder) { DecodedBlockArray blockArray = decoder.DecodedBlocks[this.componentIndex]; for (int i = 0; i < blockArray.Count; i++) { this.ProcessBlockColors(decoder, ref blockArray.Buffer[i]); } }
/// <summary> /// Read Huffman data from Jpeg scans in <see cref="JpegDecoderCore.InputStream"/>, /// and decode it as <see cref="Block8x8F"/> into <see cref="JpegDecoderCore.DecodedBlocks"/>. /// /// 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="JpegDecoderCore"/> instance</param> public void DecodeBlocks(JpegDecoderCore decoder) { int blockCount = 0; int mcu = 0; byte expectedRst = JpegConstants.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; this.hi = decoder.ComponentArray[this.ComponentIndex].HorizontalFactor; int vi = decoder.ComponentArray[this.ComponentIndex].VerticalFactor; 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; } } // Take an existing block (required when progressive): int blockIndex = this.GetBlockIndex(decoder); this.data.Block = decoder.DecodedBlocks[this.ComponentIndex].Buffer[blockIndex].Block; if (!decoder.InputProcessor.UnexpectedEndOfStreamReached) { this.DecodeBlock(decoder, scanIndex); } // Store the decoded block DecodedBlockArray blocks = decoder.DecodedBlocks[this.ComponentIndex]; blocks.Buffer[blockIndex].SaveBlock(this.bx, this.by, ref 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.UnexpectedEndOfStreamReached) { DecoderErrorCode errorCode = decoder.InputProcessor.ReadFullUnsafe(decoder.Temp, 0, 2); if (decoder.InputProcessor.CheckEOFEnsureNoError(errorCode)) { if (decoder.Temp[0] != 0xff || decoder.Temp[1] != expectedRst) { throw new ImageFormatException("Bad RST marker"); } expectedRst++; if (expectedRst == JpegConstants.Markers.RST7 + 1) { expectedRst = JpegConstants.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 } }