Ejemplo n.º 1
0
        public void Init()
        {
            this.WidthInBlocks = (int)MathF.Ceiling(
                MathF.Ceiling(this.Frame.SamplesPerLine / 8F) * this.HorizontalSamplingFactor / this.Frame.MaxHorizontalFactor);

            this.HeightInBlocks = (int)MathF.Ceiling(
                MathF.Ceiling(this.Frame.Scanlines / 8F) * this.VerticalSamplingFactor / this.Frame.MaxVerticalFactor);

            int blocksPerLineForMcu   = this.Frame.McusPerLine * this.HorizontalSamplingFactor;
            int blocksPerColumnForMcu = this.Frame.McusPerColumn * this.VerticalSamplingFactor;

            this.SizeInBlocks = new Size(blocksPerLineForMcu, blocksPerColumnForMcu);

            // For 4-component images (either CMYK or YCbCrK), we only support two
            // hv vectors: [0x11 0x11 0x11 0x11] and [0x22 0x11 0x11 0x22].
            // Theoretically, 4-component JPEG images could mix and match hv values
            // but in practice, those two combinations are the only ones in use,
            // and it simplifies the applyBlack code below if we can assume that:
            // - for CMYK, the C and K channels have full samples, and if the M
            // and Y channels subsample, they subsample both horizontally and
            // vertically.
            // - for YCbCrK, the Y and K channels have full samples.
            if (this.Index == 0 || this.Index == 3)
            {
                this.SubSamplingDivisors = new Size(1, 1);
            }
            else
            {
                PdfJsFrameComponent c0 = this.Frame.Components[0];
                this.SubSamplingDivisors = c0.SamplingFactors.DivideBy(this.SamplingFactors);
            }

            this.SpectralBlocks = this.memoryManager.Allocate2D <Block8x8>(blocksPerColumnForMcu, blocksPerLineForMcu + 1, true);
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Allocates the frame component blocks
        /// </summary>
        public void InitComponents()
        {
            this.McusPerLine   = (int)MathF.Ceiling(this.SamplesPerLine / 8F / this.MaxHorizontalFactor);
            this.McusPerColumn = (int)MathF.Ceiling(this.Scanlines / 8F / this.MaxVerticalFactor);

            for (int i = 0; i < this.ComponentCount; i++)
            {
                PdfJsFrameComponent component = this.Components[i];
                component.Init();
            }
        }
Ejemplo n.º 3
0
 private void DecodeScanBaseline(
     PdfJsHuffmanTables dcHuffmanTables,
     PdfJsHuffmanTables acHuffmanTables,
     PdfJsFrameComponent[] components,
     int componentsLength,
     DoubleBufferedStreamReader stream)
 {
     if (componentsLength == 1)
     {
         PdfJsFrameComponent   component      = components[this.compIndex];
         ref short             blockDataRef   = ref MemoryMarshal.GetReference(MemoryMarshal.Cast <Block8x8, short>(component.SpectralBlocks.Span));
         ref PdfJsHuffmanTable dcHuffmanTable = ref dcHuffmanTables[component.DCHuffmanTableId];
Ejemplo n.º 4
0
 private void DecodeScanBaseline(
     PdfJsHuffmanTables dcHuffmanTables,
     PdfJsHuffmanTables acHuffmanTables,
     PdfJsFrameComponent[] components,
     int componentsLength,
     int mcusPerLine,
     int mcuToRead,
     ref int mcu,
     Stream stream)
 {
     if (componentsLength == 1)
     {
         PdfJsFrameComponent   component      = components[this.compIndex];
         ref PdfJsHuffmanTable dcHuffmanTable = ref dcHuffmanTables[component.DCHuffmanTableId];
         ref PdfJsHuffmanTable acHuffmanTable = ref acHuffmanTables[component.ACHuffmanTableId];
Ejemplo n.º 5
0
        private void ParseBaselineDataInterleaved()
        {
            // Interleaved
            int mcu           = 0;
            int mcusPerColumn = this.frame.McusPerColumn;
            int mcusPerLine   = this.frame.McusPerLine;

            for (int j = 0; j < mcusPerColumn; j++)
            {
                for (int i = 0; i < mcusPerLine; i++)
                {
                    // Scan an interleaved mcu... process components in order
                    for (int k = 0; k < this.componentsLength; k++)
                    {
                        PdfJsFrameComponent component = this.components[k];

                        ref PdfJsHuffmanTable dcHuffmanTable = ref this.dcHuffmanTables[component.DCHuffmanTableId];
                        ref PdfJsHuffmanTable acHuffmanTable = ref this.acHuffmanTables[component.ACHuffmanTableId];
                        ref short             fastACRef      = ref this.fastACTables.GetAcTableReference(component);
                        int h = component.HorizontalSamplingFactor;
                        int v = component.VerticalSamplingFactor;

                        // Scan out an mcu's worth of this component; that's just determined
                        // by the basic H and V specified for the component
                        for (int y = 0; y < v; y++)
                        {
                            for (int x = 0; x < h; x++)
                            {
                                if (this.eof)
                                {
                                    return;
                                }

                                int mcuRow   = mcu / mcusPerLine;
                                int mcuCol   = mcu % mcusPerLine;
                                int blockRow = (mcuRow * v) + y;
                                int blockCol = (mcuCol * h) + x;

                                this.DecodeBlockBaseline(
                                    component,
                                    blockRow,
                                    blockCol,
                                    ref dcHuffmanTable,
                                    ref acHuffmanTable,
                                    ref fastACRef);
                            }
                        }
                    }
Ejemplo n.º 6
0
        /// <summary>
        /// Decodes the spectral scan
        /// </summary>
        /// <param name="frame">The image frame</param>
        /// <param name="stream">The input stream</param>
        /// <param name="dcHuffmanTables">The DC Huffman tables</param>
        /// <param name="acHuffmanTables">The AC Huffman tables</param>
        /// <param name="components">The scan components</param>
        /// <param name="componentIndex">The component index within the array</param>
        /// <param name="componentsLength">The length of the components. Different to the array length</param>
        /// <param name="resetInterval">The reset interval</param>
        /// <param name="spectralStart">The spectral selection start</param>
        /// <param name="spectralEnd">The spectral selection end</param>
        /// <param name="successivePrev">The successive approximation bit high end</param>
        /// <param name="successive">The successive approximation bit low end</param>
        public void DecodeScan(
            PdfJsFrame frame,
            Stream stream,
            PdfJsHuffmanTables dcHuffmanTables,
            PdfJsHuffmanTables acHuffmanTables,
            PdfJsFrameComponent[] components,
            int componentIndex,
            int componentsLength,
            ushort resetInterval,
            int spectralStart,
            int spectralEnd,
            int successivePrev,
            int successive)
        {
            this.markerBuffer            = new byte[2];
            this.compIndex               = componentIndex;
            this.specStart               = spectralStart;
            this.specEnd                 = spectralEnd;
            this.successiveState         = successive;
            this.endOfStreamReached      = false;
            this.unexpectedMarkerReached = false;

            bool progressive = frame.Progressive;
            int  mcusPerLine = frame.McusPerLine;

            int mcu = 0;
            int mcuExpected;

            if (componentsLength == 1)
            {
                mcuExpected = components[this.compIndex].WidthInBlocks * components[this.compIndex].HeightInBlocks;
            }
            else
            {
                mcuExpected = mcusPerLine * frame.McusPerColumn;
            }

            PdfJsFileMarker fileMarker;

            while (mcu < mcuExpected)
            {
                // Reset interval stuff
                int mcuToRead = resetInterval != 0 ? Math.Min(mcuExpected - mcu, resetInterval) : mcuExpected;
                for (int i = 0; i < components.Length; i++)
                {
                    PdfJsFrameComponent c = components[i];
                    c.Pred = 0;
                }

                this.eobrun = 0;

                if (!progressive)
                {
                    this.DecodeScanBaseline(dcHuffmanTables, acHuffmanTables, components, componentsLength, mcusPerLine, mcuToRead, ref mcu, stream);
                }
                else
                {
                    if (this.specStart == 0)
                    {
                        if (successivePrev == 0)
                        {
                            this.DecodeScanDCFirst(dcHuffmanTables, components, componentsLength, mcusPerLine, mcuToRead, ref mcu, stream);
                        }
                        else
                        {
                            this.DecodeScanDCSuccessive(components, componentsLength, mcusPerLine, mcuToRead, ref mcu, stream);
                        }
                    }
                    else
                    {
                        if (successivePrev == 0)
                        {
                            this.DecodeScanACFirst(acHuffmanTables, components, componentsLength, mcusPerLine, mcuToRead, ref mcu, stream);
                        }
                        else
                        {
                            this.DecodeScanACSuccessive(acHuffmanTables, components, componentsLength, mcusPerLine, mcuToRead, ref mcu, stream);
                        }
                    }
                }

                // Find marker
                this.bitsCount   = 0;
                this.accumulator = 0;
                this.bitsUnRead  = 0;
                fileMarker       = PdfJsJpegDecoderCore.FindNextFileMarker(this.markerBuffer, stream);

                // Some bad images seem to pad Scan blocks with e.g. zero bytes, skip past
                // those to attempt to find a valid marker (fixes issue4090.pdf) in original code.
                if (fileMarker.Invalid)
                {
#if DEBUG
                    Debug.WriteLine($"DecodeScan - Unexpected MCU data at {stream.Position}, next marker is: {fileMarker.Marker:X}");
#endif
                }

                ushort marker = fileMarker.Marker;

                // RSTn - We've already read the bytes and altered the position so no need to skip
                if (marker >= PdfJsJpegConstants.Markers.RST0 && marker <= PdfJsJpegConstants.Markers.RST7)
                {
                    continue;
                }

                if (!fileMarker.Invalid)
                {
                    // We've found a valid marker.
                    // Rewind the stream to the position of the marker and break
                    stream.Position = fileMarker.Position;
                    break;
                }
            }

            fileMarker = PdfJsJpegDecoderCore.FindNextFileMarker(this.markerBuffer, stream);

            // Some images include more Scan blocks than expected, skip past those and
            // attempt to find the next valid marker (fixes issue8182.pdf) in original code.
            if (fileMarker.Invalid)
            {
#if DEBUG
                Debug.WriteLine($"DecodeScan - Unexpected MCU data at {stream.Position}, next marker is: {fileMarker.Marker:X}");
#endif
            }
            else
            {
                // We've found a valid marker.
                // Rewind the stream to the position of the marker
                stream.Position = fileMarker.Position;
            }
        }
Ejemplo n.º 7
0
        /// <summary>
        /// A port of Poppler's IDCT method which in turn is taken from:
        /// Christoph Loeffler, Adriaan Ligtenberg, George S. Moschytz,
        /// 'Practical Fast 1-D DCT Algorithms with 11 Multiplications',
        /// IEEE Intl. Conf. on Acoustics, Speech &amp; Signal Processing, 1989, 988-991.
        /// </summary>
        /// <param name="component">The fram component</param>
        /// <param name="blockBufferOffset">The block buffer offset</param>
        /// <param name="computationBuffer">The computational buffer for holding temp values</param>
        /// <param name="quantizationTable">The quantization table</param>
        public static void QuantizeAndInverse(PdfJsFrameComponent component, int blockBufferOffset, ref Span <short> computationBuffer, ref Span <short> quantizationTable)
        {
            Span <short> blockData = component.BlockData.Slice(blockBufferOffset);
            int          v0, v1, v2, v3, v4, v5, v6, v7;
            int          p0, p1, p2, p3, p4, p5, p6, p7;
            int          t;

            // inverse DCT on rows
            for (int row = 0; row < 64; row += 8)
            {
                // gather block data
                p0 = blockData[row];
                p1 = blockData[row + 1];
                p2 = blockData[row + 2];
                p3 = blockData[row + 3];
                p4 = blockData[row + 4];
                p5 = blockData[row + 5];
                p6 = blockData[row + 6];
                p7 = blockData[row + 7];

                // dequant p0
                p0 *= quantizationTable[row];

                // check for all-zero AC coefficients
                if ((p1 | p2 | p3 | p4 | p5 | p6 | p7) == 0)
                {
                    t = ((DctSqrt2 * p0) + 512) >> 10;
                    short st = (short)t;
                    computationBuffer[row]     = st;
                    computationBuffer[row + 1] = st;
                    computationBuffer[row + 2] = st;
                    computationBuffer[row + 3] = st;
                    computationBuffer[row + 4] = st;
                    computationBuffer[row + 5] = st;
                    computationBuffer[row + 6] = st;
                    computationBuffer[row + 7] = st;
                    continue;
                }

                // dequant p1 ... p7
                p1 *= quantizationTable[row + 1];
                p2 *= quantizationTable[row + 2];
                p3 *= quantizationTable[row + 3];
                p4 *= quantizationTable[row + 4];
                p5 *= quantizationTable[row + 5];
                p6 *= quantizationTable[row + 6];
                p7 *= quantizationTable[row + 7];

                // stage 4
                v0 = ((DctSqrt2 * p0) + 128) >> 8;
                v1 = ((DctSqrt2 * p4) + 128) >> 8;
                v2 = p2;
                v3 = p6;
                v4 = ((DctSqrt1D2 * (p1 - p7)) + 128) >> 8;
                v7 = ((DctSqrt1D2 * (p1 + p7)) + 128) >> 8;
                v5 = p3 << 4;
                v6 = p5 << 4;

                // stage 3
                v0 = (v0 + v1 + 1) >> 1;
                v1 = v0 - v1;
                t  = ((v2 * DctSin6) + (v3 * DctCos6) + 128) >> 8;
                v2 = ((v2 * DctCos6) - (v3 * DctSin6) + 128) >> 8;
                v3 = t;
                v4 = (v4 + v6 + 1) >> 1;
                v6 = v4 - v6;
                v7 = (v7 + v5 + 1) >> 1;
                v5 = v7 - v5;

                // stage 2
                v0 = (v0 + v3 + 1) >> 1;
                v3 = v0 - v3;
                v1 = (v1 + v2 + 1) >> 1;
                v2 = v1 - v2;
                t  = ((v4 * DctSin3) + (v7 * DctCos3) + 2048) >> 12;
                v4 = ((v4 * DctCos3) - (v7 * DctSin3) + 2048) >> 12;
                v7 = t;
                t  = ((v5 * DctSin1) + (v6 * DctCos1) + 2048) >> 12;
                v5 = ((v5 * DctCos1) - (v6 * DctSin1) + 2048) >> 12;
                v6 = t;

                // stage 1
                computationBuffer[row]     = (short)(v0 + v7);
                computationBuffer[row + 7] = (short)(v0 - v7);
                computationBuffer[row + 1] = (short)(v1 + v6);
                computationBuffer[row + 6] = (short)(v1 - v6);
                computationBuffer[row + 2] = (short)(v2 + v5);
                computationBuffer[row + 5] = (short)(v2 - v5);
                computationBuffer[row + 3] = (short)(v3 + v4);
                computationBuffer[row + 4] = (short)(v3 - v4);
            }

            // inverse DCT on columns
            for (int col = 0; col < 8; ++col)
            {
                p0 = computationBuffer[col];
                p1 = computationBuffer[col + 8];
                p2 = computationBuffer[col + 16];
                p3 = computationBuffer[col + 24];
                p4 = computationBuffer[col + 32];
                p5 = computationBuffer[col + 40];
                p6 = computationBuffer[col + 48];
                p7 = computationBuffer[col + 56];

                // check for all-zero AC coefficients
                if ((p1 | p2 | p3 | p4 | p5 | p6 | p7) == 0)
                {
                    t = ((DctSqrt2 * p0) + 8192) >> 14;

                    // convert to 8 bit
                    t = (t < -2040) ? 0 : (t >= 2024) ? MaxJSample : (t + 2056) >> 4;
                    short st = (short)t;

                    blockData[col]      = st;
                    blockData[col + 8]  = st;
                    blockData[col + 16] = st;
                    blockData[col + 24] = st;
                    blockData[col + 32] = st;
                    blockData[col + 40] = st;
                    blockData[col + 48] = st;
                    blockData[col + 56] = st;
                    continue;
                }

                // stage 4
                v0 = ((DctSqrt2 * p0) + 2048) >> 12;
                v1 = ((DctSqrt2 * p4) + 2048) >> 12;
                v2 = p2;
                v3 = p6;
                v4 = ((DctSqrt1D2 * (p1 - p7)) + 2048) >> 12;
                v7 = ((DctSqrt1D2 * (p1 + p7)) + 2048) >> 12;
                v5 = p3;
                v6 = p5;

                // stage 3
                // Shift v0 by 128.5 << 5 here, so we don't need to shift p0...p7 when
                // converting to UInt8 range later.
                v0 = ((v0 + v1 + 1) >> 1) + 4112;
                v1 = v0 - v1;
                t  = ((v2 * DctSin6) + (v3 * DctCos6) + 2048) >> 12;
                v2 = ((v2 * DctCos6) - (v3 * DctSin6) + 2048) >> 12;
                v3 = t;
                v4 = (v4 + v6 + 1) >> 1;
                v6 = v4 - v6;
                v7 = (v7 + v5 + 1) >> 1;
                v5 = v7 - v5;

                // stage 2
                v0 = (v0 + v3 + 1) >> 1;
                v3 = v0 - v3;
                v1 = (v1 + v2 + 1) >> 1;
                v2 = v1 - v2;
                t  = ((v4 * DctSin3) + (v7 * DctCos3) + 2048) >> 12;
                v4 = ((v4 * DctCos3) - (v7 * DctSin3) + 2048) >> 12;
                v7 = t;
                t  = ((v5 * DctSin1) + (v6 * DctCos1) + 2048) >> 12;
                v5 = ((v5 * DctCos1) - (v6 * DctSin1) + 2048) >> 12;
                v6 = t;

                // stage 1
                p0 = v0 + v7;
                p7 = v0 - v7;
                p1 = v1 + v6;
                p6 = v1 - v6;
                p2 = v2 + v5;
                p5 = v2 - v5;
                p3 = v3 + v4;
                p4 = v3 - v4;

                // convert to 8-bit integers
                p0 = (p0 < 16) ? 0 : (p0 >= 4080) ? MaxJSample : p0 >> 4;
                p1 = (p1 < 16) ? 0 : (p1 >= 4080) ? MaxJSample : p1 >> 4;
                p2 = (p2 < 16) ? 0 : (p2 >= 4080) ? MaxJSample : p2 >> 4;
                p3 = (p3 < 16) ? 0 : (p3 >= 4080) ? MaxJSample : p3 >> 4;
                p4 = (p4 < 16) ? 0 : (p4 >= 4080) ? MaxJSample : p4 >> 4;
                p5 = (p5 < 16) ? 0 : (p5 >= 4080) ? MaxJSample : p5 >> 4;
                p6 = (p6 < 16) ? 0 : (p6 >= 4080) ? MaxJSample : p6 >> 4;
                p7 = (p7 < 16) ? 0 : (p7 >= 4080) ? MaxJSample : p7 >> 4;

                // store block data
                blockData[col]      = (short)p0;
                blockData[col + 8]  = (short)p1;
                blockData[col + 16] = (short)p2;
                blockData[col + 24] = (short)p3;
                blockData[col + 32] = (short)p4;
                blockData[col + 40] = (short)p5;
                blockData[col + 48] = (short)p6;
                blockData[col + 56] = (short)p7;
            }
        }
Ejemplo n.º 8
0
        /// <summary>
        /// A port of <see href="https://github.com/libjpeg-turbo/libjpeg-turbo/blob/master/jidctfst.c#L171"/>
        /// A 2-D IDCT can be done by 1-D IDCT on each column followed by 1-D IDCT
        /// on each row(or vice versa, but it's more convenient to emit a row at
        /// a time).  Direct algorithms are also available, but they are much more
        /// complex and seem not to be any faster when reduced to code.
        ///
        /// This implementation is based on Arai, Agui, and Nakajima's algorithm for
        /// scaled DCT.Their original paper (Trans.IEICE E-71(11):1095) is in
        /// Japanese, but the algorithm is described in the Pennebaker &amp; Mitchell
        /// JPEG textbook(see REFERENCES section in file README.ijg).  The following
        /// code is based directly on figure 4-8 in P&amp;M.
        /// While an 8-point DCT cannot be done in less than 11 multiplies, it is
        /// possible to arrange the computation so that many of the multiplies are
        /// simple scalings of the final outputs.These multiplies can then be
        /// folded into the multiplications or divisions by the JPEG quantization
        /// table entries.  The AA&amp;N method leaves only 5 multiplies and 29 adds
        /// to be done in the DCT itself.
        /// The primary disadvantage of this method is that with fixed-point math,
        /// accuracy is lost due to imprecise representation of the scaled
        /// quantization values.The smaller the quantization table entry, the less
        /// precise the scaled value, so this implementation does worse with high -
        /// quality - setting files than with low - quality ones.
        /// </summary>
        /// <param name="component">The frame component</param>
        /// <param name="blockBufferOffset">The block buffer offset</param>
        /// <param name="computationBuffer">The computational buffer for holding temp values</param>
        /// <param name="multiplierTable">The multiplier table</param>
        public static void QuantizeAndInverseFast(PdfJsFrameComponent component, int blockBufferOffset, ref Span <short> computationBuffer, ref Span <short> multiplierTable)
        {
            Span <short> blockData = component.BlockData.Slice(blockBufferOffset);
            int          p0, p1, p2, p3, p4, p5, p6, p7;

            for (int col = 0; col < 8; col++)
            {
                // Gather block data
                p0 = blockData[col];
                p1 = blockData[col + 8];
                p2 = blockData[col + 16];
                p3 = blockData[col + 24];
                p4 = blockData[col + 32];
                p5 = blockData[col + 40];
                p6 = blockData[col + 48];
                p7 = blockData[col + 56];

                int tmp0 = p0 * multiplierTable[col];

                // Due to quantization, we will usually find that many of the input
                // coefficients are zero, especially the AC terms.  We can exploit this
                // by short-circuiting the IDCT calculation for any column in which all
                // the AC terms are zero.  In that case each output is equal to the
                // DC coefficient (with scale factor as needed).
                // With typical images and quantization tables, half or more of the
                // column DCT calculations can be simplified this way.
                if ((p1 | p2 | p3 | p4 | p5 | p6 | p7) == 0)
                {
                    short dcval = (short)tmp0;

                    computationBuffer[col]      = dcval;
                    computationBuffer[col + 8]  = dcval;
                    computationBuffer[col + 16] = dcval;
                    computationBuffer[col + 24] = dcval;
                    computationBuffer[col + 32] = dcval;
                    computationBuffer[col + 40] = dcval;
                    computationBuffer[col + 48] = dcval;
                    computationBuffer[col + 56] = dcval;

                    continue;
                }

                // Even part
                int tmp1 = p2 * multiplierTable[col + 16];
                int tmp2 = p4 * multiplierTable[col + 32];
                int tmp3 = p6 * multiplierTable[col + 48];

                int tmp10 = tmp0 + tmp2; // Phase 3
                int tmp11 = tmp0 - tmp2;

                int tmp13 = tmp1 + tmp3;                                    // Phases 5-3
                int tmp12 = Multiply(tmp1 - tmp3, FIX_1_414213562) - tmp13; // 2*c4

                tmp0 = tmp10 + tmp13;                                       // Phase 2
                tmp3 = tmp10 - tmp13;
                tmp1 = tmp11 + tmp12;
                tmp2 = tmp11 - tmp12;

                // Odd Part
                int tmp4 = p1 * multiplierTable[col + 8];
                int tmp5 = p3 * multiplierTable[col + 24];
                int tmp6 = p5 * multiplierTable[col + 40];
                int tmp7 = p7 * multiplierTable[col + 56];

                int z13 = tmp6 + tmp5; // Phase 6
                int z10 = tmp6 - tmp5;
                int z11 = tmp4 + tmp7;
                int z12 = tmp4 - tmp7;

                tmp7  = z11 + z13;                             // Phase 5
                tmp11 = Multiply(z11 - z13, FIX_1_414213562);  // 2*c4

                int z5 = Multiply(z10 + z12, FIX_1_847759065); // 2*c2
                tmp10 = z5 - Multiply(z12, FIX_1_082392200);   // 2*(c2-c6)
                tmp12 = z5 - Multiply(z10, FIX_2_613125930);   // 2*(c2+c6)

                tmp6 = tmp12 - tmp7;                           // Phase 2
                tmp5 = tmp11 - tmp6;
                tmp4 = tmp10 - tmp5;

                computationBuffer[col]      = (short)(tmp0 + tmp7);
                computationBuffer[col + 56] = (short)(tmp0 - tmp7);
                computationBuffer[col + 8]  = (short)(tmp1 + tmp6);
                computationBuffer[col + 48] = (short)(tmp1 - tmp6);
                computationBuffer[col + 16] = (short)(tmp2 + tmp5);
                computationBuffer[col + 40] = (short)(tmp2 - tmp5);
                computationBuffer[col + 24] = (short)(tmp3 + tmp4);
                computationBuffer[col + 32] = (short)(tmp3 - tmp4);
            }

            // Pass 2: process rows from work array, store into output array.
            // Note that we must descale the results by a factor of 8 == 2**3,
            // and also undo the pass 1 bits scaling.
            for (int row = 0; row < 64; row += 8)
            {
                p1 = computationBuffer[row + 1];
                p2 = computationBuffer[row + 2];
                p3 = computationBuffer[row + 3];
                p4 = computationBuffer[row + 4];
                p5 = computationBuffer[row + 5];
                p6 = computationBuffer[row + 6];
                p7 = computationBuffer[row + 7];

                // Add range center and fudge factor for final descale and range-limit.
                int z5 = computationBuffer[row] + (RangeCenter << (Pass1Bits + 3)) + (1 << (Pass1Bits + 2));

                // Check for all-zero AC coefficients
                if ((p1 | p2 | p3 | p4 | p5 | p6 | p7) == 0)
                {
                    byte dcval = Limit[LimitOffset + (RightShift(z5, Pass1Bits + 3) & RangeMask)];

                    blockData[row]     = dcval;
                    blockData[row + 1] = dcval;
                    blockData[row + 2] = dcval;
                    blockData[row + 3] = dcval;
                    blockData[row + 4] = dcval;
                    blockData[row + 5] = dcval;
                    blockData[row + 6] = dcval;
                    blockData[row + 7] = dcval;

                    continue;
                }

                // Even part
                int tmp10 = z5 + p4;
                int tmp11 = z5 - p4;

                int tmp13 = p2 + p6;
                int tmp12 = Multiply(p2 - p6, FIX_1_414213562) - tmp13; // 2*c4

                int tmp0 = tmp10 + tmp13;
                int tmp3 = tmp10 - tmp13;
                int tmp1 = tmp11 + tmp12;
                int tmp2 = tmp11 - tmp12;

                // Odd part
                int z13 = p5 + p3;
                int z10 = p5 - p3;
                int z11 = p1 + p7;
                int z12 = p1 - p7;

                int tmp7 = z11 + z13;                         // Phase 5
                tmp11 = Multiply(z11 - z13, FIX_1_414213562); // 2*c4

                z5    = Multiply(z10 + z12, FIX_1_847759065); // 2*c2
                tmp10 = z5 - Multiply(z12, FIX_1_082392200);  // 2*(c2-c6)
                tmp12 = z5 - Multiply(z10, FIX_2_613125930);  // 2*(c2+c6)

                int tmp6 = tmp12 - tmp7;                      // Phase 2
                int tmp5 = tmp11 - tmp6;
                int tmp4 = tmp10 - tmp5;

                // Final output stage: scale down by a factor of 8, offset, and range-limit
                blockData[row]     = Limit[LimitOffset + (RightShift(tmp0 + tmp7, Pass1Bits + 3) & RangeMask)];
                blockData[row + 7] = Limit[LimitOffset + (RightShift(tmp0 - tmp7, Pass1Bits + 3) & RangeMask)];
                blockData[row + 1] = Limit[LimitOffset + (RightShift(tmp1 + tmp6, Pass1Bits + 3) & RangeMask)];
                blockData[row + 6] = Limit[LimitOffset + (RightShift(tmp1 - tmp6, Pass1Bits + 3) & RangeMask)];
                blockData[row + 2] = Limit[LimitOffset + (RightShift(tmp2 + tmp5, Pass1Bits + 3) & RangeMask)];
                blockData[row + 5] = Limit[LimitOffset + (RightShift(tmp2 - tmp5, Pass1Bits + 3) & RangeMask)];
                blockData[row + 3] = Limit[LimitOffset + (RightShift(tmp3 + tmp4, Pass1Bits + 3) & RangeMask)];
                blockData[row + 4] = Limit[LimitOffset + (RightShift(tmp3 - tmp4, Pass1Bits + 3) & RangeMask)];
            }
        }
Ejemplo n.º 9
0
        /// <summary>
        /// Decodes the spectral scan
        /// </summary>
        /// <param name="frame">The image frame</param>
        /// <param name="stream">The input stream</param>
        /// <param name="dcHuffmanTables">The DC Huffman tables</param>
        /// <param name="acHuffmanTables">The AC Huffman tables</param>
        /// <param name="components">The scan components</param>
        /// <param name="componentIndex">The component index within the array</param>
        /// <param name="componentsLength">The length of the components. Different to the array length</param>
        /// <param name="resetInterval">The reset interval</param>
        /// <param name="spectralStart">The spectral selection start</param>
        /// <param name="spectralEnd">The spectral selection end</param>
        /// <param name="successivePrev">The successive approximation bit high end</param>
        /// <param name="successive">The successive approximation bit low end</param>
        public void DecodeScan(
            PdfJsFrame frame,
            DoubleBufferedStreamReader stream,
            PdfJsHuffmanTables dcHuffmanTables,
            PdfJsHuffmanTables acHuffmanTables,
            PdfJsFrameComponent[] components,
            int componentIndex,
            int componentsLength,
            ushort resetInterval,
            int spectralStart,
            int spectralEnd,
            int successivePrev,
            int successive)
        {
            this.dctZigZag               = ZigZag.CreateUnzigTable();
            this.markerBuffer            = new byte[2];
            this.compIndex               = componentIndex;
            this.specStart               = spectralStart;
            this.specEnd                 = spectralEnd;
            this.successiveState         = successive;
            this.endOfStreamReached      = false;
            this.unexpectedMarkerReached = false;

            bool progressive = frame.Progressive;

            this.mcusPerLine = frame.McusPerLine;

            this.mcu = 0;
            int mcuExpected;

            if (componentsLength == 1)
            {
                mcuExpected = components[this.compIndex].WidthInBlocks * components[this.compIndex].HeightInBlocks;
            }
            else
            {
                mcuExpected = this.mcusPerLine * frame.McusPerColumn;
            }

            while (this.mcu < mcuExpected)
            {
                // Reset interval stuff
                this.mcuToRead = resetInterval != 0 ? Math.Min(mcuExpected - this.mcu, resetInterval) : mcuExpected;
                for (int i = 0; i < components.Length; i++)
                {
                    PdfJsFrameComponent c = components[i];
                    c.Pred = 0;
                }

                this.eobrun = 0;

                if (!progressive)
                {
                    this.DecodeScanBaseline(dcHuffmanTables, acHuffmanTables, components, componentsLength, stream);
                }
                else
                {
                    bool isAc    = this.specStart != 0;
                    bool isFirst = successivePrev == 0;
                    PdfJsHuffmanTables huffmanTables = isAc ? acHuffmanTables : dcHuffmanTables;
                    this.DecodeScanProgressive(huffmanTables, isAc, isFirst, components, componentsLength, stream);
                }

                // Reset
                // TODO: I do not understand why these values are reset? We should surely be tracking the bits across mcu's?
                this.bitsCount = 0;
                this.bitsData  = 0;
                this.unexpectedMarkerReached = false;

                // Some images include more scan blocks than expected, skip past those and
                // attempt to find the next valid marker
                PdfJsFileMarker fileMarker = PdfJsJpegDecoderCore.FindNextFileMarker(this.markerBuffer, stream);
                byte            marker     = fileMarker.Marker;

                // RSTn - We've already read the bytes and altered the position so no need to skip
                if (marker >= PdfJsJpegConstants.Markers.RST0 && marker <= PdfJsJpegConstants.Markers.RST7)
                {
                    continue;
                }

                if (!fileMarker.Invalid)
                {
                    // We've found a valid marker.
                    // Rewind the stream to the position of the marker and break
                    stream.Position = fileMarker.Position;
                    break;
                }

#if DEBUG
                Debug.WriteLine($"DecodeScan - Unexpected MCU data at {stream.Position}, next marker is: {fileMarker.Marker:X}");
#endif
            }
        }
Ejemplo n.º 10
0
 public ref short GetAcTableReference(PdfJsFrameComponent component)
 {
     return(ref this.tables.GetRowSpan(component.ACHuffmanTableId)[0]);
 }