Ejemplo n.º 1
0
        /// <summary>
        /// Decodes a successive approximation refinement block, as specified in section G.1.2.
        /// </summary>
        /// <param name="decoder">The decoder instance</param>
        /// <param name="h">The Huffman tree</param>
        /// <param name="delta">The low transform offset</param>
        private void Refine(JpegDecoderCore decoder, ref HuffmanTree h, int delta)
        {
            Block8x8F *b = this.pointers.Block;

            // Refining a DC component is trivial.
            if (this.zigStart == 0)
            {
                if (this.zigEnd != 0)
                {
                    throw new ImageFormatException("Invalid state for zig DC component");
                }

                bool bit = decoder.DecodeBit();
                if (bit)
                {
                    int stuff = (int)Block8x8F.GetScalarAt(b, 0);

                    // int stuff = (int)b[0];
                    stuff |= delta;

                    // b[0] = stuff;
                    Block8x8F.SetScalarAt(b, 0, stuff);
                }

                return;
            }

            // Refining AC components is more complicated; see sections G.1.2.2 and G.1.2.3.
            int zig = this.zigStart;

            if (this.eobRun == 0)
            {
                for (; zig <= this.zigEnd; zig++)
                {
                    bool done = false;
                    int  z    = 0;
                    byte val  = decoder.DecodeHuffman(ref h);
                    int  val0 = val >> 4;
                    int  val1 = val & 0x0f;

                    switch (val1)
                    {
                    case 0:
                        if (val0 != 0x0f)
                        {
                            this.eobRun = (ushort)(1 << val0);
                            if (val0 != 0)
                            {
                                this.eobRun |= (ushort)decoder.DecodeBits(val0);
                            }

                            done = true;
                        }

                        break;

                    case 1:
                        z = delta;
                        bool bit = decoder.DecodeBit();
                        if (!bit)
                        {
                            z = -z;
                        }

                        break;

                    default:
                        throw new ImageFormatException("Unexpected Huffman code");
                    }

                    if (done)
                    {
                        break;
                    }

                    zig = this.RefineNonZeroes(decoder, zig, val0, delta);
                    if (zig > this.zigEnd)
                    {
                        throw new ImageFormatException($"Too many coefficients {zig} > {this.zigEnd}");
                    }

                    if (z != 0)
                    {
                        // b[Unzig[zig]] = z;
                        Block8x8F.SetScalarAt(b, this.pointers.Unzig[zig], z);
                    }
                }
            }

            if (this.eobRun > 0)
            {
                this.eobRun--;
                this.RefineNonZeroes(decoder, zig, -1, delta);
            }
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Process the current block at (<see cref="bx"/>, <see cref="by"/>)
        /// </summary>
        /// <param name="decoder">The decoder</param>
        /// <param name="i">The index of the scan</param>
        /// <param name="compIndex">The component index</param>
        /// <param name="hi">Horizontal sampling factor at the given component index</param>
        private void ProcessBlockImpl(JpegDecoderCore decoder, int i, int compIndex, int hi)
        {
            var b = this.pointers.Block;

            int huffmannIdx = (AcTableIndex * HuffmanTree.ThRowSize) + this.pointers.Scan[i].AcTableSelector;

            if (this.ah != 0)
            {
                this.Refine(decoder, ref decoder.HuffmanTrees[huffmannIdx], 1 << this.al);
            }
            else
            {
                int zig = this.zigStart;
                if (zig == 0)
                {
                    zig++;

                    // Decode the DC coefficient, as specified in section F.2.2.1.
                    byte value =
                        decoder.DecodeHuffman(
                            ref decoder.HuffmanTrees[(DcTableIndex * HuffmanTree.ThRowSize) + this.pointers.Scan[i].DcTableSelector]);
                    if (value > 16)
                    {
                        throw new ImageFormatException("Excessive DC component");
                    }

                    int deltaDC = decoder.Bits.ReceiveExtend(value, decoder);
                    this.pointers.Dc[compIndex] += deltaDC;

                    // b[0] = dc[compIndex] << al;
                    Block8x8F.SetScalarAt(b, 0, this.pointers.Dc[compIndex] << this.al);
                }

                if (zig <= this.zigEnd && this.eobRun > 0)
                {
                    this.eobRun--;
                }
                else
                {
                    // Decode the AC coefficients, as specified in section F.2.2.2.
                    for (; zig <= this.zigEnd; zig++)
                    {
                        byte value = decoder.DecodeHuffman(ref decoder.HuffmanTrees[huffmannIdx]);
                        byte val0  = (byte)(value >> 4);
                        byte val1  = (byte)(value & 0x0f);
                        if (val1 != 0)
                        {
                            zig += val0;
                            if (zig > this.zigEnd)
                            {
                                break;
                            }

                            int ac = decoder.Bits.ReceiveExtend(val1, decoder);

                            // b[Unzig[zig]] = ac << al;
                            Block8x8F.SetScalarAt(b, this.pointers.Unzig[zig], ac << this.al);
                        }
                        else
                        {
                            if (val0 != 0x0f)
                            {
                                this.eobRun = (ushort)(1 << val0);
                                if (val0 != 0)
                                {
                                    this.eobRun |= (ushort)decoder.DecodeBits(val0);
                                }

                                this.eobRun--;
                                break;
                            }

                            zig += 0x0f;
                        }
                    }
                }
            }

            if (decoder.IsProgressive)
            {
                if (this.zigEnd != Block8x8F.ScalarCount - 1 || this.al != 0)
                {
                    // We haven't completely decoded this 8x8 block. Save the coefficients.
                    // this.ProgCoeffs[compIndex][((@by * XNumberOfMCUs) * hi) + bx] = b.Clone();
                    decoder.ProgCoeffs[compIndex][((this.by * this.XNumberOfMCUs) * hi) + this.bx] = *b;

                    // At this point, we could execute the rest of the loop body to dequantize and
                    // perform the inverse DCT, to save early stages of a progressive image to the
                    // *image.YCbCr buffers (the whole point of progressive encoding), but in Go,
                    // the jpeg.Decode function does not return until the entire image is decoded,
                    // so we "continue" here to avoid wasted computation.
                    return;
                }
            }

            // Dequantize, perform the inverse DCT and store the block to the image.
            Block8x8F.UnZig(b, this.pointers.QuantiazationTable, this.pointers.Unzig);

            DCT.TransformIDCT(ref *b, ref *this.pointers.Temp1, ref *this.pointers.Temp2);

            var destChannel = decoder.GetDestinationChannel(compIndex);
            var destArea    = destChannel.GetOffsetedSubAreaForBlock(this.bx, this.by);

            destArea.LoadColorsFrom(this.pointers.Temp1, this.pointers.Temp2);
        }