diff --git a/src/ImageSharp/Formats/Tiff/Compression/Decompressors/DeflateTiffCompression.cs b/src/ImageSharp/Formats/Tiff/Compression/Decompressors/DeflateTiffCompression.cs
index 12aadbea6..3fcbd292d 100644
--- a/src/ImageSharp/Formats/Tiff/Compression/Decompressors/DeflateTiffCompression.cs
+++ b/src/ImageSharp/Formats/Tiff/Compression/Decompressors/DeflateTiffCompression.cs
@@ -76,11 +76,11 @@ 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)
{
if (this.isTiled)
{
+ // When the image is tiled, undoing the horizontal predictor will be done for each tile row.
HorizontalPredictor.UndoTile(buffer, this.tileWidth, this.colorType, this.isBigEndian);
}
else
diff --git a/src/ImageSharp/Formats/Tiff/Compression/Decompressors/LzwTiffCompression.cs b/src/ImageSharp/Formats/Tiff/Compression/Decompressors/LzwTiffCompression.cs
index 01591e138..5995cbc8f 100644
--- a/src/ImageSharp/Formats/Tiff/Compression/Decompressors/LzwTiffCompression.cs
+++ b/src/ImageSharp/Formats/Tiff/Compression/Decompressors/LzwTiffCompression.cs
@@ -17,6 +17,10 @@ internal sealed class LzwTiffCompression : TiffBaseDecompressor
private readonly TiffColorType colorType;
+ private readonly bool isTiled;
+
+ private readonly int tileWidth;
+
///
/// Initializes a new instance of the class.
///
@@ -26,11 +30,15 @@ internal sealed class LzwTiffCompression : TiffBaseDecompressor
/// The color type of the pixel data.
/// The tiff predictor used.
/// if set to true decodes the pixel data as big endian, otherwise as little endian.
- public LzwTiffCompression(MemoryAllocator memoryAllocator, int width, int bitsPerPixel, TiffColorType colorType, TiffPredictor predictor, bool isBigEndian)
+ /// Flag indicates, if the image is a tiled image.
+ /// Number of pixels in a tile row.
+ public LzwTiffCompression(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;
}
///
@@ -41,7 +49,15 @@ internal sealed class LzwTiffCompression : TiffBaseDecompressor
if (this.Predictor == TiffPredictor.Horizontal)
{
- HorizontalPredictor.Undo(buffer, this.Width, this.colorType, this.isBigEndian);
+ if (this.isTiled)
+ {
+ // When the image is tiled, undoing the horizontal predictor will be done for each tile row.
+ 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 e15584f3f..6bd0230a1 100644
--- a/src/ImageSharp/Formats/Tiff/Compression/HorizontalPredictor.cs
+++ b/src/ImageSharp/Formats/Tiff/Compression/HorizontalPredictor.cs
@@ -62,6 +62,13 @@ internal static class HorizontalPredictor
}
}
+ ///
+ /// Inverts the horizontal predictor for each tile row.
+ ///
+ /// Buffer with decompressed pixel data for a tile.
+ /// Tile with in pixels.
+ /// The color type of the pixel data.
+ /// If set to true decodes the pixel data as big endian, otherwise as little endian.
public static void UndoTile(Span pixelBytes, int tileWidth, TiffColorType colorType, bool isBigEndian)
{
for (int y = 0; y < tileWidth; y++)
diff --git a/src/ImageSharp/Formats/Tiff/Compression/TiffDecompressorsFactory.cs b/src/ImageSharp/Formats/Tiff/Compression/TiffDecompressorsFactory.cs
index 3274f5729..eec1efcb2 100644
--- a/src/ImageSharp/Formats/Tiff/Compression/TiffDecompressorsFactory.cs
+++ b/src/ImageSharp/Formats/Tiff/Compression/TiffDecompressorsFactory.cs
@@ -45,7 +45,7 @@ internal static class TiffDecompressorsFactory
case TiffDecoderCompressionType.Lzw:
DebugGuard.IsTrue(faxOptions == FaxCompressionOptions.None, "No fax compression options are expected");
- return new LzwTiffCompression(allocator, width, bitsPerPixel, colorType, predictor, byteOrder == ByteOrder.BigEndian);
+ return new LzwTiffCompression(allocator, width, bitsPerPixel, colorType, predictor, byteOrder == ByteOrder.BigEndian, isTiled, tileWidth);
case TiffDecoderCompressionType.T4:
DebugGuard.IsTrue(predictor == TiffPredictor.None, "Predictor should only be used with lzw or deflate compression");
diff --git a/tests/ImageSharp.Tests/Formats/Tiff/Compression/LzwTiffCompressionTests.cs b/tests/ImageSharp.Tests/Formats/Tiff/Compression/LzwTiffCompressionTests.cs
index 635a3a33e..86da73186 100644
--- a/tests/ImageSharp.Tests/Formats/Tiff/Compression/LzwTiffCompressionTests.cs
+++ b/tests/ImageSharp.Tests/Formats/Tiff/Compression/LzwTiffCompressionTests.cs
@@ -37,7 +37,7 @@ public class LzwTiffCompressionTests
using BufferedReadStream stream = CreateCompressedStream(data);
byte[] buffer = new byte[data.Length];
- using var decompressor = new LzwTiffCompression(Configuration.Default.MemoryAllocator, 10, 8, TiffColorType.BlackIsZero8, TiffPredictor.None, false);
+ using var decompressor = new LzwTiffCompression(Configuration.Default.MemoryAllocator, 10, 8, TiffColorType.BlackIsZero8, TiffPredictor.None, false, false, 0);
decompressor.Decompress(stream, 0, (uint)stream.Length, 1, buffer, default);
Assert.Equal(data, buffer);
diff --git a/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs
index 16d3ade0e..819547c51 100644
--- a/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs
+++ b/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs
@@ -107,6 +107,23 @@ public class TiffDecoderTests : TiffDecoderBaseTester
public void TiffDecoder_CanDecode_Tiled_Deflate_Compressed(TestImageProvider provider)
where TPixel : unmanaged, IPixel => TestTiffDecoder(provider);
+ [Theory]
+ [WithFile(TiledRgbaLzwCompressedWithPredictor, PixelTypes.Rgba32)]
+ [WithFile(TiledRgbLzwCompressedWithPredictor, PixelTypes.Rgba32)]
+ [WithFile(TiledGrayLzwCompressedWithPredictor, PixelTypes.Rgba32)]
+ [WithFile(TiledGray16BitLittleEndianLzwCompressedWithPredictor, PixelTypes.Rgba32)]
+ [WithFile(TiledGray16BitBigEndianLzwCompressedWithPredictor, PixelTypes.Rgba32)]
+ [WithFile(TiledGray32BitLittleEndianLzwCompressedWithPredictor, PixelTypes.Rgba32)]
+ [WithFile(TiledGray32BitBigEndianLzwCompressedWithPredictor, PixelTypes.Rgba32)]
+ [WithFile(TiledRgb48BitLittleEndianLzwCompressedWithPredictor, PixelTypes.Rgba32)]
+ [WithFile(TiledRgb48BitBigEndianLzwCompressedWithPredictor, PixelTypes.Rgba32)]
+ [WithFile(TiledRgba64BitLittleEndianLzwCompressedWithPredictor, PixelTypes.Rgba32)]
+ [WithFile(TiledRgba64BitBigEndianLzwCompressedWithPredictor, PixelTypes.Rgba32)]
+ [WithFile(TiledRgb96BitLittleEndianLzwCompressedWithPredictor, PixelTypes.Rgba32)]
+ [WithFile(TiledRgb96BitBigEndianDeflateCompressedWithPredictor, PixelTypes.Rgba32)]
+ public void TiffDecoder_CanDecode_Tiled_Lzw_Compressed(TestImageProvider provider)
+ where TPixel : unmanaged, IPixel => TestTiffDecoder(provider);
+
[Theory]
[WithFile(Rgba8BitPlanarUnassociatedAlpha, PixelTypes.Rgba32)]
public void TiffDecoder_CanDecode_Planar_32Bit(TestImageProvider provider)
diff --git a/tests/ImageSharp.Tests/TestImages.cs b/tests/ImageSharp.Tests/TestImages.cs
index 000cf4d2e..6982a2822 100644
--- a/tests/ImageSharp.Tests/TestImages.cs
+++ b/tests/ImageSharp.Tests/TestImages.cs
@@ -1003,6 +1003,21 @@ public static class TestImages
public const string TiledRgb96BitBigEndianDeflateCompressedWithPredictor = "Tiff/tiled_rgb_96bit_big_endian_deflate_compressed_predictor.tiff";
public const string TiledRgba128BitLittleEndianDeflateCompressedWithPredictor = "Tiff/tiled_rgba_128bit_little_endian_deflate_compressed_predictor.tiff";
public const string TiledRgba128BitBigEndianDeflateCompressedWithPredictor = "Tiff/tiled_rgba_128bit_big_endian_deflate_compressed_predictor.tiff";
+ public const string TiledRgbaLzwCompressedWithPredictor = "Tiff/tiled_rgba_lzw_compressed_predictor.tiff";
+ public const string TiledRgbLzwCompressedWithPredictor = "Tiff/tiled_rgb_lzw_compressed_predictor.tiff";
+ public const string TiledGrayLzwCompressedWithPredictor = "Tiff/tiled_gray_lzw_compressed_predictor.tiff";
+ public const string TiledGray16BitLittleEndianLzwCompressedWithPredictor = "Tiff/tiled_gray_16bit_little_endian_lzw_compressed_predictor.tiff";
+ public const string TiledGray16BitBigEndianLzwCompressedWithPredictor = "Tiff/tiled_gray_16bit_big_endian_lzw_compressed_predictor.tiff";
+ public const string TiledGray32BitLittleEndianLzwCompressedWithPredictor = "Tiff/tiled_gray_32bit_little_endian_lzw_compressed_predictor.tiff";
+ public const string TiledGray32BitBigEndianLzwCompressedWithPredictor = "Tiff/tiled_gray_32bit_big_endian_lzw_compressed_predictor.tiff";
+ public const string TiledRgb48BitLittleEndianLzwCompressedWithPredictor = "Tiff/tiled_rgb_48bit_little_endian_lzw_compressed_predictor.tiff";
+ public const string TiledRgb48BitBigEndianLzwCompressedWithPredictor = "Tiff/tiled_rgb_48bit_big_endian_lzw_compressed_predictor.tiff";
+ public const string TiledRgba64BitLittleEndianLzwCompressedWithPredictor = "Tiff/tiled_rgba_64bit_little_endian_lzw_compressed_predictor.tiff";
+ public const string TiledRgba64BitBigEndianLzwCompressedWithPredictor = "Tiff/tiled_rgba_64bit_big_endian_lzw_compressed_predictor.tiff";
+ public const string TiledRgb96BitLittleEndianLzwCompressedWithPredictor = "Tiff/tiled_rgb_96bit_little_endian_lzw_compressed_predictor.tiff";
+ public const string TiledRgb96BitBigEndianLzwCompressedWithPredictor = "Tiff/tiled_rgb_96bit_big_endian_lzw_compressed_predictor.tiff";
+ public const string TiledRgba128BitLittleEndianLzwCompressedWithPredictor = "Tiff/tiled_rgba_128bit_little_endian_lzw_compressed_predictor.tiff";
+ public const string TiledRgba128BitBigEndianLzwCompressedWithPredictor = "Tiff/tiled_rgba_128bit_big_endian_lzw_compressed_predictor.tiff";
// Images with alpha channel.
public const string Rgba2BitUnassociatedAlpha = "Tiff/RgbaUnassociatedAlpha2bit.tiff";
diff --git a/tests/Images/Input/Tiff/tiled_gray_16bit_big_endian_lzw_compressed_predictor.tiff b/tests/Images/Input/Tiff/tiled_gray_16bit_big_endian_lzw_compressed_predictor.tiff
new file mode 100644
index 000000000..6600ab8c2
--- /dev/null
+++ b/tests/Images/Input/Tiff/tiled_gray_16bit_big_endian_lzw_compressed_predictor.tiff
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:d1cf5098ff98ded0a55cfa73f823cef9c324a66e38ce4a82bae2d3ef4c058c3e
+size 78817
diff --git a/tests/Images/Input/Tiff/tiled_gray_16bit_little_endian_lzw_compressed_predictor.tiff b/tests/Images/Input/Tiff/tiled_gray_16bit_little_endian_lzw_compressed_predictor.tiff
new file mode 100644
index 000000000..d4508e32a
--- /dev/null
+++ b/tests/Images/Input/Tiff/tiled_gray_16bit_little_endian_lzw_compressed_predictor.tiff
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:879bacee73f5fea767439071aa6057d66d2d61bc554b109abb7b79765873730b
+size 78795
diff --git a/tests/Images/Input/Tiff/tiled_gray_32bit_big_endian_lzw_compressed_predictor.tiff b/tests/Images/Input/Tiff/tiled_gray_32bit_big_endian_lzw_compressed_predictor.tiff
new file mode 100644
index 000000000..adf2c55e0
--- /dev/null
+++ b/tests/Images/Input/Tiff/tiled_gray_32bit_big_endian_lzw_compressed_predictor.tiff
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:41140a44fde93ea15514b153f1fd4d15f8e69fc8ca0c88336f01c700c4d06f93
+size 104333
diff --git a/tests/Images/Input/Tiff/tiled_gray_32bit_little_endian_lzw_compressed_predictor.tiff b/tests/Images/Input/Tiff/tiled_gray_32bit_little_endian_lzw_compressed_predictor.tiff
new file mode 100644
index 000000000..2f7abc69a
--- /dev/null
+++ b/tests/Images/Input/Tiff/tiled_gray_32bit_little_endian_lzw_compressed_predictor.tiff
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:b7c32da6db17088b0c3e2c21ffbdd7c43fc4944b03c2cdb9b863c296656b898d
+size 103239
diff --git a/tests/Images/Input/Tiff/tiled_gray_lzw_compressed_predictor.tiff b/tests/Images/Input/Tiff/tiled_gray_lzw_compressed_predictor.tiff
new file mode 100644
index 000000000..b226121cc
--- /dev/null
+++ b/tests/Images/Input/Tiff/tiled_gray_lzw_compressed_predictor.tiff
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:63deeb0eecf0ce51000a5bba275d5a7e40fb833a962b50e6b85c4493a3719911
+size 61555
diff --git a/tests/Images/Input/Tiff/tiled_rgb_48bit_big_endian_lzw_compressed_predictor.tiff b/tests/Images/Input/Tiff/tiled_rgb_48bit_big_endian_lzw_compressed_predictor.tiff
new file mode 100644
index 000000000..843268cad
--- /dev/null
+++ b/tests/Images/Input/Tiff/tiled_rgb_48bit_big_endian_lzw_compressed_predictor.tiff
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:45f06403f1dc24991450331c3388ba8c4f5fd004f48787c541fad0b1c104b964
+size 212595
diff --git a/tests/Images/Input/Tiff/tiled_rgb_48bit_little_endian_lzw_compressed_predictor.tiff b/tests/Images/Input/Tiff/tiled_rgb_48bit_little_endian_lzw_compressed_predictor.tiff
new file mode 100644
index 000000000..e3457633e
--- /dev/null
+++ b/tests/Images/Input/Tiff/tiled_rgb_48bit_little_endian_lzw_compressed_predictor.tiff
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:4fdb91eda4e04df41df9dfb98702349308b0f104ca49051726db084c595d912b
+size 212463
diff --git a/tests/Images/Input/Tiff/tiled_rgb_64bit_big_endian_lzw_compressed_predictor.tiff b/tests/Images/Input/Tiff/tiled_rgb_64bit_big_endian_lzw_compressed_predictor.tiff
new file mode 100644
index 000000000..9c442bf34
--- /dev/null
+++ b/tests/Images/Input/Tiff/tiled_rgb_64bit_big_endian_lzw_compressed_predictor.tiff
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:a0ddd2ec8f73c784b060ff790e70f586bba70905b75f3cf8ae18f2b054e1eb06
+size 244677
diff --git a/tests/Images/Input/Tiff/tiled_rgb_64bit_little_endian_lzw_compressed_predictor.tiff b/tests/Images/Input/Tiff/tiled_rgb_64bit_little_endian_lzw_compressed_predictor.tiff
new file mode 100644
index 000000000..456f57cbd
--- /dev/null
+++ b/tests/Images/Input/Tiff/tiled_rgb_64bit_little_endian_lzw_compressed_predictor.tiff
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:d8e05d9ca953045d732c4304575588d2db2ead50177b2ed9416922568760ee1f
+size 244625
diff --git a/tests/Images/Input/Tiff/tiled_rgb_96bit_big_endian_lzw_compressed_predictor.tiff b/tests/Images/Input/Tiff/tiled_rgb_96bit_big_endian_lzw_compressed_predictor.tiff
new file mode 100644
index 000000000..90a73d706
--- /dev/null
+++ b/tests/Images/Input/Tiff/tiled_rgb_96bit_big_endian_lzw_compressed_predictor.tiff
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:f99d456c3fbf25ca307026a355230d7e68ac89c73d5739cceca1a2a600214483
+size 282887
diff --git a/tests/Images/Input/Tiff/tiled_rgb_96bit_little_endian_lzw_compressed_predictor.tiff b/tests/Images/Input/Tiff/tiled_rgb_96bit_little_endian_lzw_compressed_predictor.tiff
new file mode 100644
index 000000000..3eba8648a
--- /dev/null
+++ b/tests/Images/Input/Tiff/tiled_rgb_96bit_little_endian_lzw_compressed_predictor.tiff
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:3bdbf90168ec824eab9f66ebd12d5dd09971363719a7b382111f50344751bbfa
+size 281055
diff --git a/tests/Images/Input/Tiff/tiled_rgb_lzw_compressed_predictor.tiff b/tests/Images/Input/Tiff/tiled_rgb_lzw_compressed_predictor.tiff
new file mode 100644
index 000000000..144fdc0a0
--- /dev/null
+++ b/tests/Images/Input/Tiff/tiled_rgb_lzw_compressed_predictor.tiff
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:12382128d89ddddf8b7ec0cf70bdfcac26c9b093bb1a2b77f61ddf75a824bfd7
+size 163249
diff --git a/tests/Images/Input/Tiff/tiled_rgba_128bit_big_endian_lzw_compressed_predictor.tiff b/tests/Images/Input/Tiff/tiled_rgba_128bit_big_endian_lzw_compressed_predictor.tiff
new file mode 100644
index 000000000..6aee230d8
--- /dev/null
+++ b/tests/Images/Input/Tiff/tiled_rgba_128bit_big_endian_lzw_compressed_predictor.tiff
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:81819483cbde5fddbbbf274da327a85a38db7d9946187cb5fa8c00cb03e2828d
+size 336229
diff --git a/tests/Images/Input/Tiff/tiled_rgba_128bit_little_endian_lzw_compressed_predictor.tiff b/tests/Images/Input/Tiff/tiled_rgba_128bit_little_endian_lzw_compressed_predictor.tiff
new file mode 100644
index 000000000..2a35d0f1c
--- /dev/null
+++ b/tests/Images/Input/Tiff/tiled_rgba_128bit_little_endian_lzw_compressed_predictor.tiff
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:ed8cd226de68190ea5740d59ec0ef95095a6802ffb40539e9e2db0d9cd0ab276
+size 334413
diff --git a/tests/Images/Input/Tiff/tiled_rgba_lzw_compressed_predictor.tiff b/tests/Images/Input/Tiff/tiled_rgba_lzw_compressed_predictor.tiff
new file mode 100644
index 000000000..efc09ced5
--- /dev/null
+++ b/tests/Images/Input/Tiff/tiled_rgba_lzw_compressed_predictor.tiff
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:3b9a1da29756a4bbac7ea7266067748f8468619191e9a7635e84e5eac8acc3b8
+size 183629