Skip to content

Commit 7a5be72

Browse files
committed
Add test cases for tiled lzw compressed images
1 parent 0a52ee7 commit 7a5be72

22 files changed

+105
-5
lines changed

src/ImageSharp/Formats/Tiff/Compression/Decompressors/DeflateTiffCompression.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,11 +76,11 @@ protected override void Decompress(BufferedReadStream stream, int byteCount, int
7676
}
7777
}
7878

79-
// When the image is tiled, undoing the horizontal predictor will be done for each tile row in the DecodeTilesChunky() method.
8079
if (this.Predictor == TiffPredictor.Horizontal)
8180
{
8281
if (this.isTiled)
8382
{
83+
// When the image is tiled, undoing the horizontal predictor will be done for each tile row.
8484
HorizontalPredictor.UndoTile(buffer, this.tileWidth, this.colorType, this.isBigEndian);
8585
}
8686
else

src/ImageSharp/Formats/Tiff/Compression/Decompressors/LzwTiffCompression.cs

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,10 @@ internal sealed class LzwTiffCompression : TiffBaseDecompressor
1717

1818
private readonly TiffColorType colorType;
1919

20+
private readonly bool isTiled;
21+
22+
private readonly int tileWidth;
23+
2024
/// <summary>
2125
/// Initializes a new instance of the <see cref="LzwTiffCompression" /> class.
2226
/// </summary>
@@ -26,11 +30,15 @@ internal sealed class LzwTiffCompression : TiffBaseDecompressor
2630
/// <param name="colorType">The color type of the pixel data.</param>
2731
/// <param name="predictor">The tiff predictor used.</param>
2832
/// <param name="isBigEndian">if set to <c>true</c> decodes the pixel data as big endian, otherwise as little endian.</param>
29-
public LzwTiffCompression(MemoryAllocator memoryAllocator, int width, int bitsPerPixel, TiffColorType colorType, TiffPredictor predictor, bool isBigEndian)
33+
/// <param name="isTiled">Flag indicates, if the image is a tiled image.</param>
34+
/// <param name="tileWidth">Number of pixels in a tile row.</param>
35+
public LzwTiffCompression(MemoryAllocator memoryAllocator, int width, int bitsPerPixel, TiffColorType colorType, TiffPredictor predictor, bool isBigEndian, bool isTiled, int tileWidth)
3036
: base(memoryAllocator, width, bitsPerPixel, predictor)
3137
{
3238
this.colorType = colorType;
3339
this.isBigEndian = isBigEndian;
40+
this.isTiled = isTiled;
41+
this.tileWidth = tileWidth;
3442
}
3543

3644
/// <inheritdoc/>
@@ -41,7 +49,15 @@ protected override void Decompress(BufferedReadStream stream, int byteCount, int
4149

4250
if (this.Predictor == TiffPredictor.Horizontal)
4351
{
44-
HorizontalPredictor.Undo(buffer, this.Width, this.colorType, this.isBigEndian);
52+
if (this.isTiled)
53+
{
54+
// When the image is tiled, undoing the horizontal predictor will be done for each tile row.
55+
HorizontalPredictor.UndoTile(buffer, this.tileWidth, this.colorType, this.isBigEndian);
56+
}
57+
else
58+
{
59+
HorizontalPredictor.Undo(buffer, this.Width, this.colorType, this.isBigEndian);
60+
}
4561
}
4662
}
4763

src/ImageSharp/Formats/Tiff/Compression/HorizontalPredictor.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,13 @@ public static void Undo(Span<byte> pixelBytes, int width, TiffColorType colorTyp
6262
}
6363
}
6464

