diff --git a/src/ImageSharp/Formats/Tiff/Compression/Decompressors/DeflateTiffCompression.cs b/src/ImageSharp/Formats/Tiff/Compression/Decompressors/DeflateTiffCompression.cs index 3e874b7d2..12aadbea6 100644 --- a/src/ImageSharp/Formats/Tiff/Compression/Decompressors/DeflateTiffCompression.cs +++ b/src/ImageSharp/Formats/Tiff/Compression/Decompressors/DeflateTiffCompression.cs @@ -24,6 +24,8 @@ internal sealed class DeflateTiffCompression : TiffBaseDecompressor private readonly bool isTiled; + private readonly int tileWidth; + /// /// Initializes a new instance of the class. /// @@ -34,12 +36,14 @@ internal sealed class DeflateTiffCompression : TiffBaseDecompressor /// The tiff predictor used. /// if set to true decodes the pixel data as big endian, otherwise as little endian. /// Flag indicates, if the image is a tiled image. - public DeflateTiffCompression(MemoryAllocator memoryAllocator, int width, int bitsPerPixel, TiffColorType colorType, TiffPredictor predictor, bool isBigEndian, bool isTiled) + /// Number of pixels in a tile row. + public DeflateTiffCompression(MemoryAllocator memoryAllocator, int width, int bitsPerPixel, TiffColorType colorType, TiffPredictor predictor, bool isBigEndian, bool isTiled, int tileWidth) : base(memoryAllocator, width, bitsPerPixel, predictor) { this.colorType = colorType; this.isBigEndian = isBigEndian; this.isTiled = isTiled; + this.tileWidth = tileWidth; } /// @@ -73,9 +77,16 @@ internal sealed class DeflateTiffCompression : TiffBaseDecompressor } // When the image is tiled, undoing the horizontal predictor will be done for each tile row in the DecodeTilesChunky() method. - if (this.Predictor == TiffPredictor.Horizontal && !this.isTiled) + if (this.Predictor == TiffPredictor.Horizontal) { - HorizontalPredictor.Undo(buffer, this.Width, this.colorType, this.isBigEndian); + if (this.isTiled) + { + HorizontalPredictor.UndoTile(buffer, this.tileWidth, this.colorType, this.isBigEndian); + } + else + { + HorizontalPredictor.Undo(buffer, this.Width, this.colorType, this.isBigEndian); + } } } diff --git a/src/ImageSharp/Formats/Tiff/Compression/HorizontalPredictor.cs b/src/ImageSharp/Formats/Tiff/Compression/HorizontalPredictor.cs index c7f25f118..e15584f3f 100644 --- a/src/ImageSharp/Formats/Tiff/Compression/HorizontalPredictor.cs +++ b/src/ImageSharp/Formats/Tiff/Compression/HorizontalPredictor.cs @@ -62,6 +62,14 @@ internal static class HorizontalPredictor } } + public static void UndoTile(Span pixelBytes, int tileWidth, TiffColorType colorType, bool isBigEndian) + { + for (int y = 0; y < tileWidth; y++) + { + UndoRow(pixelBytes, tileWidth, y, colorType, isBigEndian); + } + } + /// /// Inverts the horizontal predictor for one row. /// diff --git a/src/ImageSharp/Formats/Tiff/Compression/TiffDecompressorsFactory.cs b/src/ImageSharp/Formats/Tiff/Compression/TiffDecompressorsFactory.cs index c05d14dc6..3274f5729 100644 --- a/src/ImageSharp/Formats/Tiff/Compression/TiffDecompressorsFactory.cs +++ b/src/ImageSharp/Formats/Tiff/Compression/TiffDecompressorsFactory.cs @@ -4,7 +4,6 @@ using SixLabors.ImageSharp.Formats.Tiff.Compression.Decompressors; using SixLabors.ImageSharp.Formats.Tiff.Constants; using SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation; -using SixLabors.ImageSharp.Formats.Webp; using SixLabors.ImageSharp.Memory; namespace SixLabors.ImageSharp.Formats.Tiff.Compression; @@ -25,7 +24,8 @@ internal static class TiffDecompressorsFactory uint oldJpegStartOfImageMarker, TiffFillOrder fillOrder, ByteOrder byteOrder, - bool isTiled = false) + bool isTiled = false, + int tileWidth = 0) { switch (method) { @@ -41,7 +41,7 @@ internal static class TiffDecompressorsFactory case TiffDecoderCompressionType.Deflate: DebugGuard.IsTrue(faxOptions == FaxCompressionOptions.None, "No fax compression options are expected"); - return new DeflateTiffCompression(allocator, width, bitsPerPixel, colorType, predictor, byteOrder == ByteOrder.BigEndian, isTiled); + return new DeflateTiffCompression(allocator, width, bitsPerPixel, colorType, predictor, byteOrder == ByteOrder.BigEndian, isTiled, tileWidth); case TiffDecoderCompressionType.Lzw: DebugGuard.IsTrue(faxOptions == FaxCompressionOptions.None, "No fax compression options are expected"); diff --git a/src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs b/src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs index 20f0dcba6..c642f6734 100644 --- a/src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs +++ b/src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs @@ -679,8 +679,7 @@ internal class TiffDecoderCore : ImageDecoderCore using IMemoryOwner tileBuffer = this.memoryAllocator.Allocate(bytesPerTileRow * tileLength, AllocationOptions.Clean); Span tileBufferSpan = tileBuffer.GetSpan(); - bool isTiled = true; - using TiffBaseDecompressor decompressor = this.CreateDecompressor(frame.Width, bitsPerPixel, isTiled); + using TiffBaseDecompressor decompressor = this.CreateDecompressor(frame.Width, bitsPerPixel, true, tileWidth); TiffBaseColorDecoder colorDecoder = this.CreateChunkyColorDecoder(); int tileIndex = 0; @@ -748,7 +747,7 @@ internal class TiffDecoderCore : ImageDecoderCore this.YcbcrSubSampling, this.byteOrder); - private TiffBaseDecompressor CreateDecompressor(int frameWidth, int bitsPerPixel, bool isTiled = false) + private TiffBaseDecompressor CreateDecompressor(int frameWidth, int bitsPerPixel, bool isTiled = false, int tileWidth = 0) where TPixel : unmanaged, IPixel => TiffDecompressorsFactory.Create( this.Options, @@ -764,7 +763,8 @@ internal class TiffDecoderCore : ImageDecoderCore this.OldJpegCompressionStartOfImageMarker.GetValueOrDefault(), this.FillOrder, this.byteOrder, - isTiled); + isTiled, + tileWidth); private IMemoryOwner ConvertNumbers(Array array, out Span span) { diff --git a/tests/ImageSharp.Tests/Formats/Tiff/Compression/DeflateTiffCompressionTests.cs b/tests/ImageSharp.Tests/Formats/Tiff/Compression/DeflateTiffCompressionTests.cs index b0ca4699e..3db142d6d 100644 --- a/tests/ImageSharp.Tests/Formats/Tiff/Compression/DeflateTiffCompressionTests.cs +++ b/tests/ImageSharp.Tests/Formats/Tiff/Compression/DeflateTiffCompressionTests.cs @@ -23,7 +23,7 @@ public class DeflateTiffCompressionTests using BufferedReadStream stream = CreateCompressedStream(data); byte[] buffer = new byte[data.Length]; - using var decompressor = new DeflateTiffCompression(Configuration.Default.MemoryAllocator, 10, 8, TiffColorType.BlackIsZero8, TiffPredictor.None, false, false); + using var decompressor = new DeflateTiffCompression(Configuration.Default.MemoryAllocator, 10, 8, TiffColorType.BlackIsZero8, TiffPredictor.None, false, false, 0); decompressor.Decompress(stream, 0, (uint)stream.Length, 1, buffer, default);