/// <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();
        }
Exemple #3
0
        /// <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();
                }
            }
        }
Exemple #8
0
        /// <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);
            }
        }