65+
/// <summary>
66+
/// Inverts the horizontal predictor for each tile row.
67+
/// </summary>
68+
/// <param name="pixelBytes">Buffer with decompressed pixel data for a tile.</param>
69+
/// <param name="tileWidth">Tile with in pixels.</param>
70+
/// <param name="colorType">The color type of the pixel data.</param>
71+
/// <param name="isBigEndian">If set to <c>true</c> decodes the pixel data as big endian, otherwise as little endian.</param>
6572
public static void UndoTile(Span<byte> pixelBytes, int tileWidth, TiffColorType colorType, bool isBigEndian)
6673
{
6774
for (int y = 0; y < tileWidth; y++)

src/ImageSharp/Formats/Tiff/Compression/TiffDecompressorsFactory.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ public static TiffBaseDecompressor Create(
4545

4646
case TiffDecoderCompressionType.Lzw:
4747
DebugGuard.IsTrue(faxOptions == FaxCompressionOptions.None, "No fax compression options are expected");
48-
return new LzwTiffCompression(allocator, width, bitsPerPixel, colorType, predictor, byteOrder == ByteOrder.BigEndian);
48+
return new LzwTiffCompression(allocator, width, bitsPerPixel, colorType, predictor, byteOrder == ByteOrder.BigEndian, isTiled, tileWidth);
4949

5050
case TiffDecoderCompressionType.T4:
5151
DebugGuard.IsTrue(predictor == TiffPredictor.None, "Predictor should only be used with lzw or deflate compression");

tests/ImageSharp.Tests/Formats/Tiff/Compression/LzwTiffCompressionTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ public void Compress_Decompress_Roundtrip_Works(byte[] data)
3737
using BufferedReadStream stream = CreateCompressedStream(data);
3838
byte[] buffer = new byte[data.Length];
3939

40-
using var decompressor = new LzwTiffCompression(Configuration.Default.MemoryAllocator, 10, 8, TiffColorType.BlackIsZero8, TiffPredictor.None, false);
40+
using var decompressor = new LzwTiffCompression(Configuration.Default.MemoryAllocator, 10, 8, TiffColorType.BlackIsZero8, TiffPredictor.None, false, false, 0);
4141
decompressor.Decompress(stream, 0, (uint)stream.Length, 1, buffer, default);
4242

4343
Assert.Equal(data, buffer);

tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,23 @@ public void TiffDecoder_CanDecode_Tiled<TPixel>(TestImageProvider<TPixel> provid
107107
public void TiffDecoder_CanDecode_Tiled_Deflate_Compressed<TPixel>(TestImageProvider<TPixel> provider)
108108
where TPixel : unmanaged, IPixel<TPixel> => TestTiffDecoder(provider);
109109

110+
[Theory]
111+
[WithFile(TiledRgbaLzwCompressedWithPredictor, PixelTypes.Rgba32)]
112+
[WithFile(TiledRgbLzwCompressedWithPredictor, PixelTypes.Rgba32)]
113+
[WithFile(TiledGrayLzwCompressedWithPredictor, PixelTypes.Rgba32)]
114+
[WithFile(TiledGray16BitLittleEndianLzwCompressedWithPredictor, PixelTypes.Rgba32)]
115+
[WithFile(TiledGray16BitBigEndianLzwCompressedWithPredictor, PixelTypes.Rgba32)]
116+
[WithFile(TiledGray32BitLittleEndianLzwCompressedWithPredictor, PixelTypes.Rgba32)]
117+
[WithFile(TiledGray32BitBigEndianLzwCompressedWithPredictor, PixelTypes.Rgba32)]
118+
[WithFile(TiledRgb48BitLittleEndianLzwCompressedWithPredictor, PixelTypes.Rgba32)]
119+
[WithFile(TiledRgb48BitBigEndianLzwCompressedWithPredictor, PixelTypes.Rgba32)]
120+
[WithFile(TiledRgba64BitLittleEndianLzwCompressedWithPredictor, PixelTypes.Rgba32)]
121+
[WithFile(TiledRgba64BitBigEndianLzwCompressedWithPredictor, PixelTypes.Rgba32)]
122+
[WithFile(TiledRgb96BitLittleEndianLzwCompressedWithPredictor, PixelTypes.Rgba32)]
123+
[WithFile(TiledRgb96BitBigEndianDeflateCompressedWithPredictor, PixelTypes.Rgba32)]
124+
public void TiffDecoder_CanDecode_Tiled_Lzw_Compressed<TPixel>(TestImageProvider<TPixel> provider)
125+
where TPixel : unmanaged, IPixel<TPixel> => TestTiffDecoder(provider);
126+
110127
[Theory]
111128
[WithFile(Rgba8BitPlanarUnassociatedAlpha, PixelTypes.Rgba32)]
112129
public void TiffDecoder_CanDecode_Planar_32Bit<TPixel>(TestImageProvider<TPixel> provider)

tests/ImageSharp.Tests/TestImages.cs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1003,6 +1003,21 @@ public static class Tiff
10031003
public const string TiledRgb96BitBigEndianDeflateCompressedWithPredictor = "Tiff/tiled_rgb_96bit_big_endian_deflate_compressed_predictor.tiff";
10041004
public const string TiledRgba128BitLittleEndianDeflateCompressedWithPredictor = "Tiff/tiled_rgba_128bit_little_endian_deflate_compressed_predictor.tiff";
10051005
public const string TiledRgba128BitBigEndianDeflateCompressedWithPredictor = "Tiff/tiled_rgba_128bit_big_endian_deflate_compressed_predictor.tiff";
1006+
public const string TiledRgbaLzwCompressedWithPredictor = "Tiff/tiled_rgba_lzw_compressed_predictor.tiff";
1007+
public const string TiledRgbLzwCompressedWithPredictor = "Tiff/tiled_rgb_lzw_compressed_predictor.tiff";
1008+
public const string TiledGrayLzwCompressedWithPredictor = "Tiff/tiled_gray_lzw_compressed_predictor.tiff";
1009+
public const string TiledGray16BitLittleEndianLzwCompressedWithPredictor = "Tiff/tiled_gray_16bit_little_endian_lzw_compressed_predictor.tiff";
1010+
public const string TiledGray16BitBigEndianLzwCompressedWithPredictor = "Tiff/tiled_gray_16bit_big_endian_lzw_compressed_predictor.tiff";
1011+
public const string TiledGray32BitLittleEndianLzwCompressedWithPredictor = "Tiff/tiled_gray_32bit_little_endian_lzw_compressed_predictor.tiff";
1012+
public const string TiledGray32BitBigEndianLzwCompressedWithPredictor = "Tiff/tiled_gray_32bit_big_endian_lzw_compressed_predictor.tiff";
1013+
public const string TiledRgb48BitLittleEndianLzwCompressedWithPredictor = "Tiff/tiled_rgb_48bit_little_endian_lzw_compressed_predictor.tiff";
1014+
public const string TiledRgb48BitBigEndianLzwCompressedWithPredictor = "Tiff/tiled_rgb_48bit_big_endian_lzw_compressed_predictor.tiff";
1015+
public const string TiledRgba64BitLittleEndianLzwCompressedWithPredictor = "Tiff/tiled_rgba_64bit_little_endian_lzw_compressed_predictor.tiff";
1016+
public const string TiledRgba64BitBigEndianLzwCompressedWithPredictor = "Tiff/tiled_rgba_64bit_big_endian_lzw_compressed_predictor.tiff";
1017+
public const string TiledRgb96BitLittleEndianLzwCompressedWithPredictor = "Tiff/tiled_rgb_96bit_little_endian_lzw_compressed_predictor.tiff";
1018+
public const string TiledRgb96BitBigEndianLzwCompressedWithPredictor = "Tiff/tiled_rgb_96bit_big_endian_lzw_compressed_predictor.tiff";
1019+
public const string TiledRgba128BitLittleEndianLzwCompressedWithPredictor = "Tiff/tiled_rgba_128bit_little_endian_lzw_compressed_predictor.tiff";
1020+
public const string TiledRgba128BitBigEndianLzwCompressedWithPredictor = "Tiff/tiled_rgba_128bit_big_endian_lzw_compressed_predictor.tiff";
10061021

10071022
// Images with alpha channel.
10081023
public const string Rgba2BitUnassociatedAlpha = "Tiff/RgbaUnassociatedAlpha2bit.tiff";
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
version https://git-lfs.github.com/spec/v1
2+
oid sha256:d1cf5098ff98ded0a55cfa73f823cef9c324a66e38ce4a82bae2d3ef4c058c3e
3+
size 78817
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
version https://git-lfs.github.com/spec/v1
2+
oid sha256:879bacee73f5fea767439071aa6057d66d2d61bc554b109abb7b79765873730b
3+
size 78795
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
version https://git-lfs.github.com/spec/v1
2+
oid sha256:41140a44fde93ea15514b153f1fd4d15f8e69fc8ca0c88336f01c700c4d06f93
3+
size 104333

0 commit comments

Comments
 (0)