/// <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()); }