From 4560f57eb5f6f4da5048c2aa5b224e6ea530a841 Mon Sep 17 00:00:00 2001 From: antonfirsov Date: Wed, 28 Dec 2016 20:51:48 +0100 Subject: [PATCH] docs --- .../Jpg/Components/Decoder/JpegScanDecoder.cs | 292 +++++++++++------- 1 file changed, 178 insertions(+), 114 deletions(-) diff --git a/src/ImageSharp/Formats/Jpg/Components/Decoder/JpegScanDecoder.cs b/src/ImageSharp/Formats/Jpg/Components/Decoder/JpegScanDecoder.cs index ea2ab9230..34e51eaf0 100644 --- a/src/ImageSharp/Formats/Jpg/Components/Decoder/JpegScanDecoder.cs +++ b/src/ImageSharp/Formats/Jpg/Components/Decoder/JpegScanDecoder.cs @@ -27,20 +27,45 @@ namespace ImageSharp.Formats.Jpg [StructLayout(LayoutKind.Sequential)] public struct ComponentData { + /// + /// The main input block + /// public Block8x8F Block; + /// + /// Temporal block 1 to store intermediate and/or final computation results + /// public Block8x8F Temp1; + /// + /// Temporal block 2 to store intermediate and/or final computation results + /// public Block8x8F Temp2; + /// + /// The quantization table as + /// public Block8x8F QuantiazationTable; + /// + /// The jpeg unzig data + /// public UnzigData Unzig; + /// + /// The no-idea-what's this data + /// public fixed byte ScanData[3 * JpegDecoderCore.MaxComponents]; + /// + /// The DC data + /// public fixed int Dc[JpegDecoderCore.MaxComponents]; + /// + /// Creates and initializes a new instance + /// + /// public static ComponentData Create() { ComponentData data = default(ComponentData); @@ -114,26 +139,56 @@ namespace ImageSharp.Formats.Jpg // significant bit. // For baseline JPEGs, these parameters are hard-coded to 0/63/0/0. + /// + /// Start index of the zig-zag selection bound + /// private int zigStart; + /// + /// End index of the zig-zag selection bound + /// private int zigEnd; + /// + /// Successive approximation high value + /// private int ah; + /// + /// Successive approximation high and low value + /// private int al; // XNumberOfMCUs and YNumberOfMCUs are the number of MCUs (Minimum Coded Units) in the image. + /// + /// Number of MCU-s (Minimum Coded Units) on X axis + /// public int XNumberOfMCUs; + /// + /// Number of MCU-s (Minimum Coded Units) in Y axis + /// public int YNumberOfMCUs; private int scanComponentCount; + /// + /// The buffer + /// private ComponentData Data; + /// + /// Pointers to elements of + /// private ComponentPointers Pointers; + /// + /// Initializes the default instance after creation + /// + /// + /// + /// public static void Init(JpegScanDecoder* p, JpegDecoderCore decoder, int remaining) { p->Data = ComponentData.Create(); @@ -141,6 +196,129 @@ namespace ImageSharp.Formats.Jpg p->InitImpl(decoder, remaining); } + /// + /// Reads the blocks from the -s stream, and processes them into the corresponding instances. + /// + /// + public void ProcessBlocks(JpegDecoderCore decoder) + { + int blockCount = 0; + int mcu = 0; + byte expectedRst = JpegConstants.Markers.RST0; + + for (int my = 0; my < this.YNumberOfMCUs; my++) + { + for (int mx = 0; mx < this.XNumberOfMCUs; mx++) + { + for (int i = 0; i < this.scanComponentCount; i++) + { + int compIndex = this.Pointers.Scan[i].Index; + int hi = decoder.ComponentArray[compIndex].HorizontalFactor; + int vi = decoder.ComponentArray[compIndex].VerticalFactor; + + for (int j = 0; j < hi * vi; j++) + { + // 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 + if (this.scanComponentCount != 1) + { + this.bx = (hi * mx) + (j % hi); + this.by = (vi * my) + (j / hi); + } + else + { + int q = this.XNumberOfMCUs * hi; + this.bx = blockCount % q; + this.by = blockCount / q; + blockCount++; + if (this.bx * 8 >= decoder.ImageWidth || this.by * 8 >= decoder.ImageHeight) + { + continue; + } + } + + int qtIndex = decoder.ComponentArray[compIndex].Selector; + + // TODO: Reading & processing blocks should be done in 2 separate loops. The second one could be parallelized. The first one could be async. + + this.Data.QuantiazationTable = decoder.QuantizationTables[qtIndex]; + + //Load the previous partially decoded coefficients, if applicable. + if (decoder.IsProgressive) + { + int blockIndex = ((this.by * this.XNumberOfMCUs) * hi) + this.bx; + this.Data.Block = decoder.ProgCoeffs[compIndex][blockIndex]; + } + else + { + this.Data.Block.Clear(); + } + + this.ProcessBlockImpl(decoder, i, compIndex, hi); + } + + // for j + } + + // for i + mcu++; + + if (decoder.RestartInterval > 0 && mcu % decoder.RestartInterval == 0 && mcu < this.XNumberOfMCUs * this.YNumberOfMCUs) + { + // 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. + decoder.ReadFull(decoder.Temp, 0, 2); + 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.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. + decoder.EobRun = 0; + } + } + + // for mx + } + } + + /// + /// The implementation part of as an instance method. + /// + /// The + /// The remaining bytes private void InitImpl(JpegDecoderCore decoder, int remaining) { if (decoder.ComponentCount == 0) @@ -283,120 +461,6 @@ namespace ImageSharp.Formats.Jpg } } - public void ProcessBlocks(JpegDecoderCore decoder) - { - int blockCount = 0; - int mcu = 0; - byte expectedRst = JpegConstants.Markers.RST0; - - for (int my = 0; my < this.YNumberOfMCUs; my++) - { - for (int mx = 0; mx < this.XNumberOfMCUs; mx++) - { - for (int i = 0; i < this.scanComponentCount; i++) - { - int compIndex = this.Pointers.Scan[i].Index; - int hi = decoder.ComponentArray[compIndex].HorizontalFactor; - int vi = decoder.ComponentArray[compIndex].VerticalFactor; - - for (int j = 0; j < hi * vi; j++) - { - // 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 - if (this.scanComponentCount != 1) - { - this.bx = (hi * mx) + (j % hi); - this.by = (vi * my) + (j / hi); - } - else - { - int q = this.XNumberOfMCUs * hi; - this.bx = blockCount % q; - this.by = blockCount / q; - blockCount++; - if (this.bx * 8 >= decoder.ImageWidth || this.by * 8 >= decoder.ImageHeight) - { - continue; - } - } - - int qtIndex = decoder.ComponentArray[compIndex].Selector; - - // TODO: Reading & processing blocks should be done in 2 separate loops. The second one could be parallelized. The first one could be async. - - this.Data.QuantiazationTable = decoder.QuantizationTables[qtIndex]; - - //Load the previous partially decoded coefficients, if applicable. - if (decoder.IsProgressive) - { - int blockIndex = ((this.by * this.XNumberOfMCUs) * hi) + this.bx; - this.Data.Block = decoder.ProgCoeffs[compIndex][blockIndex]; - } - else - { - this.Data.Block.Clear(); - } - - this.ProcessBlockImpl(decoder, i, compIndex, hi); - } - - // for j - } - - // for i - mcu++; - - if (decoder.RestartInterval > 0 && mcu % decoder.RestartInterval == 0 && mcu < this.XNumberOfMCUs * this.YNumberOfMCUs) - { - // 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. - decoder.ReadFull(decoder.Temp, 0, 2); - 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.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. - decoder.EobRun = 0; - } - } - - // for mx - } - } - /// /// Decodes a successive approximation refinement block, as specified in section G.1.2. ///