/// <inheritdoc />
        public ValueTask InvokeAsync(TiffImageDecoderContext context, ITiffImageDecoderPipelineNode next)
        {
            if (context is null)
            {
                throw new ArgumentNullException(nameof(context));
            }
            if (next is null)
            {
                throw new ArgumentNullException(nameof(next));
            }

            TiffYCbCrConverter16 converter = _converter;

            int skippedRowOffset = context.SourceImageSize.Width * context.SourceReadOffset.Y;
            int planarByteCount  = sizeof(ushort) * context.SourceImageSize.Width * context.SourceImageSize.Height;

            ReadOnlySpan <byte>   sourceSpan = context.UncompressedData.Span;
            ReadOnlySpan <ushort> sourceY    = MemoryMarshal.Cast <byte, ushort>(sourceSpan.Slice(0, planarByteCount));
            ReadOnlySpan <ushort> sourceCb   = MemoryMarshal.Cast <byte, ushort>(sourceSpan.Slice(planarByteCount, planarByteCount));
            ReadOnlySpan <ushort> sourceCr   = MemoryMarshal.Cast <byte, ushort>(sourceSpan.Slice(2 * planarByteCount, planarByteCount));

            using TiffPixelBufferWriter <TiffRgba64> writer = context.GetWriter <TiffRgba64>();

            int  rows = context.ReadSize.Height;
            int  cols = context.ReadSize.Width;
            bool reverseEndiannessNeeded = context.IsLittleEndian != BitConverter.IsLittleEndian;

            if (reverseEndiannessNeeded)
            {
                for (int row = 0; row < rows; row++)
                {
                    using TiffPixelSpanHandle <TiffRgba64> pixelSpanHandle = writer.GetRowSpan(row);
                    Span <TiffRgba64> rowDestinationSpan = pixelSpanHandle.GetSpan();
                    int rowOffset = skippedRowOffset + row * context.SourceImageSize.Width + context.SourceReadOffset.X;
                    for (int col = 0; col < cols; col++)
                    {
                        int componentOffset = rowOffset + col;
                        rowDestinationSpan[col] = converter.ConvertToRgba64(BinaryPrimitives.ReverseEndianness(sourceY[componentOffset]), BinaryPrimitives.ReverseEndianness(sourceCb[componentOffset]), BinaryPrimitives.ReverseEndianness(sourceCr[componentOffset]));
                    }
                }
            }
            else
            {
                for (int row = 0; row < rows; row++)
                {
                    using TiffPixelSpanHandle <TiffRgba64> pixelSpanHandle = writer.GetRowSpan(row);
                    Span <TiffRgba64> rowDestinationSpan = pixelSpanHandle.GetSpan();
                    int rowOffset = skippedRowOffset + row * context.SourceImageSize.Width + context.SourceReadOffset.X;
                    for (int col = 0; col < cols; col++)
                    {
                        int componentOffset = rowOffset + col;
                        rowDestinationSpan[col] = converter.ConvertToRgba64(sourceY[componentOffset], sourceCb[componentOffset], sourceCr[componentOffset]);
                    }
                }
            }

            return(next.RunAsync(context));
        }
        /// <inheritdoc />
        public ValueTask InvokeAsync(TiffImageDecoderContext context, ITiffImageDecoderPipelineNode next)
        {
            if (context is null)
            {
                throw new ArgumentNullException(nameof(context));
            }
            if (next is null)
            {
                throw new ArgumentNullException(nameof(next));
            }

            TiffYCbCrConverter16 converter = _converter;

            int           elementsPerScanline = 3 * context.SourceImageSize.Width;
            Memory <byte> source     = context.UncompressedData.Slice(context.SourceReadOffset.Y * elementsPerScanline * sizeof(ushort));
            Span <ushort> sourceSpan = MemoryMarshal.Cast <byte, ushort>(source.Span);

            using TiffPixelBufferWriter <TiffRgba64> writer = context.GetWriter <TiffRgba64>();

            int  rows = context.ReadSize.Height;
            int  cols = context.ReadSize.Width;
            bool reverseEndiannessNeeded = context.IsLittleEndian != BitConverter.IsLittleEndian;

            if (reverseEndiannessNeeded)
            {
                for (int row = 0; row < rows; row++)
                {
                    using TiffPixelSpanHandle <TiffRgba64> pixelSpanHandle = writer.GetRowSpan(row);
                    Span <ushort>     rowSourceSpan      = sourceSpan.Slice(3 * context.SourceReadOffset.X, 3 * context.ReadSize.Width);
                    Span <TiffRgba64> rowDestinationSpan = pixelSpanHandle.GetSpan();

                    for (int i = 0; i < rowSourceSpan.Length; i++)
                    {
                        rowSourceSpan[i] = BinaryPrimitives.ReverseEndianness(rowSourceSpan[i]);
                    }

                    converter.ConvertToRgba64(rowSourceSpan, rowDestinationSpan, cols);
                    sourceSpan = sourceSpan.Slice(elementsPerScanline);
                }
            }
            else
            {
                for (int row = 0; row < rows; row++)
                {
                    using TiffPixelSpanHandle <TiffRgba64> pixelSpanHandle = writer.GetRowSpan(row);
                    Span <ushort>     rowSourceSpan      = sourceSpan.Slice(3 * context.SourceReadOffset.X, 3 * context.ReadSize.Width);
                    Span <TiffRgba64> rowDestinationSpan = pixelSpanHandle.GetSpan();

                    converter.ConvertToRgba64(rowSourceSpan, rowDestinationSpan, cols);
                    sourceSpan = sourceSpan.Slice(elementsPerScanline);
                }
            }


            return(next.RunAsync(context));
        }
 /// <summary>
 /// Initialize the middleware.
 /// </summary>
 /// <param name="coefficients">The YCbCrCoefficients tag.</param>
 /// <param name="referenceBlackWhite">The ReferenceBlackWhite tag.</param>
 public TiffChunkyYCbCr161616Interpreter(TiffValueCollection <TiffRational> coefficients, TiffValueCollection <TiffRational> referenceBlackWhite)
 {
     if (!coefficients.IsEmpty && coefficients.Count != 3)
     {
         throw new ArgumentException("coefficient should have 3 none-zero elements.");
     }
     if (!referenceBlackWhite.IsEmpty && referenceBlackWhite.Count != 6)
     {
         throw new ArgumentException("referenceWhiteBlack should have 6 elements.");
     }
     _converter = TiffYCbCrConverter16.Create(coefficients.GetOrCreateArray(), referenceBlackWhite.GetOrCreateArray());
 }