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