diff --git a/src/ImageSharp/Formats/Png/PngThrowHelper.cs b/src/ImageSharp/Formats/Png/PngThrowHelper.cs
index 0552e9a79e..8dc70e1d9a 100644
--- a/src/ImageSharp/Formats/Png/PngThrowHelper.cs
+++ b/src/ImageSharp/Formats/Png/PngThrowHelper.cs
@@ -44,7 +44,7 @@ internal static class PngThrowHelper
=> throw new NotSupportedException($"Invalid {name}. {message}. Was '{value}'.");
[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}'.");
[DoesNotReturn]
diff --git a/src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs b/src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs
index d699a7b631..7336924602 100644
--- a/src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs
+++ b/src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs
@@ -648,7 +648,7 @@ internal class TiffDecoderCore : ImageDecoderCore
}
///
- /// 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.
///
/// The pixel format.
/// The image frame to decode into.
@@ -674,14 +674,10 @@ internal class TiffDecoderCore : ImageDecoderCore
int width = pixels.Width;
int height = pixels.Height;
int bitsPerPixel = this.BitsPerPixel;
-
- int bytesPerRow = RoundUpToMultipleOfEight(width * bitsPerPixel);
int bytesPerTileRow = RoundUpToMultipleOfEight(tileWidth * bitsPerPixel);
- int uncompressedTilesSize = bytesPerTileRow * tileLength;
- using IMemoryOwner tileBuffer = this.memoryAllocator.Allocate(uncompressedTilesSize, AllocationOptions.Clean);
- using IMemoryOwner uncompressedPixelBuffer = this.memoryAllocator.Allocate(tilesDown * tileLength * bytesPerRow, AllocationOptions.Clean);
+
+ using IMemoryOwner tileBuffer = this.memoryAllocator.Allocate(bytesPerTileRow * tileLength, AllocationOptions.Clean);
Span tileBufferSpan = tileBuffer.GetSpan();
- Span uncompressedPixelBufferSpan = uncompressedPixelBuffer.GetSpan();
using TiffBaseDecompressor decompressor = this.CreateDecompressor(frame.Width, bitsPerPixel);
TiffBaseColorDecoder colorDecoder = this.CreateChunkyColorDecoder();
@@ -689,13 +685,15 @@ internal class TiffDecoderCore : ImageDecoderCore
int tileIndex = 0;
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++)
{
cancellationToken.ThrowIfCancellationRequested();
- int uncompressedPixelBufferOffset = tileY * tileLength * bytesPerRow;
bool isLastHorizontalTile = tileX == tilesAcross - 1;
+ int remainingPixelsInRow = width - (tileX * tileWidth);
decompressor.Decompress(
this.inputStream,
@@ -706,22 +704,21 @@ internal class TiffDecoderCore : ImageDecoderCore
cancellationToken);
int tileBufferOffset = 0;
- uncompressedPixelBufferOffset += bytesPerTileRow * tileX;
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 uncompressedPixelRow = uncompressedPixelBufferSpan.Slice(uncompressedPixelBufferOffset, bytesToCopy);
- tileBufferSpan.Slice(tileBufferOffset, bytesToCopy).CopyTo(uncompressedPixelRow);
+ // Decode the tile row directly into the pixel buffer.
+ ReadOnlySpan tileRowSpan = tileBufferSpan.Slice(tileBufferOffset, bytesToCopy);
+ colorDecoder.Decode(tileRowSpan, pixels, left, y, rowWidth, 1);
tileBufferOffset += bytesPerTileRow;
- uncompressedPixelBufferOffset += bytesPerRow;
}
- remainingPixelsInRow -= tileWidth;
tileIndex++;
}
}
-
- colorDecoder.Decode(uncompressedPixelBufferSpan, pixels, 0, 0, width, height);
}
private TiffBaseColorDecoder CreateChunkyColorDecoder()