/// <summary> /// Decodes the image data for chunky encoded pixel data. /// </summary> /// <typeparam name="TPixel">The pixel format.</typeparam> /// <param name="frame">The image frame to decode data into.</param> /// <param name="rowsPerStrip">The rows per strip.</param> /// <param name="stripOffsets">The strip offsets.</param> /// <param name="stripByteCounts">The strip byte counts.</param> /// <param name="cancellationToken">The token to monitor cancellation.</param> private void DecodeStripsChunky <TPixel>(ImageFrame <TPixel> frame, int rowsPerStrip, Span <ulong> stripOffsets, Span <ulong> stripByteCounts, CancellationToken cancellationToken) where TPixel : unmanaged, IPixel <TPixel> { // If the rowsPerStrip has the default value, which is effectively infinity. That is, the entire image is one strip. if (rowsPerStrip == TiffConstants.RowsPerStripInfinity) { rowsPerStrip = frame.Height; } int uncompressedStripSize = this.CalculateStripBufferSize(frame.Width, rowsPerStrip); int bitsPerPixel = this.BitsPerPixel; using IMemoryOwner <byte> stripBuffer = this.memoryAllocator.Allocate <byte>(uncompressedStripSize, AllocationOptions.Clean); Span <byte> stripBufferSpan = stripBuffer.GetSpan(); Buffer2D <TPixel> pixels = frame.PixelBuffer; using TiffBaseDecompressor decompressor = TiffDecompressorsFactory.Create( this.Configuration, this.CompressionType, this.memoryAllocator, this.PhotometricInterpretation, frame.Width, bitsPerPixel, this.ColorType, this.Predictor, this.FaxCompressionOptions, this.JpegTables, this.FillOrder, this.byteOrder); TiffBaseColorDecoder <TPixel> colorDecoder = TiffColorDecoderFactory <TPixel> .Create( this.Configuration, this.memoryAllocator, this.ColorType, this.BitsPerSample, this.ColorMap, this.ReferenceBlackAndWhite, this.YcbcrCoefficients, this.YcbcrSubSampling, this.byteOrder); for (int stripIndex = 0; stripIndex < stripOffsets.Length; stripIndex++) { cancellationToken.ThrowIfCancellationRequested(); int stripHeight = stripIndex < stripOffsets.Length - 1 || frame.Height % rowsPerStrip == 0 ? rowsPerStrip : frame.Height % rowsPerStrip; int top = rowsPerStrip * stripIndex; if (top + stripHeight > frame.Height) { // Make sure we ignore any strips that are not needed for the image (if too many are present). break; } decompressor.Decompress( this.inputStream, stripOffsets[stripIndex], stripByteCounts[stripIndex], stripHeight, stripBufferSpan); colorDecoder.Decode(stripBufferSpan, pixels, 0, top, frame.Width, stripHeight); } }
/// <summary> /// Decodes the image data for planar encoded pixel data. /// </summary> /// <typeparam name="TPixel">The pixel format.</typeparam> /// <param name="frame">The image frame to decode data into.</param> /// <param name="rowsPerStrip">The number of rows per strip of data.</param> /// <param name="stripOffsets">An array of byte offsets to each strip in the image.</param> /// <param name="stripByteCounts">An array of the size of each strip (in bytes).</param> /// <param name="cancellationToken">The token to monitor cancellation.</param> private void DecodeStripsPlanar <TPixel>(ImageFrame <TPixel> frame, int rowsPerStrip, Span <ulong> stripOffsets, Span <ulong> stripByteCounts, CancellationToken cancellationToken) where TPixel : unmanaged, IPixel <TPixel> { int stripsPerPixel = this.BitsPerSample.Channels; int stripsPerPlane = stripOffsets.Length / stripsPerPixel; int bitsPerPixel = this.BitsPerPixel; Buffer2D <TPixel> pixels = frame.PixelBuffer; var stripBuffers = new IMemoryOwner <byte> [stripsPerPixel]; try { for (int stripIndex = 0; stripIndex < stripBuffers.Length; stripIndex++) { int uncompressedStripSize = this.CalculateStripBufferSize(frame.Width, rowsPerStrip, stripIndex); stripBuffers[stripIndex] = this.memoryAllocator.Allocate <byte>(uncompressedStripSize); } using TiffBaseDecompressor decompressor = TiffDecompressorsFactory.Create( this.Configuration, this.CompressionType, this.memoryAllocator, this.PhotometricInterpretation, frame.Width, bitsPerPixel, this.ColorType, this.Predictor, this.FaxCompressionOptions, this.JpegTables, this.FillOrder, this.byteOrder); TiffBasePlanarColorDecoder <TPixel> colorDecoder = TiffColorDecoderFactory <TPixel> .CreatePlanar( this.ColorType, this.BitsPerSample, this.ColorMap, this.ReferenceBlackAndWhite, this.YcbcrCoefficients, this.YcbcrSubSampling, this.byteOrder); for (int i = 0; i < stripsPerPlane; i++) { cancellationToken.ThrowIfCancellationRequested(); int stripHeight = i < stripsPerPlane - 1 || frame.Height % rowsPerStrip == 0 ? rowsPerStrip : frame.Height % rowsPerStrip; int stripIndex = i; for (int planeIndex = 0; planeIndex < stripsPerPixel; planeIndex++) { decompressor.Decompress( this.inputStream, stripOffsets[stripIndex], stripByteCounts[stripIndex], stripHeight, stripBuffers[planeIndex].GetSpan()); stripIndex += stripsPerPlane; } colorDecoder.Decode(stripBuffers, pixels, 0, rowsPerStrip * i, frame.Width, stripHeight); } } finally { foreach (IMemoryOwner <byte> buf in stripBuffers) { buf?.Dispose(); } } }