/// <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);
        }
        private void Initialize(int quality, bool optimizeCoding)
        {
            TiffJpegEncoder encoder;

            switch (_photometricInterpretation)
            {
            case TiffPhotometricInterpretation.BlackIsZero:
            case TiffPhotometricInterpretation.WhiteIsZero:
                _componentCount = 1;
                encoder         = new TiffJpegEncoder(minimumBufferSegmentSize: MinimumBufferSegmentSize);
                encoder.SetQuantizationTable(JpegStandardQuantizationTable.ScaleByQuality(JpegStandardQuantizationTable.GetLuminanceTable(JpegElementPrecision.Precision8Bit, 0), quality));
                if (optimizeCoding)
                {
                    encoder.SetHuffmanTable(true, 0);
                    encoder.SetHuffmanTable(false, 0);
                }
                else
                {
                    encoder.SetHuffmanTable(true, 0, JpegStandardHuffmanEncodingTable.GetLuminanceDCTable());
                    encoder.SetHuffmanTable(false, 0, JpegStandardHuffmanEncodingTable.GetLuminanceACTable());
                }
                encoder.AddComponent(0, 0, 0, 0, 1, 1);     // Y component
                break;

            case TiffPhotometricInterpretation.RGB:
                _componentCount = 3;
                encoder         = new TiffJpegEncoder(minimumBufferSegmentSize: MinimumBufferSegmentSize);
                encoder.SetQuantizationTable(JpegStandardQuantizationTable.ScaleByQuality(JpegStandardQuantizationTable.GetLuminanceTable(JpegElementPrecision.Precision8Bit, 0), quality));
                if (optimizeCoding)
                {
                    encoder.SetHuffmanTable(true, 0);
                    encoder.SetHuffmanTable(false, 0);
                }
                else
                {
                    encoder.SetHuffmanTable(true, 0, JpegStandardHuffmanEncodingTable.GetLuminanceDCTable());
                    encoder.SetHuffmanTable(false, 0, JpegStandardHuffmanEncodingTable.GetLuminanceACTable());
                }
                encoder.AddComponent(0, 0, 0, 0, 1, 1);     // R component
                encoder.AddComponent(1, 0, 0, 0, 1, 1);     // G component
                encoder.AddComponent(2, 0, 0, 0, 1, 1);     // B component
                break;

            case TiffPhotometricInterpretation.Seperated:
                _componentCount = 4;
                encoder         = new TiffJpegEncoder(minimumBufferSegmentSize: MinimumBufferSegmentSize);
                encoder.SetQuantizationTable(JpegStandardQuantizationTable.ScaleByQuality(JpegStandardQuantizationTable.GetLuminanceTable(JpegElementPrecision.Precision8Bit, 0), quality));
                if (optimizeCoding)
                {
                    encoder.SetHuffmanTable(true, 0);
                    encoder.SetHuffmanTable(false, 0);
                }
                else
                {
                    encoder.SetHuffmanTable(true, 0, JpegStandardHuffmanEncodingTable.GetLuminanceDCTable());
                    encoder.SetHuffmanTable(false, 0, JpegStandardHuffmanEncodingTable.GetLuminanceACTable());
                }
                encoder.AddComponent(0, 0, 0, 0, 1, 1);     // C component
                encoder.AddComponent(1, 0, 0, 0, 1, 1);     // M component
                encoder.AddComponent(2, 0, 0, 0, 1, 1);     // Y component
                encoder.AddComponent(3, 0, 0, 0, 1, 1);     // K component
                break;

            case TiffPhotometricInterpretation.YCbCr:
                _componentCount = 3;
                encoder         = new TiffJpegEncoder(minimumBufferSegmentSize: MinimumBufferSegmentSize);
                encoder.SetQuantizationTable(JpegStandardQuantizationTable.ScaleByQuality(JpegStandardQuantizationTable.GetLuminanceTable(JpegElementPrecision.Precision8Bit, 0), quality));
                encoder.SetQuantizationTable(JpegStandardQuantizationTable.ScaleByQuality(JpegStandardQuantizationTable.GetChrominanceTable(JpegElementPrecision.Precision8Bit, 1), quality));
                if (optimizeCoding)
                {
                    encoder.SetHuffmanTable(true, 0);
                    encoder.SetHuffmanTable(false, 0);
                    encoder.SetHuffmanTable(true, 1);
                    encoder.SetHuffmanTable(false, 1);
                }
                else
                {
                    encoder.SetHuffmanTable(true, 0, JpegStandardHuffmanEncodingTable.GetLuminanceDCTable());
                    encoder.SetHuffmanTable(false, 0, JpegStandardHuffmanEncodingTable.GetLuminanceACTable());
                    encoder.SetHuffmanTable(true, 1, JpegStandardHuffmanEncodingTable.GetChrominanceDCTable());
                    encoder.SetHuffmanTable(false, 1, JpegStandardHuffmanEncodingTable.GetChrominanceACTable());
                }
                encoder.AddComponent(0, 0, 0, 0, (byte)_horizontalSubsampling, (byte)_verticalSubsampling); // Y component
                encoder.AddComponent(1, 1, 1, 1, 1, 1);                                                     // Cb component
                encoder.AddComponent(2, 1, 1, 1, 1, 1);                                                     // Cr component
                break;

            default:
                throw new NotSupportedException("JPEG compression only supports BlackIsZero, WhiteIsZero, RGB, YCbCr and CMYK photometric interpretation.");
            }
            _encoder = encoder;
        }
 public JpegTableWriter(TiffJpegEncoder encoder, bool useSharedHuffmanTables, bool useSharedQuantizationTables)
 {
     _encoder = encoder;
     _useSharedHuffmanTables      = useSharedHuffmanTables;
     _useSharedQuantizationTables = useSharedQuantizationTables;
 }