diff --git a/src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs b/src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs index 419fbc31ca..177a93d247 100644 --- a/src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs +++ b/src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs @@ -219,21 +219,57 @@ namespace SixLabors.ImageSharp.Formats.Tiff int rowsPerStrip = tags.GetValue(ExifTag.RowsPerStrip) != null ? (int)tags.GetValue(ExifTag.RowsPerStrip).Value : TiffConstants.RowsPerStripInfinity; - var stripOffsets = (Array)tags.GetValueInternal(ExifTag.StripOffsets)?.GetValue(); - var stripByteCounts = (Array)tags.GetValueInternal(ExifTag.StripByteCounts)?.GetValue(); + var stripOffsetsArray = (Array)tags.GetValueInternal(ExifTag.StripOffsets).GetValue(); + var stripByteCountsArray = (Array)tags.GetValueInternal(ExifTag.StripByteCounts).GetValue(); + + IMemoryOwner stripOffsetsMemory = this.ConvertNumbers(stripOffsetsArray, out Span stripOffsets); + IMemoryOwner stripByteCountsMemory = this.ConvertNumbers(stripByteCountsArray, out Span stripByteCounts); if (this.PlanarConfiguration == TiffPlanarConfiguration.Planar) { - this.DecodeStripsPlanar(frame, rowsPerStrip, stripOffsets, stripByteCounts, cancellationToken); + this.DecodeStripsPlanar( + frame, + rowsPerStrip, + stripOffsets, + stripByteCounts, + cancellationToken); } else { - this.DecodeStripsChunky(frame, rowsPerStrip, stripOffsets, stripByteCounts, cancellationToken); + this.DecodeStripsChunky( + frame, + rowsPerStrip, + stripOffsets, + stripByteCounts, + cancellationToken); } + stripOffsetsMemory?.Dispose(); + stripByteCountsMemory?.Dispose(); return frame; } + private IMemoryOwner ConvertNumbers(Array array, out Span span) + { + if (array is Number[] numbers) + { + IMemoryOwner memory = this.memoryAllocator.Allocate(numbers.Length); + span = memory.GetSpan(); + for (int i = 0; i < numbers.Length; i++) + { + span[i] = (uint)numbers[i]; + } + + return memory; + } + else + { + DebugGuard.IsTrue(array is ulong[], $"Expected {nameof(UInt64)} array."); + span = (ulong[])array; + return null; + } + } + /// /// Calculates the size (in bytes) for a pixel buffer using the determined color format. /// @@ -284,7 +320,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff /// An array of byte offsets to each strip in the image. /// An array of the size of each strip (in bytes). /// The token to monitor cancellation. - private void DecodeStripsPlanar(ImageFrame frame, int rowsPerStrip, Array stripOffsets, Array stripByteCounts, CancellationToken cancellationToken) + private void DecodeStripsPlanar(ImageFrame frame, int rowsPerStrip, Span stripOffsets, Span stripByteCounts, CancellationToken cancellationToken) where TPixel : unmanaged, IPixel { int stripsPerPixel = this.BitsPerSample.Channels; @@ -335,26 +371,13 @@ namespace SixLabors.ImageSharp.Formats.Tiff int stripIndex = i; for (int planeIndex = 0; planeIndex < stripsPerPixel; planeIndex++) { - ulong offset = stripOffsets.GetValue(stripIndex) switch - { - ulong val => val, - Number val => (uint)val, - _ => throw TiffThrowHelper.ThrowImageFormatException("Expected Number or Long8 array") - }; - - ulong count = stripByteCounts.GetValue(stripIndex) switch - { - ulong val => val, - Number val => (uint)val, - _ => throw TiffThrowHelper.ThrowImageFormatException("Expected Number or Long8 array") - }; - decompressor.Decompress( this.inputStream, - offset, - count, + stripOffsets[stripIndex], + stripByteCounts[stripIndex], stripHeight, stripBuffers[planeIndex].GetSpan()); + stripIndex += stripsPerPlane; } @@ -379,7 +402,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff /// The strip offsets. /// The strip byte counts. /// The token to monitor cancellation. - private void DecodeStripsChunky(ImageFrame frame, int rowsPerStrip, Array stripOffsets, Array stripByteCounts, CancellationToken cancellationToken) + private void DecodeStripsChunky(ImageFrame frame, int rowsPerStrip, Span stripOffsets, Span stripByteCounts, CancellationToken cancellationToken) where TPixel : unmanaged, IPixel { // If the rowsPerStrip has the default value, which is effectively infinity. That is, the entire image is one strip. @@ -435,24 +458,10 @@ namespace SixLabors.ImageSharp.Formats.Tiff break; } - ulong offset = stripOffsets.GetValue(stripIndex) switch - { - ulong val => val, - Number val => (uint)val, - _ => throw TiffThrowHelper.ThrowImageFormatException("Expected Number or Long8 array") - }; - - ulong count = stripByteCounts.GetValue(stripIndex) switch - { - ulong val => val, - Number val => (uint)val, - _ => throw TiffThrowHelper.ThrowImageFormatException("Expected Number or Long8 array") - }; - decompressor.Decompress( this.inputStream, - offset, - count, + stripOffsets[stripIndex], + stripByteCounts[stripIndex], stripHeight, stripBufferSpan);