/// <inheritdoc /> public void Compress(TiffCompressionContext context, ReadOnlyMemory <byte> input, IBufferWriter <byte> outputWriter) { if (context is null) { throw new ArgumentNullException(nameof(context)); } if (context.PhotometricInterpretation != TiffPhotometricInterpretation.WhiteIsZero && context.PhotometricInterpretation != TiffPhotometricInterpretation.BlackIsZero) { throw new NotSupportedException("ThunderScan compression does not support this photometric interpretation."); } if (context.BitsPerSample.Count != 1 || context.BitsPerSample[0] != 8) { throw new NotSupportedException("Unsupported bits per sample."); } context.BitsPerSample = TiffValueCollection.Single <ushort>(4); Span <byte> buffer = stackalloc byte[4]; var encoder = new ThunderScanEncoder(outputWriter, buffer); int height = context.ImageSize.Height; int bytesPerScanline = context.BytesPerScanline; ReadOnlySpan <byte> inputSpan = input.Span; for (int row = 0; row < height; row++) { ReadOnlySpan <byte> run = inputSpan.Slice(0, bytesPerScanline); inputSpan = inputSpan.Slice(bytesPerScanline); encoder.Encode(run); encoder.Reset(); } }
/// <inheritdoc /> public void Compress(TiffCompressionContext context, ReadOnlyMemory <byte> input, IBufferWriter <byte> outputWriter) { if (context is null) { throw new ArgumentNullException(nameof(context)); } if (context.PhotometricInterpretation != TiffPhotometricInterpretation.WhiteIsZero && context.PhotometricInterpretation != TiffPhotometricInterpretation.BlackIsZero) { throw new NotSupportedException("Modified Huffman compression does not support this photometric interpretation."); } if (context.BitsPerSample.Count != 1 || context.BitsPerSample[0] != 8) { throw new NotSupportedException("Unsupported bits per sample."); } context.BitsPerSample = TiffValueCollection.Single <ushort>(1); ReadOnlySpan <byte> inputSpan = input.Span; int width = context.ImageSize.Width; int height = context.ImageSize.Height; var bitWriter = new BitWriter2(outputWriter, 4096); // Process every scanline for (int row = 0; row < height; row++) { ReadOnlySpan <byte> rowSpan = inputSpan.Slice(0, width); inputSpan = inputSpan.Slice(width); CcittEncodingTable currentTable = CcittEncodingTable.WhiteInstance; CcittEncodingTable otherTable = CcittEncodingTable.BlackInstance; // ModifiedHuffman compression assumes WhiteIsZero photometric interpretation is used. // Since the first run is white run, we look for black pixel in the first iteration. byte nextRunPixel = 255; while (!rowSpan.IsEmpty) { // Get the length of the current run int runLength = rowSpan.IndexOf(nextRunPixel); if (runLength < 0) { runLength = rowSpan.Length; } currentTable.EncodeRun(ref bitWriter, runLength); rowSpan = rowSpan.Slice(runLength); // Switch to the other color CcittHelper.SwapTable(ref currentTable, ref otherTable); nextRunPixel = (byte)~nextRunPixel; } bitWriter.AdvanceAlignByte(); } bitWriter.Flush(); }
/// <inheritdoc /> public void Compress(TiffCompressionContext context, ReadOnlyMemory <byte> input, IBufferWriter <byte> outputWriter) { var lzw = new TiffLzwEncoder(); try { lzw.Initialize(input.Span, outputWriter); lzw.Encode(); } finally { lzw.Dispose(); } }
/// <inheritdoc /> public void Compress(TiffCompressionContext context, ReadOnlyMemory <byte> input, IBufferWriter <byte> outputWriter) { if (context is null) { throw new ArgumentNullException(nameof(context)); } if (outputWriter is null) { throw new ArgumentNullException(nameof(outputWriter)); } input.CopyTo(outputWriter.GetMemory(input.Length)); outputWriter.Advance(input.Length); }
/// <inheritdoc /> public void Compress(TiffCompressionContext context, ReadOnlyMemory <byte> input, IBufferWriter <byte> outputWriter) { if (context is null) { throw new ArgumentNullException(nameof(context)); } if (outputWriter is null) { throw new ArgumentNullException(nameof(outputWriter)); } if (_encoder is null) { throw new InvalidOperationException("JPEG encoder is not initialized."); } if (context.PhotometricInterpretation != _photometricInterpretation) { throw new InvalidOperationException(); } CheckBitsPerSample(context.BitsPerSample); TiffJpegEncoder encoder = _encoder.CloneParameter(); encoder.MemoryPool = context.MemoryPool; // Input JpegBufferInputReader inputReader = Interlocked.Exchange(ref _inputReader, null) ?? new JpegBufferInputReader(); encoder.SetInputReader(inputReader); // Update InputReader inputReader.Update(context.ImageSize.Width, context.ImageSize.Height, _componentCount, input); // Output encoder.SetOutput(outputWriter); // Encoder encoder.Encode(!_useSharedHuffmanTables, !_useSharedQuantizationTables, _optimizeCoding); // Reset state inputReader.Reset(); // Cache the input reader instance Interlocked.CompareExchange(ref _inputReader, inputReader, null); }
/// <inheritdoc /> public void Compress(TiffCompressionContext context, ReadOnlyMemory <byte> input, IBufferWriter <byte> outputWriter) { if (context is null) { throw new ArgumentNullException(nameof(context)); } if (context.PhotometricInterpretation != TiffPhotometricInterpretation.WhiteIsZero && context.PhotometricInterpretation != TiffPhotometricInterpretation.BlackIsZero) { throw new NotSupportedException("Modified Huffman compression does not support this photometric interpretation."); } if (context.BitsPerSample.Count != 1 || context.BitsPerSample[0] != 8) { throw new NotSupportedException("Unsupported bits per sample."); } context.BitsPerSample = TiffValueCollection.Single <ushort>(1); ReadOnlySpan <byte> inputSpan = input.Span; int width = context.ImageSize.Width; int height = context.ImageSize.Height; var bitWriter = new BitWriter2(outputWriter, 4096); ReferenceScanline referenceScanline = new ReferenceScanline(whiteIsZero: true, width); // Process every scanline for (int row = 0; row < height; row++) { ReadOnlySpan <byte> scanline = inputSpan.Slice(0, width); inputSpan = inputSpan.Slice(width); Encode2DScanline(ref bitWriter, referenceScanline, scanline); referenceScanline = new ReferenceScanline(whiteIsZero: true, scanline); } bitWriter.Flush(); }
/// <inheritdoc /> public void Compress(TiffCompressionContext context, ReadOnlyMemory <byte> input, IBufferWriter <byte> outputWriter) { if (context is null) { throw new ArgumentNullException(nameof(context)); } if (outputWriter is null) { throw new ArgumentNullException(nameof(outputWriter)); } var deflater = new Deflater((int)_compressionLevel, noZlibHeaderOrFooter: false); int bytesWritten = deflater.Deflate(outputWriter.GetSpan()); outputWriter.Advance(bytesWritten); deflater.SetInput(input); while (true) { bytesWritten = deflater.Deflate(outputWriter.GetSpan()); if (bytesWritten != 0) { outputWriter.Advance(bytesWritten); } if (deflater.IsFinished) { break; } if (deflater.IsNeedingInput) { deflater.Finish(); } } }
/// <inheritdoc /> public void Compress(TiffCompressionContext context, ReadOnlyMemory <byte> input, IBufferWriter <byte> outputWriter) { if (context is null) { throw new ArgumentNullException(nameof(context)); } if (outputWriter is null) { throw new ArgumentNullException(nameof(outputWriter)); } int height = context.ImageSize.Height; int bytesPerScanline = context.BytesPerScanline; ReadOnlySpan <byte> inputSpan = input.Span; for (int row = 0; row < height; row++) { ReadOnlySpan <byte> run = inputSpan.Slice(0, bytesPerScanline); inputSpan = inputSpan.Slice(bytesPerScanline); PackBits(run, outputWriter); } }