public JpegArithmeticSequentialScanDecoder(JpegDecoder decoder, JpegFrameHeader frameHeader) : base(decoder) { _frameHeader = frameHeader; // Compute maximum sampling factor int maxHorizontalSampling = 1; int maxVerticalSampling = 1; foreach (JpegFrameComponentSpecificationParameters currentFrameComponent in frameHeader.Components !) { maxHorizontalSampling = Math.Max(maxHorizontalSampling, currentFrameComponent.HorizontalSamplingFactor); maxVerticalSampling = Math.Max(maxVerticalSampling, currentFrameComponent.VerticalSamplingFactor); } _maxHorizontalSampling = maxHorizontalSampling; _maxVerticalSampling = maxVerticalSampling; _restartInterval = decoder.GetRestartInterval(); _mcusPerLine = (frameHeader.SamplesPerLine + 8 * maxHorizontalSampling - 1) / (8 * maxHorizontalSampling); _mcusPerColumn = (frameHeader.NumberOfLines + 8 * maxVerticalSampling - 1) / (8 * maxVerticalSampling); _levelShift = 1 << (frameHeader.SamplePrecision - 1); // Pre-allocate the JpegDecodeComponent instances _components = new JpegArithmeticDecodingComponent[frameHeader.NumberOfComponents]; for (int i = 0; i < _components.Length; i++) { _components[i] = new JpegArithmeticDecodingComponent(); } }
public JpegArithmeticProgressiveScanDecoder(JpegDecoder decoder, JpegFrameHeader frameHeader) : base(decoder) { _frameHeader = frameHeader; // Compute maximum sampling factor int maxHorizontalSampling = 1; int maxVerticalSampling = 1; foreach (JpegFrameComponentSpecificationParameters currentFrameComponent in frameHeader.Components !) { maxHorizontalSampling = Math.Max(maxHorizontalSampling, currentFrameComponent.HorizontalSamplingFactor); maxVerticalSampling = Math.Max(maxVerticalSampling, currentFrameComponent.VerticalSamplingFactor); } _mcusPerLine = (frameHeader.SamplesPerLine + 8 * maxHorizontalSampling - 1) / (8 * maxHorizontalSampling); _mcusPerColumn = (frameHeader.NumberOfLines + 8 * maxVerticalSampling - 1) / (8 * maxVerticalSampling); _levelShift = 1 << (frameHeader.SamplePrecision - 1); JpegBlockOutputWriter?outputWriter = decoder.GetOutputWriter(); if (outputWriter is null) { ThrowInvalidDataException("Output writer is not set."); } _outputWriter = outputWriter; _allocator = new JpegBlockAllocator(decoder.MemoryPool); _allocator.Allocate(frameHeader); // Pre-allocate the JpegDecodeComponent instances _components = new JpegArithmeticDecodingComponent[frameHeader.NumberOfComponents]; for (int i = 0; i < _components.Length; i++) { _components[i] = new JpegArithmeticDecodingComponent(); } }
public JpegHuffmanLosslessScanDecoder(JpegDecoder decoder, JpegFrameHeader frameHeader) : base(decoder) { _frameHeader = frameHeader; // Compute maximum sampling factor int maxHorizontalSampling = 1; int maxVerticalSampling = 1; foreach (JpegFrameComponentSpecificationParameters currentFrameComponent in frameHeader.Components !) { maxHorizontalSampling = Math.Max(maxHorizontalSampling, currentFrameComponent.HorizontalSamplingFactor); maxVerticalSampling = Math.Max(maxVerticalSampling, currentFrameComponent.VerticalSamplingFactor); } _restartInterval = decoder.GetRestartInterval(); _mcusPerLine = (frameHeader.SamplesPerLine + maxHorizontalSampling - 1) / maxHorizontalSampling; _mcusPerColumn = (frameHeader.NumberOfLines + maxVerticalSampling - 1) / maxVerticalSampling; JpegBlockOutputWriter?outputWriter = decoder.GetOutputWriter(); if (outputWriter is null) { ThrowInvalidDataException("Output writer is not set."); } _allocator = new JpegPartialScanlineAllocator(outputWriter, decoder.MemoryPool); _allocator.Allocate(frameHeader); // Pre-allocate the JpegDecodeComponent instances _components = new JpegHuffmanDecodingComponent[frameHeader.NumberOfComponents]; for (int i = 0; i < _components.Length; i++) { _components[i] = new JpegHuffmanDecodingComponent(); } }
public void Encode(bool writeHuffmanTables, bool writeQuantizationTables, bool optimizeCoding) { JpegWriter writer = CreateJpegWriter(); WriteStartOfImage(ref writer); if (writeQuantizationTables) { WriteQuantizationTables(ref writer); } JpegFrameHeader frameHeader = WriteStartOfFrame(ref writer); JpegBlockAllocator?allocator = optimizeCoding ? new JpegBlockAllocator(MemoryPool) : null; try { if (!(allocator is null)) { allocator.Allocate(frameHeader); TransformBlocks(allocator); BuildHuffmanTables(frameHeader, allocator, false); WriteHuffmanTables(ref writer); WriteStartOfScan(ref writer); WritePreparedScanData(frameHeader, allocator, ref writer); } else { if (writeHuffmanTables) { WriteHuffmanTables(ref writer); } WriteStartOfScan(ref writer); WriteScanData(ref writer); } }
public void Decompress(TiffDecompressionContext context, ReadOnlyMemory <byte> input, Memory <byte> output) { // Copy frame header JpegFrameHeader frameHeader = _frameHeader; frameHeader = new JpegFrameHeader(frameHeader.SamplePrecision, (ushort)context.ImageSize.Height, (ushort)context.ImageSize.Width, frameHeader.NumberOfComponents, frameHeader.Components); var decoder = new JpegDecoder(); decoder.StartOfFrame = JpegMarker.StartOfFrame0; decoder.MemoryPool = context.MemoryPool; decoder.SetFrameHeader(frameHeader); decoder.SetRestartInterval(_restartInterval); foreach (ComponentInfo componentInfo in _components) { decoder.SetQuantizationTable(componentInfo.QuantizationTable); decoder.SetHuffmanTable(componentInfo.DcTable); decoder.SetHuffmanTable(componentInfo.AcTable); } var outputWriter = new JpegBuffer8BitOutputWriter(context.ImageSize.Width, context.SkippedScanlines, context.SkippedScanlines + context.RequestedScanlines, decoder.NumberOfComponents, output); decoder.SetOutputWriter(outputWriter); var reader = new JpegReader(input); decoder.ProcessScan(ref reader, _scanHeader); }
public void Initialize(ushort restartInterval, ushort[] subsamplingFactors) { _restartInterval = restartInterval; // Make sure everything is initialized if (_components.Length == 0) { throw new InvalidDataException(); } foreach (ComponentInfo component in _components) { if (!component.IsInitialized) { throw new InvalidDataException(); } } var frameComponents = new JpegFrameComponentSpecificationParameters[_components.Length]; var scanComponents = new JpegScanComponentSpecificationParameters[_components.Length]; // Special case for YCbCr. if (subsamplingFactors.Length == 2) { if (frameComponents.Length != 3) { // YCbCr image must have 3 components. throw new InvalidDataException(); } if (subsamplingFactors[0] != 1 && subsamplingFactors[0] != 2 && subsamplingFactors[0] != 4) { throw new InvalidDataException("Subsampling factor other than 1,2,4 is not supported."); } if (subsamplingFactors[1] != 1 && subsamplingFactors[1] != 2 && subsamplingFactors[1] != 4) { throw new InvalidDataException("Subsampling factor other than 1,2,4 is not supported."); } ushort maxFactor = Math.Max(subsamplingFactors[0], subsamplingFactors[1]); frameComponents[0] = new JpegFrameComponentSpecificationParameters(0, (byte)maxFactor, (byte)maxFactor, 0); frameComponents[1] = new JpegFrameComponentSpecificationParameters(1, (byte)(maxFactor / subsamplingFactors[0]), (byte)(maxFactor / subsamplingFactors[1]), 1); frameComponents[2] = new JpegFrameComponentSpecificationParameters(2, (byte)(maxFactor / subsamplingFactors[0]), (byte)(maxFactor / subsamplingFactors[1]), 2); } else { for (int i = 0; i < frameComponents.Length; i++) { frameComponents[i] = new JpegFrameComponentSpecificationParameters((byte)i, 1, 1, (byte)i); } } for (int i = 0; i < scanComponents.Length; i++) { scanComponents[i] = new JpegScanComponentSpecificationParameters((byte)i, (byte)i, (byte)i); } _frameHeader = new JpegFrameHeader(8, 0, 0, (byte)frameComponents.Length, frameComponents); _scanHeader = new JpegScanHeader((byte)scanComponents.Length, scanComponents, 0, 0, 0, 0); }
protected int InitDecodeComponents(JpegFrameHeader frameHeader, JpegScanHeader scanHeader, Span <JpegArithmeticDecodingComponent> components) { Debug.Assert(!(frameHeader.Components is null)); Debug.Assert(!(scanHeader.Components is null)); // Compute maximum sampling factor int maxHorizontalSampling = 1; int maxVerticalSampling = 1; foreach (JpegFrameComponentSpecificationParameters currentFrameComponent in frameHeader.Components !) { maxHorizontalSampling = Math.Max(maxHorizontalSampling, currentFrameComponent.HorizontalSamplingFactor); maxVerticalSampling = Math.Max(maxVerticalSampling, currentFrameComponent.VerticalSamplingFactor); } // Resolve each component if (components.Length < scanHeader.NumberOfComponents) { throw new InvalidOperationException(); } for (int i = 0; i < scanHeader.NumberOfComponents; i++) { JpegScanComponentSpecificationParameters scanComponenet = scanHeader.Components ![i];
public override void ProcessScan(ref JpegReader reader, JpegScanHeader scanHeader) { JpegFrameHeader frameHeader = _frameHeader; JpegBlockOutputWriter?outputWriter = Decoder.GetOutputWriter(); if (frameHeader.Components is null) { ThrowInvalidDataException(); } if (scanHeader.Components is null) { ThrowInvalidDataException(); } if (outputWriter is null) { ThrowInvalidDataException(); } // Resolve each component Span <JpegArithmeticDecodingComponent> components = _components.AsSpan(0, InitDecodeComponents(frameHeader, scanHeader, _components)); foreach (JpegArithmeticDecodingComponent component in _components) { component.DcPredictor = 0; component.DcContext = 0; component.DcStatistics?.Reset(); component.AcStatistics?.Reset(); } Reset(); // Prepare int maxHorizontalSampling = _maxHorizontalSampling; int maxVerticalSampling = _maxVerticalSampling; int mcusBeforeRestart = _restartInterval; int mcusPerLine = _mcusPerLine; int mcusPerColumn = _mcusPerColumn; int levelShift = _levelShift; JpegBitReader bitReader = new JpegBitReader(reader.RemainingBytes); // DCT Block JpegBlock8x8F blockFBuffer = default; JpegBlock8x8F outputFBuffer = default; JpegBlock8x8F tempFBuffer = default; JpegBlock8x8 outputBuffer; for (int rowMcu = 0; rowMcu < mcusPerColumn; rowMcu++) { int offsetY = rowMcu * maxVerticalSampling; for (int colMcu = 0; colMcu < mcusPerLine; colMcu++) { int offsetX = colMcu * maxHorizontalSampling; // Scan an interleaved mcu... process components in order foreach (JpegArithmeticDecodingComponent component in components) { int index = component.ComponentIndex; int h = component.HorizontalSamplingFactor; int v = component.VerticalSamplingFactor; int hs = component.HorizontalSubsamplingFactor; int vs = component.VerticalSubsamplingFactor; for (int y = 0; y < v; y++) { int blockOffsetY = (offsetY + y) * 8; for (int x = 0; x < h; x++) { // Read MCU outputBuffer = default; ReadBlock(ref bitReader, component, ref outputBuffer); // Dequantization DequantizeBlockAndUnZigZag(component.QuantizationTable, ref outputBuffer, ref blockFBuffer); // IDCT FastFloatingPointDCT.TransformIDCT(ref blockFBuffer, ref outputFBuffer, ref tempFBuffer); // Level shift ShiftDataLevel(ref outputFBuffer, ref outputBuffer, levelShift); // CopyToOutput WriteBlock(outputWriter, ref Unsafe.As <JpegBlock8x8, short>(ref outputBuffer), index, (offsetX + x) * 8, blockOffsetY, hs, vs); } } } // Handle restart if (_restartInterval > 0 && (--mcusBeforeRestart) == 0) { bitReader.AdvanceAlignByte(); JpegMarker marker = bitReader.TryReadMarker(); if (marker == JpegMarker.EndOfImage) { int bytesConsumedEoi = reader.RemainingByteCount - bitReader.RemainingBits / 8; reader.TryAdvance(bytesConsumedEoi - 2); return; } if (!marker.IsRestartMarker()) { throw new InvalidOperationException("Expect restart marker."); } mcusBeforeRestart = _restartInterval; foreach (JpegArithmeticDecodingComponent component in components) { component.DcPredictor = 0; component.DcContext = 0; component.DcStatistics?.Reset(); component.AcStatistics?.Reset(); } Reset(); } } } bitReader.AdvanceAlignByte(); int bytesConsumed = reader.RemainingByteCount - bitReader.RemainingBits / 8; if (bitReader.TryPeekMarker() != 0) { if (!bitReader.TryPeekMarker().IsRestartMarker()) { bytesConsumed -= 2; } } reader.TryAdvance(bytesConsumed); }
public static JpegScanDecoder?Create(JpegMarker sofMarker, JpegDecoder decoder, JpegFrameHeader header) { switch (sofMarker) { case JpegMarker.StartOfFrame0: case JpegMarker.StartOfFrame1: return(new JpegHuffmanBaselineScanDecoder(decoder, header)); case JpegMarker.StartOfFrame2: return(new JpegHuffmanProgressiveScanDecoder(decoder, header)); case JpegMarker.StartOfFrame3: return(new JpegHuffmanLosslessScanDecoder(decoder, header)); case JpegMarker.StartOfFrame9: return(new JpegArithmeticSequentialScanDecoder(decoder, header)); case JpegMarker.StartOfFrame10: return(new JpegArithmeticProgressiveScanDecoder(decoder, header)); default: return(null); } }