Browse Source

Merge pull request #2879 from SixLabors/js/v4-chunk-tiff-allocation

V4 : Decode Chunky Tile Rows Directly.
pull/2886/head
James Jackson-South 1 year ago
committed by GitHub
parent
commit
9c9cc0d45c
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 2
      src/ImageSharp/Formats/Png/PngThrowHelper.cs
  2. 31
      src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs

2
src/ImageSharp/Formats/Png/PngThrowHelper.cs

@ -44,7 +44,7 @@ internal static class PngThrowHelper
=> throw new NotSupportedException($"Invalid {name}. {message}. Was '{value}'."); => throw new NotSupportedException($"Invalid {name}. {message}. Was '{value}'.");
[DoesNotReturn] [DoesNotReturn]
public static void ThrowInvalidParameter(object value1, object value2, string message, [CallerArgumentExpression(nameof(value1))] string name1 = "", [CallerArgumentExpression(nameof(value1))] string name2 = "") public static void ThrowInvalidParameter(object value1, object value2, string message, [CallerArgumentExpression(nameof(value1))] string name1 = "", [CallerArgumentExpression(nameof(value2))] string name2 = "")
=> throw new NotSupportedException($"Invalid {name1} or {name2}. {message}. Was '{value1}' and '{value2}'."); => throw new NotSupportedException($"Invalid {name1} or {name2}. {message}. Was '{value1}' and '{value2}'.");
[DoesNotReturn] [DoesNotReturn]

31
src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs

@ -648,7 +648,7 @@ internal class TiffDecoderCore : ImageDecoderCore
} }
/// <summary> /// <summary>
/// Decodes the image data for Tiff's which arrange the pixel data in tiles and the chunky configuration. /// Decodes the image data for TIFFs which arrange the pixel data in tiles and the chunky configuration.
/// </summary> /// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam> /// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="frame">The image frame to decode into.</param> /// <param name="frame">The image frame to decode into.</param>
@ -674,14 +674,10 @@ internal class TiffDecoderCore : ImageDecoderCore
int width = pixels.Width; int width = pixels.Width;
int height = pixels.Height; int height = pixels.Height;
int bitsPerPixel = this.BitsPerPixel; int bitsPerPixel = this.BitsPerPixel;
int bytesPerRow = RoundUpToMultipleOfEight(width * bitsPerPixel);
int bytesPerTileRow = RoundUpToMultipleOfEight(tileWidth * bitsPerPixel); int bytesPerTileRow = RoundUpToMultipleOfEight(tileWidth * bitsPerPixel);
int uncompressedTilesSize = bytesPerTileRow * tileLength;
using IMemoryOwner<byte> tileBuffer = this.memoryAllocator.Allocate<byte>(uncompressedTilesSize, AllocationOptions.Clean); using IMemoryOwner<byte> tileBuffer = this.memoryAllocator.Allocate<byte>(bytesPerTileRow * tileLength, AllocationOptions.Clean);
using IMemoryOwner<byte> uncompressedPixelBuffer = this.memoryAllocator.Allocate<byte>(tilesDown * tileLength * bytesPerRow, AllocationOptions.Clean);
Span<byte> tileBufferSpan = tileBuffer.GetSpan(); Span<byte> tileBufferSpan = tileBuffer.GetSpan();
Span<byte> uncompressedPixelBufferSpan = uncompressedPixelBuffer.GetSpan();
using TiffBaseDecompressor decompressor = this.CreateDecompressor<TPixel>(frame.Width, bitsPerPixel); using TiffBaseDecompressor decompressor = this.CreateDecompressor<TPixel>(frame.Width, bitsPerPixel);
TiffBaseColorDecoder<TPixel> colorDecoder = this.CreateChunkyColorDecoder<TPixel>(); TiffBaseColorDecoder<TPixel> colorDecoder = this.CreateChunkyColorDecoder<TPixel>();
@ -689,13 +685,15 @@ internal class TiffDecoderCore : ImageDecoderCore
int tileIndex = 0; int tileIndex = 0;
for (int tileY = 0; tileY < tilesDown; tileY++) for (int tileY = 0; tileY < tilesDown; tileY++)
{ {
int remainingPixelsInRow = width; int rowStartY = tileY * tileLength;
int rowEndY = Math.Min(rowStartY + tileLength, height);
for (int tileX = 0; tileX < tilesAcross; tileX++) for (int tileX = 0; tileX < tilesAcross; tileX++)
{ {
cancellationToken.ThrowIfCancellationRequested(); cancellationToken.ThrowIfCancellationRequested();
int uncompressedPixelBufferOffset = tileY * tileLength * bytesPerRow;
bool isLastHorizontalTile = tileX == tilesAcross - 1; bool isLastHorizontalTile = tileX == tilesAcross - 1;
int remainingPixelsInRow = width - (tileX * tileWidth);
decompressor.Decompress( decompressor.Decompress(
this.inputStream, this.inputStream,
@ -706,22 +704,21 @@ internal class TiffDecoderCore : ImageDecoderCore
cancellationToken); cancellationToken);
int tileBufferOffset = 0; int tileBufferOffset = 0;
uncompressedPixelBufferOffset += bytesPerTileRow * tileX;
int bytesToCopy = isLastHorizontalTile ? RoundUpToMultipleOfEight(bitsPerPixel * remainingPixelsInRow) : bytesPerTileRow; int bytesToCopy = isLastHorizontalTile ? RoundUpToMultipleOfEight(bitsPerPixel * remainingPixelsInRow) : bytesPerTileRow;
for (int y = 0; y < tileLength; y++) int rowWidth = Math.Min(tileWidth, remainingPixelsInRow);
int left = tileX * tileWidth;
for (int y = rowStartY; y < rowEndY; y++)
{ {
Span<byte> uncompressedPixelRow = uncompressedPixelBufferSpan.Slice(uncompressedPixelBufferOffset, bytesToCopy); // Decode the tile row directly into the pixel buffer.
tileBufferSpan.Slice(tileBufferOffset, bytesToCopy).CopyTo(uncompressedPixelRow); ReadOnlySpan<byte> tileRowSpan = tileBufferSpan.Slice(tileBufferOffset, bytesToCopy);
colorDecoder.Decode(tileRowSpan, pixels, left, y, rowWidth, 1);
tileBufferOffset += bytesPerTileRow; tileBufferOffset += bytesPerTileRow;
uncompressedPixelBufferOffset += bytesPerRow;
} }
remainingPixelsInRow -= tileWidth;
tileIndex++; tileIndex++;
} }
} }
colorDecoder.Decode(uncompressedPixelBufferSpan, pixels, 0, 0, width, height);
} }
private TiffBaseColorDecoder<TPixel> CreateChunkyColorDecoder<TPixel>() private TiffBaseColorDecoder<TPixel> CreateChunkyColorDecoder<TPixel>()

Loading…
Cancel
Save