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()