/// <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> /// 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 } }