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); }
/// <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(); } }
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];
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];
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); } } }
/// <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; } }
/// <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 & 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; } }
/// <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 & Mitchell /// JPEG textbook(see REFERENCES section in file README.ijg). The following /// code is based directly on figure 4-8 in P&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&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)]; } }
/// <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 } }
public ref short GetAcTableReference(PdfJsFrameComponent component) { return(ref this.tables.GetRowSpan(component.ACHuffmanTableId)[0]); }