From f72be91d106d6e05c2e19dbddd0c0cde096d7032 Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Sun, 2 Feb 2025 19:27:42 +0100 Subject: [PATCH 01/17] Undo horizontal prediction for each tile row in case of tiled tiff's --- .../Decompressors/DeflateTiffCompression.cs | 9 +- .../Tiff/Compression/HorizontalPredictor.cs | 91 ++++++++++++------- .../Compression/TiffDecompressorsFactory.cs | 5 +- .../Formats/Tiff/TiffDecoderCore.cs | 15 ++- .../DeflateTiffCompressionTests.cs | 2 +- 5 files changed, 83 insertions(+), 39 deletions(-) diff --git a/src/ImageSharp/Formats/Tiff/Compression/Decompressors/DeflateTiffCompression.cs b/src/ImageSharp/Formats/Tiff/Compression/Decompressors/DeflateTiffCompression.cs index 27c311009c..3e874b7d23 100644 --- a/src/ImageSharp/Formats/Tiff/Compression/Decompressors/DeflateTiffCompression.cs +++ b/src/ImageSharp/Formats/Tiff/Compression/Decompressors/DeflateTiffCompression.cs @@ -22,6 +22,8 @@ internal sealed class DeflateTiffCompression : TiffBaseDecompressor private readonly TiffColorType colorType; + private readonly bool isTiled; + /// /// Initializes a new instance of the class. /// @@ -31,11 +33,13 @@ internal sealed class DeflateTiffCompression : 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 DeflateTiffCompression(MemoryAllocator memoryAllocator, int width, int bitsPerPixel, TiffColorType colorType, TiffPredictor predictor, bool isBigEndian) + /// 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) : base(memoryAllocator, width, bitsPerPixel, predictor) { this.colorType = colorType; this.isBigEndian = isBigEndian; + this.isTiled = isTiled; } /// @@ -68,7 +72,8 @@ protected override void Decompress(BufferedReadStream stream, int byteCount, int } } - if (this.Predictor == TiffPredictor.Horizontal) + // 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) { 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 30a9335286..21306e43ff 100644 --- a/src/ImageSharp/Formats/Tiff/Compression/HorizontalPredictor.cs +++ b/src/ImageSharp/Formats/Tiff/Compression/HorizontalPredictor.cs @@ -62,6 +62,22 @@ public static void Undo(Span pixelBytes, int width, TiffColorType colorTyp } } + public static void UndoRow(Span pixelBytes, int width, int y, TiffColorType colorType) + { + // TODO: Implement missing colortypes, see above. + switch (colorType) + { + case TiffColorType.Rgb888: + case TiffColorType.CieLab: + UndoRgb24BitRow(pixelBytes, width, y); + break; + case TiffColorType.Rgba8888: + case TiffColorType.Cmyk: + UndoRgba32BitRow(pixelBytes, width, y); + break; + } + } + public static void ApplyHorizontalPrediction(Span rows, int width, int bitsPerPixel) { if (bitsPerPixel == 8) @@ -257,27 +273,56 @@ private static void UndoGray32Bit(Span pixelBytes, int width, bool isBigEn } } + private static void UndoRgb24BitRow(Span pixelBytes, int width, int y) + { + int rowBytesCount = width * 3; + Span rowBytes = pixelBytes.Slice(y * rowBytesCount, rowBytesCount); + Span rowRgb = MemoryMarshal.Cast(rowBytes)[..width]; + ref Rgb24 rowRgbBase = ref MemoryMarshal.GetReference(rowRgb); + byte r = rowRgbBase.R; + byte g = rowRgbBase.G; + byte b = rowRgbBase.B; + + for (int x = 1; x < rowRgb.Length; x++) + { + ref Rgb24 pixel = ref rowRgb[x]; + r += pixel.R; + g += pixel.G; + b += pixel.B; + pixel = new Rgb24(r, g, b); + } + } + private static void UndoRgb24Bit(Span pixelBytes, int width) { int rowBytesCount = width * 3; int height = pixelBytes.Length / rowBytesCount; for (int y = 0; y < height; y++) { - Span rowBytes = pixelBytes.Slice(y * rowBytesCount, rowBytesCount); - Span rowRgb = MemoryMarshal.Cast(rowBytes)[..width]; - ref Rgb24 rowRgbBase = ref MemoryMarshal.GetReference(rowRgb); - byte r = rowRgbBase.R; - byte g = rowRgbBase.G; - byte b = rowRgbBase.B; + UndoRgb24BitRow(pixelBytes, width, y); + } + } - for (int x = 1; x < rowRgb.Length; x++) - { - ref Rgb24 pixel = ref rowRgb[x]; - r += pixel.R; - g += pixel.G; - b += pixel.B; - pixel = new Rgb24(r, g, b); - } + private static void UndoRgba32BitRow(Span pixelBytes, int width, int y) + { + int rowBytesCount = width * 4; + + Span rowBytes = pixelBytes.Slice(y * rowBytesCount, rowBytesCount); + Span rowRgb = MemoryMarshal.Cast(rowBytes)[..width]; + ref Rgba32 rowRgbBase = ref MemoryMarshal.GetReference(rowRgb); + byte r = rowRgbBase.R; + byte g = rowRgbBase.G; + byte b = rowRgbBase.B; + byte a = rowRgbBase.A; + + for (int x = 1; x < rowRgb.Length; x++) + { + ref Rgba32 pixel = ref rowRgb[x]; + r += pixel.R; + g += pixel.G; + b += pixel.B; + a += pixel.A; + pixel = new Rgba32(r, g, b, a); } } @@ -287,23 +332,7 @@ private static void UndoRgba32Bit(Span pixelBytes, int width) int height = pixelBytes.Length / rowBytesCount; for (int y = 0; y < height; y++) { - Span rowBytes = pixelBytes.Slice(y * rowBytesCount, rowBytesCount); - Span rowRgb = MemoryMarshal.Cast(rowBytes)[..width]; - ref Rgba32 rowRgbBase = ref MemoryMarshal.GetReference(rowRgb); - byte r = rowRgbBase.R; - byte g = rowRgbBase.G; - byte b = rowRgbBase.B; - byte a = rowRgbBase.A; - - for (int x = 1; x < rowRgb.Length; x++) - { - ref Rgba32 pixel = ref rowRgb[x]; - r += pixel.R; - g += pixel.G; - b += pixel.B; - a += pixel.A; - pixel = new Rgba32(r, g, b, a); - } + UndoRgba32BitRow(pixelBytes, width, y); } } diff --git a/src/ImageSharp/Formats/Tiff/Compression/TiffDecompressorsFactory.cs b/src/ImageSharp/Formats/Tiff/Compression/TiffDecompressorsFactory.cs index 720e376b9d..c05d14dc6c 100644 --- a/src/ImageSharp/Formats/Tiff/Compression/TiffDecompressorsFactory.cs +++ b/src/ImageSharp/Formats/Tiff/Compression/TiffDecompressorsFactory.cs @@ -24,7 +24,8 @@ public static TiffBaseDecompressor Create( byte[] jpegTables, uint oldJpegStartOfImageMarker, TiffFillOrder fillOrder, - ByteOrder byteOrder) + ByteOrder byteOrder, + bool isTiled = false) { switch (method) { @@ -40,7 +41,7 @@ public static TiffBaseDecompressor Create( 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); + return new DeflateTiffCompression(allocator, width, bitsPerPixel, colorType, predictor, byteOrder == ByteOrder.BigEndian, isTiled); 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 d699a7b631..43d7944eab 100644 --- a/src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs +++ b/src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs @@ -683,7 +683,8 @@ private void DecodeTilesChunky( Span tileBufferSpan = tileBuffer.GetSpan(); Span uncompressedPixelBufferSpan = uncompressedPixelBuffer.GetSpan(); - using TiffBaseDecompressor decompressor = this.CreateDecompressor(frame.Width, bitsPerPixel); + bool isTiled = true; + using TiffBaseDecompressor decompressor = this.CreateDecompressor(frame.Width, bitsPerPixel, isTiled); TiffBaseColorDecoder colorDecoder = this.CreateChunkyColorDecoder(); int tileIndex = 0; @@ -712,6 +713,13 @@ private void DecodeTilesChunky( { Span uncompressedPixelRow = uncompressedPixelBufferSpan.Slice(uncompressedPixelBufferOffset, bytesToCopy); tileBufferSpan.Slice(tileBufferOffset, bytesToCopy).CopyTo(uncompressedPixelRow); + + // Undo the horziontal predictor for each tile row. + if (this.Predictor == TiffPredictor.Horizontal) + { + HorizontalPredictor.UndoRow(uncompressedPixelRow, tileLength, 0, this.ColorType); + } + tileBufferOffset += bytesPerTileRow; uncompressedPixelBufferOffset += bytesPerRow; } @@ -750,7 +758,7 @@ private TiffBasePlanarColorDecoder CreatePlanarColorDecoder() this.YcbcrSubSampling, this.byteOrder); - private TiffBaseDecompressor CreateDecompressor(int frameWidth, int bitsPerPixel) + private TiffBaseDecompressor CreateDecompressor(int frameWidth, int bitsPerPixel, bool isTiled = false) where TPixel : unmanaged, IPixel => TiffDecompressorsFactory.Create( this.Options, @@ -765,7 +773,8 @@ private TiffBaseDecompressor CreateDecompressor(int frameWidth, int bits this.JpegTables, this.OldJpegCompressionStartOfImageMarker.GetValueOrDefault(), this.FillOrder, - this.byteOrder); + this.byteOrder, + isTiled); 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 1b12adac23..b0ca4699e5 100644 --- a/tests/ImageSharp.Tests/Formats/Tiff/Compression/DeflateTiffCompressionTests.cs +++ b/tests/ImageSharp.Tests/Formats/Tiff/Compression/DeflateTiffCompressionTests.cs @@ -23,7 +23,7 @@ public void Compress_Decompress_Roundtrip_Works(byte[] data) 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); + using var decompressor = new DeflateTiffCompression(Configuration.Default.MemoryAllocator, 10, 8, TiffColorType.BlackIsZero8, TiffPredictor.None, false, false); decompressor.Decompress(stream, 0, (uint)stream.Length, 1, buffer, default); From e186c52f32d23f379e70783436e390cf5c1eaa9f Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Mon, 3 Feb 2025 19:39:36 +0100 Subject: [PATCH 02/17] Add test case for tiled tiff, deflate compressed with predictor --- src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs | 3 ++- tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs | 1 + tests/ImageSharp.Tests/TestImages.cs | 1 + .../Input/Tiff/tiled_rgba_deflate_compressed_predictor.tiff | 3 +++ 4 files changed, 7 insertions(+), 1 deletion(-) create mode 100644 tests/Images/Input/Tiff/tiled_rgba_deflate_compressed_predictor.tiff diff --git a/src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs b/src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs index 43d7944eab..1c15646970 100644 --- a/src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs +++ b/src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs @@ -717,7 +717,8 @@ private void DecodeTilesChunky( // Undo the horziontal predictor for each tile row. if (this.Predictor == TiffPredictor.Horizontal) { - HorizontalPredictor.UndoRow(uncompressedPixelRow, tileLength, 0, this.ColorType); + int pixelsInTileRow = isLastHorizontalTile ? remainingPixelsInRow : tileLength; + HorizontalPredictor.UndoRow(uncompressedPixelRow, pixelsInTileRow, 0, this.ColorType); } tileBufferOffset += bytesPerTileRow; diff --git a/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs index 09cfe2cbea..ed6bad03aa 100644 --- a/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs @@ -87,6 +87,7 @@ public void TiffDecoder_CanDecode_Planar(TestImageProvider provi [WithFile(QuadTile, PixelTypes.Rgba32)] [WithFile(TiledChunky, PixelTypes.Rgba32)] [WithFile(TiledPlanar, PixelTypes.Rgba32)] + [WithFile(TiledDeflateCompressedWithPredictor, PixelTypes.Rgba32)] public void TiffDecoder_CanDecode_Tiled(TestImageProvider provider) where TPixel : unmanaged, IPixel => TestTiffDecoder(provider); diff --git a/tests/ImageSharp.Tests/TestImages.cs b/tests/ImageSharp.Tests/TestImages.cs index 4130474b58..cea4e3059f 100644 --- a/tests/ImageSharp.Tests/TestImages.cs +++ b/tests/ImageSharp.Tests/TestImages.cs @@ -986,6 +986,7 @@ public static class Tiff public const string QuadTile = "Tiff/quad-tile.tiff"; public const string TiledChunky = "Tiff/rgb_uncompressed_tiled_chunky.tiff"; public const string TiledPlanar = "Tiff/rgb_uncompressed_tiled_planar.tiff"; + public const string TiledDeflateCompressedWithPredictor = "Tiff/tiled_rgba_deflate_compressed_predictor.tiff"; // Images with alpha channel. public const string Rgba2BitUnassociatedAlpha = "Tiff/RgbaUnassociatedAlpha2bit.tiff"; diff --git a/tests/Images/Input/Tiff/tiled_rgba_deflate_compressed_predictor.tiff b/tests/Images/Input/Tiff/tiled_rgba_deflate_compressed_predictor.tiff new file mode 100644 index 0000000000..f30e29ec85 --- /dev/null +++ b/tests/Images/Input/Tiff/tiled_rgba_deflate_compressed_predictor.tiff @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c4f44a67086fafc1d8784922a491e0b944b4afcd09f14b66d951b042d2745e0c +size 166487 From 787e04d15a162937e6c19b8c6da8072d83d2d03e Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Tue, 4 Feb 2025 18:17:21 +0100 Subject: [PATCH 03/17] Add test case for tiled tiff, deflate compressed with predictor and color type Rgb888 --- tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs | 3 ++- tests/ImageSharp.Tests/TestImages.cs | 3 ++- .../Input/Tiff/tiled_rgb_deflate_compressed_predictor.tiff | 3 +++ 3 files changed, 7 insertions(+), 2 deletions(-) create mode 100644 tests/Images/Input/Tiff/tiled_rgb_deflate_compressed_predictor.tiff diff --git a/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs index ed6bad03aa..ee04ee4fa3 100644 --- a/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs @@ -87,7 +87,8 @@ public void TiffDecoder_CanDecode_Planar(TestImageProvider provi [WithFile(QuadTile, PixelTypes.Rgba32)] [WithFile(TiledChunky, PixelTypes.Rgba32)] [WithFile(TiledPlanar, PixelTypes.Rgba32)] - [WithFile(TiledDeflateCompressedWithPredictor, PixelTypes.Rgba32)] + [WithFile(TiledRgbaDeflateCompressedWithPredictor, PixelTypes.Rgba32)] + [WithFile(TiledRgbDeflateCompressedWithPredictor, PixelTypes.Rgba32)] public void TiffDecoder_CanDecode_Tiled(TestImageProvider provider) where TPixel : unmanaged, IPixel => TestTiffDecoder(provider); diff --git a/tests/ImageSharp.Tests/TestImages.cs b/tests/ImageSharp.Tests/TestImages.cs index cea4e3059f..0d8451b02e 100644 --- a/tests/ImageSharp.Tests/TestImages.cs +++ b/tests/ImageSharp.Tests/TestImages.cs @@ -986,7 +986,8 @@ public static class Tiff public const string QuadTile = "Tiff/quad-tile.tiff"; public const string TiledChunky = "Tiff/rgb_uncompressed_tiled_chunky.tiff"; public const string TiledPlanar = "Tiff/rgb_uncompressed_tiled_planar.tiff"; - public const string TiledDeflateCompressedWithPredictor = "Tiff/tiled_rgba_deflate_compressed_predictor.tiff"; + public const string TiledRgbaDeflateCompressedWithPredictor = "Tiff/tiled_rgba_deflate_compressed_predictor.tiff"; + public const string TiledRgbDeflateCompressedWithPredictor = "Tiff/tiled_rgb_deflate_compressed_predictor.tiff"; // Images with alpha channel. public const string Rgba2BitUnassociatedAlpha = "Tiff/RgbaUnassociatedAlpha2bit.tiff"; diff --git a/tests/Images/Input/Tiff/tiled_rgb_deflate_compressed_predictor.tiff b/tests/Images/Input/Tiff/tiled_rgb_deflate_compressed_predictor.tiff new file mode 100644 index 0000000000..d897aa94cb --- /dev/null +++ b/tests/Images/Input/Tiff/tiled_rgb_deflate_compressed_predictor.tiff @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ca9253037bde106e4af13f6264a866d5e98945f471eec6fb43e3a4108631fba6 +size 145991 From e3c747158dd648eb3a630a94968efb2038576f13 Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Thu, 6 Feb 2025 18:29:30 +0100 Subject: [PATCH 04/17] Add test case for tiled gray tiff, deflate compressed with predictor --- .../Tiff/Compression/HorizontalPredictor.cs | 27 +++++++++++++------ .../Formats/Tiff/TiffDecoderTests.cs | 1 + tests/ImageSharp.Tests/TestImages.cs | 1 + ...led_gray_deflate_compressed_predictor.tiff | 3 +++ 4 files changed, 24 insertions(+), 8 deletions(-) create mode 100644 tests/Images/Input/Tiff/tiled_gray_deflate_compressed_predictor.tiff diff --git a/src/ImageSharp/Formats/Tiff/Compression/HorizontalPredictor.cs b/src/ImageSharp/Formats/Tiff/Compression/HorizontalPredictor.cs index 21306e43ff..b60f3cb0d4 100644 --- a/src/ImageSharp/Formats/Tiff/Compression/HorizontalPredictor.cs +++ b/src/ImageSharp/Formats/Tiff/Compression/HorizontalPredictor.cs @@ -67,6 +67,11 @@ public static void UndoRow(Span pixelBytes, int width, int y, TiffColorTyp // TODO: Implement missing colortypes, see above. switch (colorType) { + case TiffColorType.BlackIsZero8: + case TiffColorType.WhiteIsZero8: + case TiffColorType.PaletteColor: + UndoGray8BitRow(pixelBytes, width, y); + break; case TiffColorType.Rgb888: case TiffColorType.CieLab: UndoRgb24BitRow(pixelBytes, width, y); @@ -168,20 +173,26 @@ private static void ApplyHorizontalPrediction8Bit(Span rows, int width) } } + private static void UndoGray8BitRow(Span pixelBytes, int width, int y) + { + int rowBytesCount = width; + int height = pixelBytes.Length / rowBytesCount; + Span rowBytes = pixelBytes.Slice(y * rowBytesCount, rowBytesCount); + byte pixelValue = rowBytes[0]; + for (int x = 1; x < width; x++) + { + pixelValue += rowBytes[x]; + rowBytes[x] = pixelValue; + } + } + private static void UndoGray8Bit(Span pixelBytes, int width) { int rowBytesCount = width; int height = pixelBytes.Length / rowBytesCount; for (int y = 0; y < height; y++) { - Span rowBytes = pixelBytes.Slice(y * rowBytesCount, rowBytesCount); - - byte pixelValue = rowBytes[0]; - for (int x = 1; x < width; x++) - { - pixelValue += rowBytes[x]; - rowBytes[x] = pixelValue; - } + UndoGray8BitRow(pixelBytes, width, y); } } diff --git a/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs index ee04ee4fa3..e3cb4bf9b8 100644 --- a/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs @@ -89,6 +89,7 @@ public void TiffDecoder_CanDecode_Planar(TestImageProvider provi [WithFile(TiledPlanar, PixelTypes.Rgba32)] [WithFile(TiledRgbaDeflateCompressedWithPredictor, PixelTypes.Rgba32)] [WithFile(TiledRgbDeflateCompressedWithPredictor, PixelTypes.Rgba32)] + [WithFile(TiledGrayDeflateCompressedWithPredictor, PixelTypes.Rgba32)] public void TiffDecoder_CanDecode_Tiled(TestImageProvider provider) where TPixel : unmanaged, IPixel => TestTiffDecoder(provider); diff --git a/tests/ImageSharp.Tests/TestImages.cs b/tests/ImageSharp.Tests/TestImages.cs index 0d8451b02e..8bc9d131fe 100644 --- a/tests/ImageSharp.Tests/TestImages.cs +++ b/tests/ImageSharp.Tests/TestImages.cs @@ -988,6 +988,7 @@ public static class Tiff public const string TiledPlanar = "Tiff/rgb_uncompressed_tiled_planar.tiff"; public const string TiledRgbaDeflateCompressedWithPredictor = "Tiff/tiled_rgba_deflate_compressed_predictor.tiff"; public const string TiledRgbDeflateCompressedWithPredictor = "Tiff/tiled_rgb_deflate_compressed_predictor.tiff"; + public const string TiledGrayDeflateCompressedWithPredictor = "Tiff/tiled_gray_deflate_compressed_predictor.tiff"; // Images with alpha channel. public const string Rgba2BitUnassociatedAlpha = "Tiff/RgbaUnassociatedAlpha2bit.tiff"; diff --git a/tests/Images/Input/Tiff/tiled_gray_deflate_compressed_predictor.tiff b/tests/Images/Input/Tiff/tiled_gray_deflate_compressed_predictor.tiff new file mode 100644 index 0000000000..ed9cd4bc05 --- /dev/null +++ b/tests/Images/Input/Tiff/tiled_gray_deflate_compressed_predictor.tiff @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b5133a684a86dbc9ef48f1f988ec505765f086861c96033d350b7565ebd28271 +size 52663 From f11fbc14d915394d5c09d581107e276904b1e6cc Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Sat, 8 Feb 2025 18:38:24 +0100 Subject: [PATCH 05/17] Add test cases for tiled 16 bit gray tiff's --- .../Tiff/Compression/HorizontalPredictor.cs | 80 ++++++++++++------- .../Formats/Tiff/TiffDecoderCore.cs | 2 +- .../Formats/Tiff/TiffDecoderTests.cs | 2 + tests/ImageSharp.Tests/TestImages.cs | 2 + ...g_endian_deflate_compressed_predictor.tiff | 3 + ...e_endian_deflate_compressed_predictor.tiff | 3 + 6 files changed, 64 insertions(+), 28 deletions(-) create mode 100644 tests/Images/Input/Tiff/tiled_gray_16bit_big_endian_deflate_compressed_predictor.tiff create mode 100644 tests/Images/Input/Tiff/tiled_gray_16bit_little_endian_deflate_compressed_predictor.tiff diff --git a/src/ImageSharp/Formats/Tiff/Compression/HorizontalPredictor.cs b/src/ImageSharp/Formats/Tiff/Compression/HorizontalPredictor.cs index b60f3cb0d4..e37a83528e 100644 --- a/src/ImageSharp/Formats/Tiff/Compression/HorizontalPredictor.cs +++ b/src/ImageSharp/Formats/Tiff/Compression/HorizontalPredictor.cs @@ -62,7 +62,7 @@ public static void Undo(Span pixelBytes, int width, TiffColorType colorTyp } } - public static void UndoRow(Span pixelBytes, int width, int y, TiffColorType colorType) + public static void UndoRow(Span pixelBytes, int width, int y, TiffColorType colorType, bool isBigEndian) { // TODO: Implement missing colortypes, see above. switch (colorType) @@ -71,6 +71,18 @@ public static void UndoRow(Span pixelBytes, int width, int y, TiffColorTyp case TiffColorType.WhiteIsZero8: case TiffColorType.PaletteColor: UndoGray8BitRow(pixelBytes, width, y); + break; + case TiffColorType.BlackIsZero16: + case TiffColorType.WhiteIsZero16: + if (isBigEndian) + { + UndoGray16BitBigEndianRow(pixelBytes, width, y); + } + else + { + UndoGray16BitLittleEndianRow(pixelBytes, width, y); + } + break; case TiffColorType.Rgb888: case TiffColorType.CieLab: @@ -196,6 +208,44 @@ private static void UndoGray8Bit(Span pixelBytes, int width) } } + private static void UndoGray16BitBigEndianRow(Span pixelBytes, int width, int y) + { + int rowBytesCount = width * 2; + int height = pixelBytes.Length / rowBytesCount; + int offset = 0; + Span rowBytes = pixelBytes.Slice(y * rowBytesCount, rowBytesCount); + ushort pixelValue = TiffUtilities.ConvertToUShortBigEndian(rowBytes.Slice(offset, 2)); + offset += 2; + + for (int x = 1; x < width; x++) + { + Span rowSpan = rowBytes.Slice(offset, 2); + ushort diff = TiffUtilities.ConvertToUShortBigEndian(rowSpan); + pixelValue += diff; + BinaryPrimitives.WriteUInt16BigEndian(rowSpan, pixelValue); + offset += 2; + } + } + + private static void UndoGray16BitLittleEndianRow(Span pixelBytes, int width, int y) + { + int rowBytesCount = width * 2; + int height = pixelBytes.Length / rowBytesCount; + int offset = 0; + Span rowBytes = pixelBytes.Slice(y * rowBytesCount, rowBytesCount); + ushort pixelValue = TiffUtilities.ConvertToUShortLittleEndian(rowBytes.Slice(offset, 2)); + offset += 2; + + for (int x = 1; x < width; x++) + { + Span rowSpan = rowBytes.Slice(offset, 2); + ushort diff = TiffUtilities.ConvertToUShortLittleEndian(rowSpan); + pixelValue += diff; + BinaryPrimitives.WriteUInt16LittleEndian(rowSpan, pixelValue); + offset += 2; + } + } + private static void UndoGray16Bit(Span pixelBytes, int width, bool isBigEndian) { int rowBytesCount = width * 2; @@ -204,38 +254,14 @@ private static void UndoGray16Bit(Span pixelBytes, int width, bool isBigEn { for (int y = 0; y < height; y++) { - int offset = 0; - Span rowBytes = pixelBytes.Slice(y * rowBytesCount, rowBytesCount); - ushort pixelValue = TiffUtilities.ConvertToUShortBigEndian(rowBytes.Slice(offset, 2)); - offset += 2; - - for (int x = 1; x < width; x++) - { - Span rowSpan = rowBytes.Slice(offset, 2); - ushort diff = TiffUtilities.ConvertToUShortBigEndian(rowSpan); - pixelValue += diff; - BinaryPrimitives.WriteUInt16BigEndian(rowSpan, pixelValue); - offset += 2; - } + UndoGray16BitBigEndianRow(pixelBytes, width, y); } } else { for (int y = 0; y < height; y++) { - int offset = 0; - Span rowBytes = pixelBytes.Slice(y * rowBytesCount, rowBytesCount); - ushort pixelValue = TiffUtilities.ConvertToUShortLittleEndian(rowBytes.Slice(offset, 2)); - offset += 2; - - for (int x = 1; x < width; x++) - { - Span rowSpan = rowBytes.Slice(offset, 2); - ushort diff = TiffUtilities.ConvertToUShortLittleEndian(rowSpan); - pixelValue += diff; - BinaryPrimitives.WriteUInt16LittleEndian(rowSpan, pixelValue); - offset += 2; - } + UndoGray16BitLittleEndianRow(pixelBytes, width, y); } } } diff --git a/src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs b/src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs index 1c15646970..1b23a6e2b7 100644 --- a/src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs +++ b/src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs @@ -718,7 +718,7 @@ private void DecodeTilesChunky( if (this.Predictor == TiffPredictor.Horizontal) { int pixelsInTileRow = isLastHorizontalTile ? remainingPixelsInRow : tileLength; - HorizontalPredictor.UndoRow(uncompressedPixelRow, pixelsInTileRow, 0, this.ColorType); + HorizontalPredictor.UndoRow(uncompressedPixelRow, pixelsInTileRow, 0, this.ColorType, this.byteOrder == ByteOrder.BigEndian); } tileBufferOffset += bytesPerTileRow; diff --git a/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs index e3cb4bf9b8..00f498e9ae 100644 --- a/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs @@ -90,6 +90,8 @@ public void TiffDecoder_CanDecode_Planar(TestImageProvider provi [WithFile(TiledRgbaDeflateCompressedWithPredictor, PixelTypes.Rgba32)] [WithFile(TiledRgbDeflateCompressedWithPredictor, PixelTypes.Rgba32)] [WithFile(TiledGrayDeflateCompressedWithPredictor, PixelTypes.Rgba32)] + [WithFile(TiledGray16BitLittleEndianDeflateCompressedWithPredictor, PixelTypes.Rgba32)] + [WithFile(TiledGray16BitBigEndianDeflateCompressedWithPredictor, PixelTypes.Rgba32)] public void TiffDecoder_CanDecode_Tiled(TestImageProvider provider) where TPixel : unmanaged, IPixel => TestTiffDecoder(provider); diff --git a/tests/ImageSharp.Tests/TestImages.cs b/tests/ImageSharp.Tests/TestImages.cs index 8bc9d131fe..fee925af3c 100644 --- a/tests/ImageSharp.Tests/TestImages.cs +++ b/tests/ImageSharp.Tests/TestImages.cs @@ -989,6 +989,8 @@ public static class Tiff public const string TiledRgbaDeflateCompressedWithPredictor = "Tiff/tiled_rgba_deflate_compressed_predictor.tiff"; public const string TiledRgbDeflateCompressedWithPredictor = "Tiff/tiled_rgb_deflate_compressed_predictor.tiff"; public const string TiledGrayDeflateCompressedWithPredictor = "Tiff/tiled_gray_deflate_compressed_predictor.tiff"; + public const string TiledGray16BitLittleEndianDeflateCompressedWithPredictor = "Tiff/tiled_gray_16bit_little_endian_deflate_compressed_predictor.tiff"; + public const string TiledGray16BitBigEndianDeflateCompressedWithPredictor = "Tiff/tiled_gray_16bit_big_endian_deflate_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_deflate_compressed_predictor.tiff b/tests/Images/Input/Tiff/tiled_gray_16bit_big_endian_deflate_compressed_predictor.tiff new file mode 100644 index 0000000000..778601cd8b --- /dev/null +++ b/tests/Images/Input/Tiff/tiled_gray_16bit_big_endian_deflate_compressed_predictor.tiff @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e267cf78bebba51628f0aca98c8720e8ea8013b9e5f96c8f12df1c153f34f065 +size 80195 diff --git a/tests/Images/Input/Tiff/tiled_gray_16bit_little_endian_deflate_compressed_predictor.tiff b/tests/Images/Input/Tiff/tiled_gray_16bit_little_endian_deflate_compressed_predictor.tiff new file mode 100644 index 0000000000..2fbe32e6fa --- /dev/null +++ b/tests/Images/Input/Tiff/tiled_gray_16bit_little_endian_deflate_compressed_predictor.tiff @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:19b4a2ee8761e0016a598f66f12eb62edf4c4d30f33694d30986ce84516ac454 +size 80177 From 47c67558cbaef446a8f685aaa4e1384964094964 Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Sun, 9 Feb 2025 13:14:58 +0100 Subject: [PATCH 06/17] Add test cases for tiled 32 bit gray tiff's --- .../Tiff/Compression/HorizontalPredictor.cs | 80 +++++++++++++------ .../Formats/Tiff/TiffDecoderTests.cs | 2 + tests/ImageSharp.Tests/TestImages.cs | 2 + ...g_endian_deflate_compressed_predictor.tiff | 3 + ...e_endian_deflate_compressed_predictor.tiff | 3 + 5 files changed, 64 insertions(+), 26 deletions(-) create mode 100644 tests/Images/Input/Tiff/tiled_gray_32bit_big_endian_deflate_compressed_predictor.tiff create mode 100644 tests/Images/Input/Tiff/tiled_gray_32bit_little_endian_deflate_compressed_predictor.tiff diff --git a/src/ImageSharp/Formats/Tiff/Compression/HorizontalPredictor.cs b/src/ImageSharp/Formats/Tiff/Compression/HorizontalPredictor.cs index e37a83528e..ce1736ca77 100644 --- a/src/ImageSharp/Formats/Tiff/Compression/HorizontalPredictor.cs +++ b/src/ImageSharp/Formats/Tiff/Compression/HorizontalPredictor.cs @@ -83,6 +83,18 @@ public static void UndoRow(Span pixelBytes, int width, int y, TiffColorTyp UndoGray16BitLittleEndianRow(pixelBytes, width, y); } + break; + case TiffColorType.BlackIsZero32: + case TiffColorType.WhiteIsZero32: + if (isBigEndian) + { + UndoGray32BitBigEndianRow(pixelBytes, width, y); + } + else + { + UndoGray32BitLittleEndianRow(pixelBytes, width, y); + } + break; case TiffColorType.Rgb888: case TiffColorType.CieLab: @@ -266,6 +278,46 @@ private static void UndoGray16Bit(Span pixelBytes, int width, bool isBigEn } } + private static void UndoGray32BitBigEndianRow(Span pixelBytes, int width, int y) + { + int rowBytesCount = width * 4; + int height = pixelBytes.Length / rowBytesCount; + + int offset = 0; + Span rowBytes = pixelBytes.Slice(y * rowBytesCount, rowBytesCount); + uint pixelValue = TiffUtilities.ConvertToUIntBigEndian(rowBytes.Slice(offset, 4)); + offset += 4; + + for (int x = 1; x < width; x++) + { + Span rowSpan = rowBytes.Slice(offset, 4); + uint diff = TiffUtilities.ConvertToUIntBigEndian(rowSpan); + pixelValue += diff; + BinaryPrimitives.WriteUInt32BigEndian(rowSpan, pixelValue); + offset += 4; + } + } + + private static void UndoGray32BitLittleEndianRow(Span pixelBytes, int width, int y) + { + int rowBytesCount = width * 4; + int height = pixelBytes.Length / rowBytesCount; + + int offset = 0; + Span rowBytes = pixelBytes.Slice(y * rowBytesCount, rowBytesCount); + uint pixelValue = TiffUtilities.ConvertToUIntLittleEndian(rowBytes.Slice(offset, 4)); + offset += 4; + + for (int x = 1; x < width; x++) + { + Span rowSpan = rowBytes.Slice(offset, 4); + uint diff = TiffUtilities.ConvertToUIntLittleEndian(rowSpan); + pixelValue += diff; + BinaryPrimitives.WriteUInt32LittleEndian(rowSpan, pixelValue); + offset += 4; + } + } + private static void UndoGray32Bit(Span pixelBytes, int width, bool isBigEndian) { int rowBytesCount = width * 4; @@ -274,38 +326,14 @@ private static void UndoGray32Bit(Span pixelBytes, int width, bool isBigEn { for (int y = 0; y < height; y++) { - int offset = 0; - Span rowBytes = pixelBytes.Slice(y * rowBytesCount, rowBytesCount); - uint pixelValue = TiffUtilities.ConvertToUIntBigEndian(rowBytes.Slice(offset, 4)); - offset += 4; - - for (int x = 1; x < width; x++) - { - Span rowSpan = rowBytes.Slice(offset, 4); - uint diff = TiffUtilities.ConvertToUIntBigEndian(rowSpan); - pixelValue += diff; - BinaryPrimitives.WriteUInt32BigEndian(rowSpan, pixelValue); - offset += 4; - } + UndoGray32BitBigEndianRow(pixelBytes, width, y); } } else { for (int y = 0; y < height; y++) { - int offset = 0; - Span rowBytes = pixelBytes.Slice(y * rowBytesCount, rowBytesCount); - uint pixelValue = TiffUtilities.ConvertToUIntLittleEndian(rowBytes.Slice(offset, 4)); - offset += 4; - - for (int x = 1; x < width; x++) - { - Span rowSpan = rowBytes.Slice(offset, 4); - uint diff = TiffUtilities.ConvertToUIntLittleEndian(rowSpan); - pixelValue += diff; - BinaryPrimitives.WriteUInt32LittleEndian(rowSpan, pixelValue); - offset += 4; - } + UndoGray32BitLittleEndianRow(pixelBytes, width, y); } } } diff --git a/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs index 00f498e9ae..c0d48e6942 100644 --- a/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs @@ -92,6 +92,8 @@ public void TiffDecoder_CanDecode_Planar(TestImageProvider provi [WithFile(TiledGrayDeflateCompressedWithPredictor, PixelTypes.Rgba32)] [WithFile(TiledGray16BitLittleEndianDeflateCompressedWithPredictor, PixelTypes.Rgba32)] [WithFile(TiledGray16BitBigEndianDeflateCompressedWithPredictor, PixelTypes.Rgba32)] + [WithFile(TiledGray32BitLittleEndianDeflateCompressedWithPredictor, PixelTypes.Rgba32)] + [WithFile(TiledGray32BitBigEndianDeflateCompressedWithPredictor, PixelTypes.Rgba32)] public void TiffDecoder_CanDecode_Tiled(TestImageProvider provider) where TPixel : unmanaged, IPixel => TestTiffDecoder(provider); diff --git a/tests/ImageSharp.Tests/TestImages.cs b/tests/ImageSharp.Tests/TestImages.cs index fee925af3c..d0007184c8 100644 --- a/tests/ImageSharp.Tests/TestImages.cs +++ b/tests/ImageSharp.Tests/TestImages.cs @@ -991,6 +991,8 @@ public static class Tiff public const string TiledGrayDeflateCompressedWithPredictor = "Tiff/tiled_gray_deflate_compressed_predictor.tiff"; public const string TiledGray16BitLittleEndianDeflateCompressedWithPredictor = "Tiff/tiled_gray_16bit_little_endian_deflate_compressed_predictor.tiff"; public const string TiledGray16BitBigEndianDeflateCompressedWithPredictor = "Tiff/tiled_gray_16bit_big_endian_deflate_compressed_predictor.tiff"; + public const string TiledGray32BitLittleEndianDeflateCompressedWithPredictor = "Tiff/tiled_gray_32bit_little_endian_deflate_compressed_predictor.tiff"; + public const string TiledGray32BitBigEndianDeflateCompressedWithPredictor = "Tiff/tiled_gray_32bit_big_endian_deflate_compressed_predictor.tiff"; // Images with alpha channel. public const string Rgba2BitUnassociatedAlpha = "Tiff/RgbaUnassociatedAlpha2bit.tiff"; diff --git a/tests/Images/Input/Tiff/tiled_gray_32bit_big_endian_deflate_compressed_predictor.tiff b/tests/Images/Input/Tiff/tiled_gray_32bit_big_endian_deflate_compressed_predictor.tiff new file mode 100644 index 0000000000..17866b164a --- /dev/null +++ b/tests/Images/Input/Tiff/tiled_gray_32bit_big_endian_deflate_compressed_predictor.tiff @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b674439ce46a39377279755ffa372c5bd863ac7787165e95590c0a9c6c5d681e +size 82469 diff --git a/tests/Images/Input/Tiff/tiled_gray_32bit_little_endian_deflate_compressed_predictor.tiff b/tests/Images/Input/Tiff/tiled_gray_32bit_little_endian_deflate_compressed_predictor.tiff new file mode 100644 index 0000000000..b524237c9a --- /dev/null +++ b/tests/Images/Input/Tiff/tiled_gray_32bit_little_endian_deflate_compressed_predictor.tiff @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3acfecebb3db8b549b7a20a3fdd967ba5a4cbb95cbb9b4a59d332fa6ec809278 +size 82519 From 97133fea558bb8445e63fd03ed4cf29c749ae284 Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Sun, 9 Feb 2025 14:54:25 +0100 Subject: [PATCH 07/17] Add test cases for tiled tiff, deflate compressed with predictor and color type Rgb161616 --- .../Tiff/Compression/HorizontalPredictor.cs | 143 +++++++++++------- .../Formats/Tiff/TiffDecoderTests.cs | 2 + tests/ImageSharp.Tests/TestImages.cs | 2 + ...g_endian_deflate_compressed_predictor.tiff | 3 + ...e_endian_deflate_compressed_predictor.tiff | 3 + 5 files changed, 95 insertions(+), 58 deletions(-) create mode 100644 tests/Images/Input/Tiff/tiled_rgb_48bit_big_endian_deflate_compressed_predictor.tiff create mode 100644 tests/Images/Input/Tiff/tiled_rgb_48bit_little_endian_deflate_compressed_predictor.tiff diff --git a/src/ImageSharp/Formats/Tiff/Compression/HorizontalPredictor.cs b/src/ImageSharp/Formats/Tiff/Compression/HorizontalPredictor.cs index ce1736ca77..16c7d9d0b4 100644 --- a/src/ImageSharp/Formats/Tiff/Compression/HorizontalPredictor.cs +++ b/src/ImageSharp/Formats/Tiff/Compression/HorizontalPredictor.cs @@ -103,6 +103,17 @@ public static void UndoRow(Span pixelBytes, int width, int y, TiffColorTyp case TiffColorType.Rgba8888: case TiffColorType.Cmyk: UndoRgba32BitRow(pixelBytes, width, y); + break; + case TiffColorType.Rgb161616: + if (isBigEndian) + { + UndoRgb48BitBigEndianRow(pixelBytes, width, y); + } + else + { + UndoRgb48BitLittleEndianRow(pixelBytes, width, y); + } + break; } } @@ -401,6 +412,78 @@ private static void UndoRgba32Bit(Span pixelBytes, int width) } } + private static void UndoRgb48BitBigEndianRow(Span pixelBytes, int width, int y) + { + int rowBytesCount = width * 6; + int height = pixelBytes.Length / rowBytesCount; + + int offset = 0; + Span rowBytes = pixelBytes.Slice(y * rowBytesCount, rowBytesCount); + ushort r = TiffUtilities.ConvertToUShortBigEndian(rowBytes.Slice(offset, 2)); + offset += 2; + ushort g = TiffUtilities.ConvertToUShortBigEndian(rowBytes.Slice(offset, 2)); + offset += 2; + ushort b = TiffUtilities.ConvertToUShortBigEndian(rowBytes.Slice(offset, 2)); + offset += 2; + + for (int x = 1; x < width; x++) + { + Span rowSpan = rowBytes.Slice(offset, 2); + ushort deltaR = TiffUtilities.ConvertToUShortBigEndian(rowSpan); + r += deltaR; + BinaryPrimitives.WriteUInt16BigEndian(rowSpan, r); + offset += 2; + + rowSpan = rowBytes.Slice(offset, 2); + ushort deltaG = TiffUtilities.ConvertToUShortBigEndian(rowSpan); + g += deltaG; + BinaryPrimitives.WriteUInt16BigEndian(rowSpan, g); + offset += 2; + + rowSpan = rowBytes.Slice(offset, 2); + ushort deltaB = TiffUtilities.ConvertToUShortBigEndian(rowSpan); + b += deltaB; + BinaryPrimitives.WriteUInt16BigEndian(rowSpan, b); + offset += 2; + } + } + + private static void UndoRgb48BitLittleEndianRow(Span pixelBytes, int width, int y) + { + int rowBytesCount = width * 6; + int height = pixelBytes.Length / rowBytesCount; + + int offset = 0; + Span rowBytes = pixelBytes.Slice(y * rowBytesCount, rowBytesCount); + ushort r = TiffUtilities.ConvertToUShortLittleEndian(rowBytes.Slice(offset, 2)); + offset += 2; + ushort g = TiffUtilities.ConvertToUShortLittleEndian(rowBytes.Slice(offset, 2)); + offset += 2; + ushort b = TiffUtilities.ConvertToUShortLittleEndian(rowBytes.Slice(offset, 2)); + offset += 2; + + for (int x = 1; x < width; x++) + { + Span rowSpan = rowBytes.Slice(offset, 2); + ushort deltaR = TiffUtilities.ConvertToUShortLittleEndian(rowSpan); + r += deltaR; + BinaryPrimitives.WriteUInt16LittleEndian(rowSpan, r); + offset += 2; + + rowSpan = rowBytes.Slice(offset, 2); + ushort deltaG = TiffUtilities.ConvertToUShortLittleEndian(rowSpan); + g += deltaG; + BinaryPrimitives.WriteUInt16LittleEndian(rowSpan, g); + offset += 2; + + rowSpan = rowBytes.Slice(offset, 2); + ushort deltaB = TiffUtilities.ConvertToUShortLittleEndian(rowSpan); + b += deltaB; + BinaryPrimitives.WriteUInt16LittleEndian(rowSpan, b); + offset += 2; + } + } + private static void UndoRgb48Bit(Span pixelBytes, int width, bool isBigEndian) { int rowBytesCount = width * 6; @@ -409,70 +492,14 @@ private static void UndoRgb48Bit(Span pixelBytes, int width, bool isBigEnd { for (int y = 0; y < height; y++) { - int offset = 0; - Span rowBytes = pixelBytes.Slice(y * rowBytesCount, rowBytesCount); - ushort r = TiffUtilities.ConvertToUShortBigEndian(rowBytes.Slice(offset, 2)); - offset += 2; - ushort g = TiffUtilities.ConvertToUShortBigEndian(rowBytes.Slice(offset, 2)); - offset += 2; - ushort b = TiffUtilities.ConvertToUShortBigEndian(rowBytes.Slice(offset, 2)); - offset += 2; - - for (int x = 1; x < width; x++) - { - Span rowSpan = rowBytes.Slice(offset, 2); - ushort deltaR = TiffUtilities.ConvertToUShortBigEndian(rowSpan); - r += deltaR; - BinaryPrimitives.WriteUInt16BigEndian(rowSpan, r); - offset += 2; - - rowSpan = rowBytes.Slice(offset, 2); - ushort deltaG = TiffUtilities.ConvertToUShortBigEndian(rowSpan); - g += deltaG; - BinaryPrimitives.WriteUInt16BigEndian(rowSpan, g); - offset += 2; - - rowSpan = rowBytes.Slice(offset, 2); - ushort deltaB = TiffUtilities.ConvertToUShortBigEndian(rowSpan); - b += deltaB; - BinaryPrimitives.WriteUInt16BigEndian(rowSpan, b); - offset += 2; - } + UndoRgb48BitBigEndianRow(pixelBytes, width, y); } } else { for (int y = 0; y < height; y++) { - int offset = 0; - Span rowBytes = pixelBytes.Slice(y * rowBytesCount, rowBytesCount); - ushort r = TiffUtilities.ConvertToUShortLittleEndian(rowBytes.Slice(offset, 2)); - offset += 2; - ushort g = TiffUtilities.ConvertToUShortLittleEndian(rowBytes.Slice(offset, 2)); - offset += 2; - ushort b = TiffUtilities.ConvertToUShortLittleEndian(rowBytes.Slice(offset, 2)); - offset += 2; - - for (int x = 1; x < width; x++) - { - Span rowSpan = rowBytes.Slice(offset, 2); - ushort deltaR = TiffUtilities.ConvertToUShortLittleEndian(rowSpan); - r += deltaR; - BinaryPrimitives.WriteUInt16LittleEndian(rowSpan, r); - offset += 2; - - rowSpan = rowBytes.Slice(offset, 2); - ushort deltaG = TiffUtilities.ConvertToUShortLittleEndian(rowSpan); - g += deltaG; - BinaryPrimitives.WriteUInt16LittleEndian(rowSpan, g); - offset += 2; - - rowSpan = rowBytes.Slice(offset, 2); - ushort deltaB = TiffUtilities.ConvertToUShortLittleEndian(rowSpan); - b += deltaB; - BinaryPrimitives.WriteUInt16LittleEndian(rowSpan, b); - offset += 2; - } + UndoRgb48BitLittleEndianRow(pixelBytes, width, y); } } } diff --git a/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs index c0d48e6942..3ef0d2998b 100644 --- a/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs @@ -94,6 +94,8 @@ public void TiffDecoder_CanDecode_Planar(TestImageProvider provi [WithFile(TiledGray16BitBigEndianDeflateCompressedWithPredictor, PixelTypes.Rgba32)] [WithFile(TiledGray32BitLittleEndianDeflateCompressedWithPredictor, PixelTypes.Rgba32)] [WithFile(TiledGray32BitBigEndianDeflateCompressedWithPredictor, PixelTypes.Rgba32)] + [WithFile(TiledRgb48BitLittleEndianDeflateCompressedWithPredictor, PixelTypes.Rgba32)] + [WithFile(TiledRgb48BitBigEndianDeflateCompressedWithPredictor, PixelTypes.Rgba32)] public void TiffDecoder_CanDecode_Tiled(TestImageProvider provider) where TPixel : unmanaged, IPixel => TestTiffDecoder(provider); diff --git a/tests/ImageSharp.Tests/TestImages.cs b/tests/ImageSharp.Tests/TestImages.cs index d0007184c8..1bd681928e 100644 --- a/tests/ImageSharp.Tests/TestImages.cs +++ b/tests/ImageSharp.Tests/TestImages.cs @@ -993,6 +993,8 @@ public static class Tiff public const string TiledGray16BitBigEndianDeflateCompressedWithPredictor = "Tiff/tiled_gray_16bit_big_endian_deflate_compressed_predictor.tiff"; public const string TiledGray32BitLittleEndianDeflateCompressedWithPredictor = "Tiff/tiled_gray_32bit_little_endian_deflate_compressed_predictor.tiff"; public const string TiledGray32BitBigEndianDeflateCompressedWithPredictor = "Tiff/tiled_gray_32bit_big_endian_deflate_compressed_predictor.tiff"; + public const string TiledRgb48BitLittleEndianDeflateCompressedWithPredictor = "Tiff/tiled_rgb_48bit_little_endian_deflate_compressed_predictor.tiff"; + public const string TiledRgb48BitBigEndianDeflateCompressedWithPredictor = "Tiff/tiled_rgb_48bit_big_endian_deflate_compressed_predictor.tiff"; // Images with alpha channel. public const string Rgba2BitUnassociatedAlpha = "Tiff/RgbaUnassociatedAlpha2bit.tiff"; diff --git a/tests/Images/Input/Tiff/tiled_rgb_48bit_big_endian_deflate_compressed_predictor.tiff b/tests/Images/Input/Tiff/tiled_rgb_48bit_big_endian_deflate_compressed_predictor.tiff new file mode 100644 index 0000000000..f6b92c92ce --- /dev/null +++ b/tests/Images/Input/Tiff/tiled_rgb_48bit_big_endian_deflate_compressed_predictor.tiff @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:0880733f8463aff1feefcc08ce21860d7fb1c8c32e19aa96143bf5679a353fba +size 201673 diff --git a/tests/Images/Input/Tiff/tiled_rgb_48bit_little_endian_deflate_compressed_predictor.tiff b/tests/Images/Input/Tiff/tiled_rgb_48bit_little_endian_deflate_compressed_predictor.tiff new file mode 100644 index 0000000000..f6b92c92ce --- /dev/null +++ b/tests/Images/Input/Tiff/tiled_rgb_48bit_little_endian_deflate_compressed_predictor.tiff @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:0880733f8463aff1feefcc08ce21860d7fb1c8c32e19aa96143bf5679a353fba +size 201673 From f804ca2e177c8eea9dfbec05a0b7cb585d413667 Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Sun, 9 Feb 2025 19:23:56 +0100 Subject: [PATCH 08/17] Add test cases for tiled tiff, deflate compressed with predictor and color type Rgba16161616 --- .../Tiff/Compression/HorizontalPredictor.cs | 173 ++++++++++-------- .../Formats/Tiff/TiffDecoderTests.cs | 2 + tests/ImageSharp.Tests/TestImages.cs | 2 + ...g_endian_deflate_compressed_predictor.tiff | 3 + ...e_endian_deflate_compressed_predictor.tiff | 3 + 5 files changed, 109 insertions(+), 74 deletions(-) create mode 100644 tests/Images/Input/Tiff/tiled_rgba_64bit_big_endian_deflate_compressed_predictor.tiff create mode 100644 tests/Images/Input/Tiff/tiled_rgba_64bit_little_endian_deflate_compressed_predictor.tiff diff --git a/src/ImageSharp/Formats/Tiff/Compression/HorizontalPredictor.cs b/src/ImageSharp/Formats/Tiff/Compression/HorizontalPredictor.cs index 16c7d9d0b4..bc3113a6c0 100644 --- a/src/ImageSharp/Formats/Tiff/Compression/HorizontalPredictor.cs +++ b/src/ImageSharp/Formats/Tiff/Compression/HorizontalPredictor.cs @@ -114,6 +114,17 @@ public static void UndoRow(Span pixelBytes, int width, int y, TiffColorTyp UndoRgb48BitLittleEndianRow(pixelBytes, width, y); } + break; + case TiffColorType.Rgba16161616: + if (isBigEndian) + { + UndoRgb64BitBigEndianRow(pixelBytes, width, y); + } + else + { + UndoRgb64BitLittleEndianRow(pixelBytes, width, y); + } + break; } } @@ -504,6 +515,92 @@ private static void UndoRgb48Bit(Span pixelBytes, int width, bool isBigEnd } } + private static void UndoRgb64BitBigEndianRow(Span pixelBytes, int width, int y) + { + int rowBytesCount = width * 8; + int offset = 0; + + Span rowBytes = pixelBytes.Slice(y * rowBytesCount, rowBytesCount); + ushort r = TiffUtilities.ConvertToUShortBigEndian(rowBytes.Slice(offset, 2)); + offset += 2; + ushort g = TiffUtilities.ConvertToUShortBigEndian(rowBytes.Slice(offset, 2)); + offset += 2; + ushort b = TiffUtilities.ConvertToUShortBigEndian(rowBytes.Slice(offset, 2)); + offset += 2; + ushort a = TiffUtilities.ConvertToUShortBigEndian(rowBytes.Slice(offset, 2)); + offset += 2; + + for (int x = 1; x < width; x++) + { + Span rowSpan = rowBytes.Slice(offset, 2); + ushort deltaR = TiffUtilities.ConvertToUShortBigEndian(rowSpan); + r += deltaR; + BinaryPrimitives.WriteUInt16BigEndian(rowSpan, r); + offset += 2; + + rowSpan = rowBytes.Slice(offset, 2); + ushort deltaG = TiffUtilities.ConvertToUShortBigEndian(rowSpan); + g += deltaG; + BinaryPrimitives.WriteUInt16BigEndian(rowSpan, g); + offset += 2; + + rowSpan = rowBytes.Slice(offset, 2); + ushort deltaB = TiffUtilities.ConvertToUShortBigEndian(rowSpan); + b += deltaB; + BinaryPrimitives.WriteUInt16BigEndian(rowSpan, b); + offset += 2; + + rowSpan = rowBytes.Slice(offset, 2); + ushort deltaA = TiffUtilities.ConvertToUShortBigEndian(rowSpan); + a += deltaA; + BinaryPrimitives.WriteUInt16BigEndian(rowSpan, a); + offset += 2; + } + } + + private static void UndoRgb64BitLittleEndianRow(Span pixelBytes, int width, int y) + { + int rowBytesCount = width * 8; + int offset = 0; + + Span rowBytes = pixelBytes.Slice(y * rowBytesCount, rowBytesCount); + ushort r = TiffUtilities.ConvertToUShortLittleEndian(rowBytes.Slice(offset, 2)); + offset += 2; + ushort g = TiffUtilities.ConvertToUShortLittleEndian(rowBytes.Slice(offset, 2)); + offset += 2; + ushort b = TiffUtilities.ConvertToUShortLittleEndian(rowBytes.Slice(offset, 2)); + offset += 2; + ushort a = TiffUtilities.ConvertToUShortLittleEndian(rowBytes.Slice(offset, 2)); + offset += 2; + + for (int x = 1; x < width; x++) + { + Span rowSpan = rowBytes.Slice(offset, 2); + ushort deltaR = TiffUtilities.ConvertToUShortLittleEndian(rowSpan); + r += deltaR; + BinaryPrimitives.WriteUInt16LittleEndian(rowSpan, r); + offset += 2; + + rowSpan = rowBytes.Slice(offset, 2); + ushort deltaG = TiffUtilities.ConvertToUShortLittleEndian(rowSpan); + g += deltaG; + BinaryPrimitives.WriteUInt16LittleEndian(rowSpan, g); + offset += 2; + + rowSpan = rowBytes.Slice(offset, 2); + ushort deltaB = TiffUtilities.ConvertToUShortLittleEndian(rowSpan); + b += deltaB; + BinaryPrimitives.WriteUInt16LittleEndian(rowSpan, b); + offset += 2; + + rowSpan = rowBytes.Slice(offset, 2); + ushort deltaA = TiffUtilities.ConvertToUShortLittleEndian(rowSpan); + a += deltaA; + BinaryPrimitives.WriteUInt16LittleEndian(rowSpan, a); + offset += 2; + } + } + private static void UndoRgba64Bit(Span pixelBytes, int width, bool isBigEndian) { int rowBytesCount = width * 8; @@ -512,86 +609,14 @@ private static void UndoRgba64Bit(Span pixelBytes, int width, bool isBigEn { for (int y = 0; y < height; y++) { - int offset = 0; - Span rowBytes = pixelBytes.Slice(y * rowBytesCount, rowBytesCount); - ushort r = TiffUtilities.ConvertToUShortBigEndian(rowBytes.Slice(offset, 2)); - offset += 2; - ushort g = TiffUtilities.ConvertToUShortBigEndian(rowBytes.Slice(offset, 2)); - offset += 2; - ushort b = TiffUtilities.ConvertToUShortBigEndian(rowBytes.Slice(offset, 2)); - offset += 2; - ushort a = TiffUtilities.ConvertToUShortBigEndian(rowBytes.Slice(offset, 2)); - offset += 2; - - for (int x = 1; x < width; x++) - { - Span rowSpan = rowBytes.Slice(offset, 2); - ushort deltaR = TiffUtilities.ConvertToUShortBigEndian(rowSpan); - r += deltaR; - BinaryPrimitives.WriteUInt16BigEndian(rowSpan, r); - offset += 2; - - rowSpan = rowBytes.Slice(offset, 2); - ushort deltaG = TiffUtilities.ConvertToUShortBigEndian(rowSpan); - g += deltaG; - BinaryPrimitives.WriteUInt16BigEndian(rowSpan, g); - offset += 2; - - rowSpan = rowBytes.Slice(offset, 2); - ushort deltaB = TiffUtilities.ConvertToUShortBigEndian(rowSpan); - b += deltaB; - BinaryPrimitives.WriteUInt16BigEndian(rowSpan, b); - offset += 2; - - rowSpan = rowBytes.Slice(offset, 2); - ushort deltaA = TiffUtilities.ConvertToUShortBigEndian(rowSpan); - a += deltaA; - BinaryPrimitives.WriteUInt16BigEndian(rowSpan, a); - offset += 2; - } + UndoRgb64BitBigEndianRow(pixelBytes, width, y); } } else { for (int y = 0; y < height; y++) { - int offset = 0; - Span rowBytes = pixelBytes.Slice(y * rowBytesCount, rowBytesCount); - ushort r = TiffUtilities.ConvertToUShortLittleEndian(rowBytes.Slice(offset, 2)); - offset += 2; - ushort g = TiffUtilities.ConvertToUShortLittleEndian(rowBytes.Slice(offset, 2)); - offset += 2; - ushort b = TiffUtilities.ConvertToUShortLittleEndian(rowBytes.Slice(offset, 2)); - offset += 2; - ushort a = TiffUtilities.ConvertToUShortLittleEndian(rowBytes.Slice(offset, 2)); - offset += 2; - - for (int x = 1; x < width; x++) - { - Span rowSpan = rowBytes.Slice(offset, 2); - ushort deltaR = TiffUtilities.ConvertToUShortLittleEndian(rowSpan); - r += deltaR; - BinaryPrimitives.WriteUInt16LittleEndian(rowSpan, r); - offset += 2; - - rowSpan = rowBytes.Slice(offset, 2); - ushort deltaG = TiffUtilities.ConvertToUShortLittleEndian(rowSpan); - g += deltaG; - BinaryPrimitives.WriteUInt16LittleEndian(rowSpan, g); - offset += 2; - - rowSpan = rowBytes.Slice(offset, 2); - ushort deltaB = TiffUtilities.ConvertToUShortLittleEndian(rowSpan); - b += deltaB; - BinaryPrimitives.WriteUInt16LittleEndian(rowSpan, b); - offset += 2; - - rowSpan = rowBytes.Slice(offset, 2); - ushort deltaA = TiffUtilities.ConvertToUShortLittleEndian(rowSpan); - a += deltaA; - BinaryPrimitives.WriteUInt16LittleEndian(rowSpan, a); - offset += 2; - } + UndoRgb64BitLittleEndianRow(pixelBytes, width, y); } } } diff --git a/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs index 3ef0d2998b..9f77843133 100644 --- a/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs @@ -96,6 +96,8 @@ public void TiffDecoder_CanDecode_Planar(TestImageProvider provi [WithFile(TiledGray32BitBigEndianDeflateCompressedWithPredictor, PixelTypes.Rgba32)] [WithFile(TiledRgb48BitLittleEndianDeflateCompressedWithPredictor, PixelTypes.Rgba32)] [WithFile(TiledRgb48BitBigEndianDeflateCompressedWithPredictor, PixelTypes.Rgba32)] + [WithFile(TiledRgba64BitLittleEndianDeflateCompressedWithPredictor, PixelTypes.Rgba32)] + [WithFile(TiledRgba64BitBigEndianDeflateCompressedWithPredictor, PixelTypes.Rgba32)] public void TiffDecoder_CanDecode_Tiled(TestImageProvider provider) where TPixel : unmanaged, IPixel => TestTiffDecoder(provider); diff --git a/tests/ImageSharp.Tests/TestImages.cs b/tests/ImageSharp.Tests/TestImages.cs index 1bd681928e..1c89cd9e2c 100644 --- a/tests/ImageSharp.Tests/TestImages.cs +++ b/tests/ImageSharp.Tests/TestImages.cs @@ -995,6 +995,8 @@ public static class Tiff public const string TiledGray32BitBigEndianDeflateCompressedWithPredictor = "Tiff/tiled_gray_32bit_big_endian_deflate_compressed_predictor.tiff"; public const string TiledRgb48BitLittleEndianDeflateCompressedWithPredictor = "Tiff/tiled_rgb_48bit_little_endian_deflate_compressed_predictor.tiff"; public const string TiledRgb48BitBigEndianDeflateCompressedWithPredictor = "Tiff/tiled_rgb_48bit_big_endian_deflate_compressed_predictor.tiff"; + public const string TiledRgba64BitLittleEndianDeflateCompressedWithPredictor = "Tiff/tiled_rgba_64bit_little_endian_deflate_compressed_predictor.tiff"; + public const string TiledRgba64BitBigEndianDeflateCompressedWithPredictor = "Tiff/tiled_rgba_64bit_big_endian_deflate_compressed_predictor.tiff"; // Images with alpha channel. public const string Rgba2BitUnassociatedAlpha = "Tiff/RgbaUnassociatedAlpha2bit.tiff"; diff --git a/tests/Images/Input/Tiff/tiled_rgba_64bit_big_endian_deflate_compressed_predictor.tiff b/tests/Images/Input/Tiff/tiled_rgba_64bit_big_endian_deflate_compressed_predictor.tiff new file mode 100644 index 0000000000..0def244601 --- /dev/null +++ b/tests/Images/Input/Tiff/tiled_rgba_64bit_big_endian_deflate_compressed_predictor.tiff @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f456272c6948159ea17d6fa7d2a89e30521c1d4e29f0ad0b1a79894f122d2153 +size 220119 diff --git a/tests/Images/Input/Tiff/tiled_rgba_64bit_little_endian_deflate_compressed_predictor.tiff b/tests/Images/Input/Tiff/tiled_rgba_64bit_little_endian_deflate_compressed_predictor.tiff new file mode 100644 index 0000000000..bcd96a88bb --- /dev/null +++ b/tests/Images/Input/Tiff/tiled_rgba_64bit_little_endian_deflate_compressed_predictor.tiff @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ee63d8b0d63fd091390678a4a2600df5c14a122002a4d9c93e7d01082a2ee347 +size 220045 From dacb713de390e107b8639e688b8941e1f912877f Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Mon, 10 Feb 2025 19:14:56 +0100 Subject: [PATCH 09/17] Add test cases for tiled tiff, deflate compressed with predictor and color type Rgb323232 --- .../Tiff/Compression/HorizontalPredictor.cs | 148 +++++++++++------- .../Formats/Tiff/TiffDecoderTests.cs | 2 + tests/ImageSharp.Tests/TestImages.cs | 2 + ...g_endian_deflate_compressed_predictor.tiff | 3 + ...e_endian_deflate_compressed_predictor.tiff | 3 + 5 files changed, 100 insertions(+), 58 deletions(-) create mode 100644 tests/Images/Input/Tiff/tiled_rgb_96bit_big_endian_deflate_compressed_predictor.tiff create mode 100644 tests/Images/Input/Tiff/tiled_rgb_96bit_little_endian_deflate_compressed_predictor.tiff diff --git a/src/ImageSharp/Formats/Tiff/Compression/HorizontalPredictor.cs b/src/ImageSharp/Formats/Tiff/Compression/HorizontalPredictor.cs index bc3113a6c0..a2b28e6f77 100644 --- a/src/ImageSharp/Formats/Tiff/Compression/HorizontalPredictor.cs +++ b/src/ImageSharp/Formats/Tiff/Compression/HorizontalPredictor.cs @@ -72,6 +72,7 @@ public static void UndoRow(Span pixelBytes, int width, int y, TiffColorTyp case TiffColorType.PaletteColor: UndoGray8BitRow(pixelBytes, width, y); break; + case TiffColorType.BlackIsZero16: case TiffColorType.WhiteIsZero16: if (isBigEndian) @@ -84,6 +85,7 @@ public static void UndoRow(Span pixelBytes, int width, int y, TiffColorTyp } break; + case TiffColorType.BlackIsZero32: case TiffColorType.WhiteIsZero32: if (isBigEndian) @@ -96,14 +98,17 @@ public static void UndoRow(Span pixelBytes, int width, int y, TiffColorTyp } break; + case TiffColorType.Rgb888: case TiffColorType.CieLab: UndoRgb24BitRow(pixelBytes, width, y); break; + case TiffColorType.Rgba8888: case TiffColorType.Cmyk: UndoRgba32BitRow(pixelBytes, width, y); break; + case TiffColorType.Rgb161616: if (isBigEndian) { @@ -115,6 +120,7 @@ public static void UndoRow(Span pixelBytes, int width, int y, TiffColorTyp } break; + case TiffColorType.Rgba16161616: if (isBigEndian) { @@ -125,6 +131,18 @@ public static void UndoRow(Span pixelBytes, int width, int y, TiffColorTyp UndoRgb64BitLittleEndianRow(pixelBytes, width, y); } + break; + + case TiffColorType.Rgb323232: + if (isBigEndian) + { + UndoRgb96BitBigEndianRow(pixelBytes, width, y); + } + else + { + UndoRgb96BitLittleEndianRow(pixelBytes, width, y); + } + break; } } @@ -621,6 +639,76 @@ private static void UndoRgba64Bit(Span pixelBytes, int width, bool isBigEn } } + private static void UndoRgb96BitBigEndianRow(Span pixelBytes, int width, int y) + { + int rowBytesCount = width * 12; + + int offset = 0; + Span rowBytes = pixelBytes.Slice(y * rowBytesCount, rowBytesCount); + uint r = TiffUtilities.ConvertToUIntBigEndian(rowBytes.Slice(offset, 4)); + offset += 4; + uint g = TiffUtilities.ConvertToUIntBigEndian(rowBytes.Slice(offset, 4)); + offset += 4; + uint b = TiffUtilities.ConvertToUIntBigEndian(rowBytes.Slice(offset, 4)); + offset += 4; + + for (int x = 1; x < width; x++) + { + Span rowSpan = rowBytes.Slice(offset, 4); + uint deltaR = TiffUtilities.ConvertToUIntBigEndian(rowSpan); + r += deltaR; + BinaryPrimitives.WriteUInt32BigEndian(rowSpan, r); + offset += 4; + + rowSpan = rowBytes.Slice(offset, 4); + uint deltaG = TiffUtilities.ConvertToUIntBigEndian(rowSpan); + g += deltaG; + BinaryPrimitives.WriteUInt32BigEndian(rowSpan, g); + offset += 4; + + rowSpan = rowBytes.Slice(offset, 4); + uint deltaB = TiffUtilities.ConvertToUIntBigEndian(rowSpan); + b += deltaB; + BinaryPrimitives.WriteUInt32BigEndian(rowSpan, b); + offset += 4; + } + } + + private static void UndoRgb96BitLittleEndianRow(Span pixelBytes, int width, int y) + { + int rowBytesCount = width * 12; + + int offset = 0; + Span rowBytes = pixelBytes.Slice(y * rowBytesCount, rowBytesCount); + uint r = TiffUtilities.ConvertToUIntLittleEndian(rowBytes.Slice(offset, 4)); + offset += 4; + uint g = TiffUtilities.ConvertToUIntLittleEndian(rowBytes.Slice(offset, 4)); + offset += 4; + uint b = TiffUtilities.ConvertToUIntLittleEndian(rowBytes.Slice(offset, 4)); + offset += 4; + + for (int x = 1; x < width; x++) + { + Span rowSpan = rowBytes.Slice(offset, 4); + uint deltaR = TiffUtilities.ConvertToUIntLittleEndian(rowSpan); + r += deltaR; + BinaryPrimitives.WriteUInt32LittleEndian(rowSpan, r); + offset += 4; + + rowSpan = rowBytes.Slice(offset, 4); + uint deltaG = TiffUtilities.ConvertToUIntLittleEndian(rowSpan); + g += deltaG; + BinaryPrimitives.WriteUInt32LittleEndian(rowSpan, g); + offset += 4; + + rowSpan = rowBytes.Slice(offset, 4); + uint deltaB = TiffUtilities.ConvertToUIntLittleEndian(rowSpan); + b += deltaB; + BinaryPrimitives.WriteUInt32LittleEndian(rowSpan, b); + offset += 4; + } + } + private static void UndoRgb96Bit(Span pixelBytes, int width, bool isBigEndian) { int rowBytesCount = width * 12; @@ -629,70 +717,14 @@ private static void UndoRgb96Bit(Span pixelBytes, int width, bool isBigEnd { for (int y = 0; y < height; y++) { - int offset = 0; - Span rowBytes = pixelBytes.Slice(y * rowBytesCount, rowBytesCount); - uint r = TiffUtilities.ConvertToUIntBigEndian(rowBytes.Slice(offset, 4)); - offset += 4; - uint g = TiffUtilities.ConvertToUIntBigEndian(rowBytes.Slice(offset, 4)); - offset += 4; - uint b = TiffUtilities.ConvertToUIntBigEndian(rowBytes.Slice(offset, 4)); - offset += 4; - - for (int x = 1; x < width; x++) - { - Span rowSpan = rowBytes.Slice(offset, 4); - uint deltaR = TiffUtilities.ConvertToUIntBigEndian(rowSpan); - r += deltaR; - BinaryPrimitives.WriteUInt32BigEndian(rowSpan, r); - offset += 4; - - rowSpan = rowBytes.Slice(offset, 4); - uint deltaG = TiffUtilities.ConvertToUIntBigEndian(rowSpan); - g += deltaG; - BinaryPrimitives.WriteUInt32BigEndian(rowSpan, g); - offset += 4; - - rowSpan = rowBytes.Slice(offset, 4); - uint deltaB = TiffUtilities.ConvertToUIntBigEndian(rowSpan); - b += deltaB; - BinaryPrimitives.WriteUInt32BigEndian(rowSpan, b); - offset += 4; - } + UndoRgb96BitBigEndianRow(pixelBytes, width, y); } } else { for (int y = 0; y < height; y++) { - int offset = 0; - Span rowBytes = pixelBytes.Slice(y * rowBytesCount, rowBytesCount); - uint r = TiffUtilities.ConvertToUIntLittleEndian(rowBytes.Slice(offset, 4)); - offset += 4; - uint g = TiffUtilities.ConvertToUIntLittleEndian(rowBytes.Slice(offset, 4)); - offset += 4; - uint b = TiffUtilities.ConvertToUIntLittleEndian(rowBytes.Slice(offset, 4)); - offset += 4; - - for (int x = 1; x < width; x++) - { - Span rowSpan = rowBytes.Slice(offset, 4); - uint deltaR = TiffUtilities.ConvertToUIntLittleEndian(rowSpan); - r += deltaR; - BinaryPrimitives.WriteUInt32LittleEndian(rowSpan, r); - offset += 4; - - rowSpan = rowBytes.Slice(offset, 4); - uint deltaG = TiffUtilities.ConvertToUIntLittleEndian(rowSpan); - g += deltaG; - BinaryPrimitives.WriteUInt32LittleEndian(rowSpan, g); - offset += 4; - - rowSpan = rowBytes.Slice(offset, 4); - uint deltaB = TiffUtilities.ConvertToUIntLittleEndian(rowSpan); - b += deltaB; - BinaryPrimitives.WriteUInt32LittleEndian(rowSpan, b); - offset += 4; - } + UndoRgb96BitLittleEndianRow(pixelBytes, width, y); } } } diff --git a/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs index 9f77843133..2ca081eff5 100644 --- a/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs @@ -98,6 +98,8 @@ public void TiffDecoder_CanDecode_Planar(TestImageProvider provi [WithFile(TiledRgb48BitBigEndianDeflateCompressedWithPredictor, PixelTypes.Rgba32)] [WithFile(TiledRgba64BitLittleEndianDeflateCompressedWithPredictor, PixelTypes.Rgba32)] [WithFile(TiledRgba64BitBigEndianDeflateCompressedWithPredictor, PixelTypes.Rgba32)] + [WithFile(TiledRgb96BitLittleEndianDeflateCompressedWithPredictor, PixelTypes.Rgba32)] + [WithFile(TiledRgb96BitBigEndianDeflateCompressedWithPredictor, PixelTypes.Rgba32)] public void TiffDecoder_CanDecode_Tiled(TestImageProvider provider) where TPixel : unmanaged, IPixel => TestTiffDecoder(provider); diff --git a/tests/ImageSharp.Tests/TestImages.cs b/tests/ImageSharp.Tests/TestImages.cs index 1c89cd9e2c..51a56e152d 100644 --- a/tests/ImageSharp.Tests/TestImages.cs +++ b/tests/ImageSharp.Tests/TestImages.cs @@ -997,6 +997,8 @@ public static class Tiff public const string TiledRgb48BitBigEndianDeflateCompressedWithPredictor = "Tiff/tiled_rgb_48bit_big_endian_deflate_compressed_predictor.tiff"; public const string TiledRgba64BitLittleEndianDeflateCompressedWithPredictor = "Tiff/tiled_rgba_64bit_little_endian_deflate_compressed_predictor.tiff"; public const string TiledRgba64BitBigEndianDeflateCompressedWithPredictor = "Tiff/tiled_rgba_64bit_big_endian_deflate_compressed_predictor.tiff"; + public const string TiledRgb96BitLittleEndianDeflateCompressedWithPredictor = "Tiff/tiled_rgb_96bit_little_endian_deflate_compressed_predictor.tiff"; + public const string TiledRgb96BitBigEndianDeflateCompressedWithPredictor = "Tiff/tiled_rgb_96bit_big_endian_deflate_compressed_predictor.tiff"; // Images with alpha channel. public const string Rgba2BitUnassociatedAlpha = "Tiff/RgbaUnassociatedAlpha2bit.tiff"; diff --git a/tests/Images/Input/Tiff/tiled_rgb_96bit_big_endian_deflate_compressed_predictor.tiff b/tests/Images/Input/Tiff/tiled_rgb_96bit_big_endian_deflate_compressed_predictor.tiff new file mode 100644 index 0000000000..34090a9e9b --- /dev/null +++ b/tests/Images/Input/Tiff/tiled_rgb_96bit_big_endian_deflate_compressed_predictor.tiff @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:67014dc658ced8b9f2a091f6b4e446d19babec2fb7b4bc14f010e570708d4d57 +size 209979 diff --git a/tests/Images/Input/Tiff/tiled_rgb_96bit_little_endian_deflate_compressed_predictor.tiff b/tests/Images/Input/Tiff/tiled_rgb_96bit_little_endian_deflate_compressed_predictor.tiff new file mode 100644 index 0000000000..1a85de4ba4 --- /dev/null +++ b/tests/Images/Input/Tiff/tiled_rgb_96bit_little_endian_deflate_compressed_predictor.tiff @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:535c6bc0231ef2510076bb7362412e337d9df4fc5564dc80a67a48a69ce304a9 +size 210047 From dec1dc1c6b36c364c44967b12919bbe320ac2bc3 Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Tue, 11 Feb 2025 19:17:27 +0100 Subject: [PATCH 10/17] Add test cases for tiled tiff, deflate compressed with predictor and color type Rgba with 32 bit for each channel --- .../Tiff/Compression/HorizontalPredictor.cs | 185 +++++++++++------- .../Formats/Tiff/TiffDecoderTests.cs | 6 +- tests/ImageSharp.Tests/TestImages.cs | 2 + ...g_endian_deflate_compressed_predictor.tiff | 3 + ...e_endian_deflate_compressed_predictor.tiff | 3 + 5 files changed, 122 insertions(+), 77 deletions(-) create mode 100644 tests/Images/Input/Tiff/tiled_rgba_128bit_big_endian_deflate_compressed_predictor.tiff create mode 100644 tests/Images/Input/Tiff/tiled_rgba_128bit_little_endian_deflate_compressed_predictor.tiff diff --git a/src/ImageSharp/Formats/Tiff/Compression/HorizontalPredictor.cs b/src/ImageSharp/Formats/Tiff/Compression/HorizontalPredictor.cs index a2b28e6f77..c7f25f1185 100644 --- a/src/ImageSharp/Formats/Tiff/Compression/HorizontalPredictor.cs +++ b/src/ImageSharp/Formats/Tiff/Compression/HorizontalPredictor.cs @@ -16,7 +16,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Compression; internal static class HorizontalPredictor { /// - /// Inverts the horizontal prediction. + /// Inverts the horizontal predictor. /// /// Buffer with decompressed pixel data. /// The width of the image or strip. @@ -62,9 +62,16 @@ public static void Undo(Span pixelBytes, int width, TiffColorType colorTyp } } + /// + /// Inverts the horizontal predictor for one row. + /// + /// Buffer with decompressed pixel data. + /// The width in pixels of the row. + /// The row index. + /// 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 UndoRow(Span pixelBytes, int width, int y, TiffColorType colorType, bool isBigEndian) { - // TODO: Implement missing colortypes, see above. switch (colorType) { case TiffColorType.BlackIsZero8: @@ -143,6 +150,18 @@ public static void UndoRow(Span pixelBytes, int width, int y, TiffColorTyp UndoRgb96BitLittleEndianRow(pixelBytes, width, y); } + break; + + case TiffColorType.Rgba32323232: + if (isBigEndian) + { + UndoRgba128BitBigEndianRow(pixelBytes, width, y); + } + else + { + UndoRgba128BitLittleEndianRow(pixelBytes, width, y); + } + break; } } @@ -729,6 +748,92 @@ private static void UndoRgb96Bit(Span pixelBytes, int width, bool isBigEnd } } + private static void UndoRgba128BitBigEndianRow(Span pixelBytes, int width, int y) + { + int rowBytesCount = width * 16; + + int offset = 0; + Span rowBytes = pixelBytes.Slice(y * rowBytesCount, rowBytesCount); + uint r = TiffUtilities.ConvertToUIntBigEndian(rowBytes.Slice(offset, 4)); + offset += 4; + uint g = TiffUtilities.ConvertToUIntBigEndian(rowBytes.Slice(offset, 4)); + offset += 4; + uint b = TiffUtilities.ConvertToUIntBigEndian(rowBytes.Slice(offset, 4)); + offset += 4; + uint a = TiffUtilities.ConvertToUIntBigEndian(rowBytes.Slice(offset, 4)); + offset += 4; + + for (int x = 1; x < width; x++) + { + Span rowSpan = rowBytes.Slice(offset, 4); + uint deltaR = TiffUtilities.ConvertToUIntBigEndian(rowSpan); + r += deltaR; + BinaryPrimitives.WriteUInt32BigEndian(rowSpan, r); + offset += 4; + + rowSpan = rowBytes.Slice(offset, 4); + uint deltaG = TiffUtilities.ConvertToUIntBigEndian(rowSpan); + g += deltaG; + BinaryPrimitives.WriteUInt32BigEndian(rowSpan, g); + offset += 4; + + rowSpan = rowBytes.Slice(offset, 4); + uint deltaB = TiffUtilities.ConvertToUIntBigEndian(rowSpan); + b += deltaB; + BinaryPrimitives.WriteUInt32BigEndian(rowSpan, b); + offset += 4; + + rowSpan = rowBytes.Slice(offset, 4); + uint deltaA = TiffUtilities.ConvertToUIntBigEndian(rowSpan); + a += deltaA; + BinaryPrimitives.WriteUInt32BigEndian(rowSpan, a); + offset += 4; + } + } + + private static void UndoRgba128BitLittleEndianRow(Span pixelBytes, int width, int y) + { + int rowBytesCount = width * 16; + + int offset = 0; + Span rowBytes = pixelBytes.Slice(y * rowBytesCount, rowBytesCount); + uint r = TiffUtilities.ConvertToUIntLittleEndian(rowBytes.Slice(offset, 4)); + offset += 4; + uint g = TiffUtilities.ConvertToUIntLittleEndian(rowBytes.Slice(offset, 4)); + offset += 4; + uint b = TiffUtilities.ConvertToUIntLittleEndian(rowBytes.Slice(offset, 4)); + offset += 4; + uint a = TiffUtilities.ConvertToUIntLittleEndian(rowBytes.Slice(offset, 4)); + offset += 4; + + for (int x = 1; x < width; x++) + { + Span rowSpan = rowBytes.Slice(offset, 4); + uint deltaR = TiffUtilities.ConvertToUIntLittleEndian(rowSpan); + r += deltaR; + BinaryPrimitives.WriteUInt32LittleEndian(rowSpan, r); + offset += 4; + + rowSpan = rowBytes.Slice(offset, 4); + uint deltaG = TiffUtilities.ConvertToUIntLittleEndian(rowSpan); + g += deltaG; + BinaryPrimitives.WriteUInt32LittleEndian(rowSpan, g); + offset += 4; + + rowSpan = rowBytes.Slice(offset, 4); + uint deltaB = TiffUtilities.ConvertToUIntLittleEndian(rowSpan); + b += deltaB; + BinaryPrimitives.WriteUInt32LittleEndian(rowSpan, b); + offset += 4; + + rowSpan = rowBytes.Slice(offset, 4); + uint deltaA = TiffUtilities.ConvertToUIntLittleEndian(rowSpan); + a += deltaA; + BinaryPrimitives.WriteUInt32LittleEndian(rowSpan, a); + offset += 4; + } + } + private static void UndoRgba128Bit(Span pixelBytes, int width, bool isBigEndian) { int rowBytesCount = width * 16; @@ -737,86 +842,14 @@ private static void UndoRgba128Bit(Span pixelBytes, int width, bool isBigE { for (int y = 0; y < height; y++) { - int offset = 0; - Span rowBytes = pixelBytes.Slice(y * rowBytesCount, rowBytesCount); - uint r = TiffUtilities.ConvertToUIntBigEndian(rowBytes.Slice(offset, 4)); - offset += 4; - uint g = TiffUtilities.ConvertToUIntBigEndian(rowBytes.Slice(offset, 4)); - offset += 4; - uint b = TiffUtilities.ConvertToUIntBigEndian(rowBytes.Slice(offset, 4)); - offset += 4; - uint a = TiffUtilities.ConvertToUIntBigEndian(rowBytes.Slice(offset, 4)); - offset += 4; - - for (int x = 1; x < width; x++) - { - Span rowSpan = rowBytes.Slice(offset, 4); - uint deltaR = TiffUtilities.ConvertToUIntBigEndian(rowSpan); - r += deltaR; - BinaryPrimitives.WriteUInt32BigEndian(rowSpan, r); - offset += 4; - - rowSpan = rowBytes.Slice(offset, 4); - uint deltaG = TiffUtilities.ConvertToUIntBigEndian(rowSpan); - g += deltaG; - BinaryPrimitives.WriteUInt32BigEndian(rowSpan, g); - offset += 4; - - rowSpan = rowBytes.Slice(offset, 4); - uint deltaB = TiffUtilities.ConvertToUIntBigEndian(rowSpan); - b += deltaB; - BinaryPrimitives.WriteUInt32BigEndian(rowSpan, b); - offset += 4; - - rowSpan = rowBytes.Slice(offset, 4); - uint deltaA = TiffUtilities.ConvertToUIntBigEndian(rowSpan); - a += deltaA; - BinaryPrimitives.WriteUInt32BigEndian(rowSpan, a); - offset += 4; - } + UndoRgba128BitBigEndianRow(pixelBytes, width, y); } } else { for (int y = 0; y < height; y++) { - int offset = 0; - Span rowBytes = pixelBytes.Slice(y * rowBytesCount, rowBytesCount); - uint r = TiffUtilities.ConvertToUIntLittleEndian(rowBytes.Slice(offset, 4)); - offset += 4; - uint g = TiffUtilities.ConvertToUIntLittleEndian(rowBytes.Slice(offset, 4)); - offset += 4; - uint b = TiffUtilities.ConvertToUIntLittleEndian(rowBytes.Slice(offset, 4)); - offset += 4; - uint a = TiffUtilities.ConvertToUIntLittleEndian(rowBytes.Slice(offset, 4)); - offset += 4; - - for (int x = 1; x < width; x++) - { - Span rowSpan = rowBytes.Slice(offset, 4); - uint deltaR = TiffUtilities.ConvertToUIntLittleEndian(rowSpan); - r += deltaR; - BinaryPrimitives.WriteUInt32LittleEndian(rowSpan, r); - offset += 4; - - rowSpan = rowBytes.Slice(offset, 4); - uint deltaG = TiffUtilities.ConvertToUIntLittleEndian(rowSpan); - g += deltaG; - BinaryPrimitives.WriteUInt32LittleEndian(rowSpan, g); - offset += 4; - - rowSpan = rowBytes.Slice(offset, 4); - uint deltaB = TiffUtilities.ConvertToUIntLittleEndian(rowSpan); - b += deltaB; - BinaryPrimitives.WriteUInt32LittleEndian(rowSpan, b); - offset += 4; - - rowSpan = rowBytes.Slice(offset, 4); - uint deltaA = TiffUtilities.ConvertToUIntLittleEndian(rowSpan); - a += deltaA; - BinaryPrimitives.WriteUInt32LittleEndian(rowSpan, a); - offset += 4; - } + UndoRgba128BitLittleEndianRow(pixelBytes, width, y); } } } diff --git a/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs index 2ca081eff5..16d3ade0ef 100644 --- a/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs @@ -87,6 +87,10 @@ public void TiffDecoder_CanDecode_Planar(TestImageProvider provi [WithFile(QuadTile, PixelTypes.Rgba32)] [WithFile(TiledChunky, PixelTypes.Rgba32)] [WithFile(TiledPlanar, PixelTypes.Rgba32)] + public void TiffDecoder_CanDecode_Tiled(TestImageProvider provider) + where TPixel : unmanaged, IPixel => TestTiffDecoder(provider); + + [Theory] [WithFile(TiledRgbaDeflateCompressedWithPredictor, PixelTypes.Rgba32)] [WithFile(TiledRgbDeflateCompressedWithPredictor, PixelTypes.Rgba32)] [WithFile(TiledGrayDeflateCompressedWithPredictor, PixelTypes.Rgba32)] @@ -100,7 +104,7 @@ public void TiffDecoder_CanDecode_Planar(TestImageProvider provi [WithFile(TiledRgba64BitBigEndianDeflateCompressedWithPredictor, PixelTypes.Rgba32)] [WithFile(TiledRgb96BitLittleEndianDeflateCompressedWithPredictor, PixelTypes.Rgba32)] [WithFile(TiledRgb96BitBigEndianDeflateCompressedWithPredictor, PixelTypes.Rgba32)] - public void TiffDecoder_CanDecode_Tiled(TestImageProvider provider) + public void TiffDecoder_CanDecode_Tiled_Deflate_Compressed(TestImageProvider provider) where TPixel : unmanaged, IPixel => TestTiffDecoder(provider); [Theory] diff --git a/tests/ImageSharp.Tests/TestImages.cs b/tests/ImageSharp.Tests/TestImages.cs index 51a56e152d..c65f9ba5e9 100644 --- a/tests/ImageSharp.Tests/TestImages.cs +++ b/tests/ImageSharp.Tests/TestImages.cs @@ -999,6 +999,8 @@ public static class Tiff public const string TiledRgba64BitBigEndianDeflateCompressedWithPredictor = "Tiff/tiled_rgba_64bit_big_endian_deflate_compressed_predictor.tiff"; public const string TiledRgb96BitLittleEndianDeflateCompressedWithPredictor = "Tiff/tiled_rgb_96bit_little_endian_deflate_compressed_predictor.tiff"; 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"; // Images with alpha channel. public const string Rgba2BitUnassociatedAlpha = "Tiff/RgbaUnassociatedAlpha2bit.tiff"; diff --git a/tests/Images/Input/Tiff/tiled_rgba_128bit_big_endian_deflate_compressed_predictor.tiff b/tests/Images/Input/Tiff/tiled_rgba_128bit_big_endian_deflate_compressed_predictor.tiff new file mode 100644 index 0000000000..27055256ed --- /dev/null +++ b/tests/Images/Input/Tiff/tiled_rgba_128bit_big_endian_deflate_compressed_predictor.tiff @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2d3f46e8555f014ef3a7b848c7e2e88645913c01fc70b6aeb215e9a2385a635f +size 239355 diff --git a/tests/Images/Input/Tiff/tiled_rgba_128bit_little_endian_deflate_compressed_predictor.tiff b/tests/Images/Input/Tiff/tiled_rgba_128bit_little_endian_deflate_compressed_predictor.tiff new file mode 100644 index 0000000000..b29d10c826 --- /dev/null +++ b/tests/Images/Input/Tiff/tiled_rgba_128bit_little_endian_deflate_compressed_predictor.tiff @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:39029aaf35c923c2136e35b9fd5fae1e9c9178791e47714b8f26cb53a0091608 +size 239441 From 71f7d86900efb39b3dbe94836296918e8d1295c8 Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Wed, 19 Feb 2025 19:32:57 +0100 Subject: [PATCH 11/17] Add method UndoTile in HorizontalPredictor --- .../Decompressors/DeflateTiffCompression.cs | 17 ++++++++++++++--- .../Tiff/Compression/HorizontalPredictor.cs | 8 ++++++++ .../Compression/TiffDecompressorsFactory.cs | 6 +++--- src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs | 8 ++++---- .../Compression/DeflateTiffCompressionTests.cs | 2 +- 5 files changed, 30 insertions(+), 11 deletions(-) diff --git a/src/ImageSharp/Formats/Tiff/Compression/Decompressors/DeflateTiffCompression.cs b/src/ImageSharp/Formats/Tiff/Compression/Decompressors/DeflateTiffCompression.cs index 3e874b7d23..12aadbea6e 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 @@ protected override void Decompress(BufferedReadStream stream, int byteCount, int } // 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 c7f25f1185..e15584f3fd 100644 --- a/src/ImageSharp/Formats/Tiff/Compression/HorizontalPredictor.cs +++ b/src/ImageSharp/Formats/Tiff/Compression/HorizontalPredictor.cs @@ -62,6 +62,14 @@ public static void Undo(Span pixelBytes, int width, TiffColorType colorTyp } } + 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 c05d14dc6c..3274f5729c 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 @@ public static TiffBaseDecompressor Create( uint oldJpegStartOfImageMarker, TiffFillOrder fillOrder, ByteOrder byteOrder, - bool isTiled = false) + bool isTiled = false, + int tileWidth = 0) { switch (method) { @@ -41,7 +41,7 @@ public static TiffBaseDecompressor Create( 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 20f0dcba63..c642f6734d 100644 --- a/src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs +++ b/src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs @@ -679,8 +679,7 @@ private void DecodeTilesChunky( 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 @@ private TiffBasePlanarColorDecoder CreatePlanarColorDecoder() 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 @@ private TiffBaseDecompressor CreateDecompressor(int frameWidth, int bits 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 b0ca4699e5..3db142d6d5 100644 --- a/tests/ImageSharp.Tests/Formats/Tiff/Compression/DeflateTiffCompressionTests.cs +++ b/tests/ImageSharp.Tests/Formats/Tiff/Compression/DeflateTiffCompressionTests.cs @@ -23,7 +23,7 @@ public void Compress_Decompress_Roundtrip_Works(byte[] data) 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); From 5cfa2bc6435c551cc47f36c62cd200c3030b857a Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Wed, 19 Feb 2025 21:07:22 +0100 Subject: [PATCH 12/17] Enable 32 bits per channel decoding for MagickReferenceDecoder --- .../TestUtilities/ReferenceCodecs/MagickReferenceDecoder.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/MagickReferenceDecoder.cs b/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/MagickReferenceDecoder.cs index 74015a4eff..57813f66ac 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/MagickReferenceDecoder.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/MagickReferenceDecoder.cs @@ -79,7 +79,7 @@ protected override Image Decode(DecoderOptions options, Stream s FromRgba32Bytes(configuration, data, framePixels); } - else if (magicFrame.Depth is 16 or 14) + else if (magicFrame.Depth is 14 or 16 or 32) { if (this.imageFormat is PngFormat png) { From 0a52ee7514d114299752a8255084681ba23018a8 Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Thu, 20 Feb 2025 17:49:12 +0100 Subject: [PATCH 13/17] Try fix build issue with ubuntu latest and net9.0 --- tests/ImageSharp.Tests/Formats/WebP/WebpCommonUtilsTests.cs | 4 ++-- tests/ImageSharp.Tests/Image/ImageFrameTests.cs | 2 +- tests/ImageSharp.Tests/Image/ImageTests.cs | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/ImageSharp.Tests/Formats/WebP/WebpCommonUtilsTests.cs b/tests/ImageSharp.Tests/Formats/WebP/WebpCommonUtilsTests.cs index a3fe028db5..80302db393 100644 --- a/tests/ImageSharp.Tests/Formats/WebP/WebpCommonUtilsTests.cs +++ b/tests/ImageSharp.Tests/Formats/WebP/WebpCommonUtilsTests.cs @@ -106,7 +106,7 @@ private static void RunCheckNoneOpaqueWithNoneOpaquePixelsTest() 174, 183, 189, 255, 148, 158, 158, 255, }; - Span row = MemoryMarshal.Cast(rowBytes); + Span row = MemoryMarshal.Cast((Span)rowBytes); bool noneOpaque; for (int length = 8; length < row.Length; length += 8) @@ -188,7 +188,7 @@ private static void RunCheckNoneOpaqueWithOpaquePixelsTest() 174, 183, 189, 255, 148, 158, 158, 255, }; - Span row = MemoryMarshal.Cast(rowBytes); + Span row = MemoryMarshal.Cast((Span)rowBytes); bool noneOpaque; for (int length = 8; length < row.Length; length += 8) diff --git a/tests/ImageSharp.Tests/Image/ImageFrameTests.cs b/tests/ImageSharp.Tests/Image/ImageFrameTests.cs index e09ef487a8..ef5b5f4def 100644 --- a/tests/ImageSharp.Tests/Image/ImageFrameTests.cs +++ b/tests/ImageSharp.Tests/Image/ImageFrameTests.cs @@ -112,7 +112,7 @@ public void CopyPixelDataTo_Success(bool disco, bool byteSpan) } byte[] expected = TestUtils.FillImageWithRandomBytes(image); - byte[] actual = new byte[expected.Length]; + Span actual = new byte[expected.Length]; if (byteSpan) { image.Frames.RootFrame.CopyPixelDataTo(actual); diff --git a/tests/ImageSharp.Tests/Image/ImageTests.cs b/tests/ImageSharp.Tests/Image/ImageTests.cs index ac91ea948e..16b8962c70 100644 --- a/tests/ImageSharp.Tests/Image/ImageTests.cs +++ b/tests/ImageSharp.Tests/Image/ImageTests.cs @@ -190,7 +190,7 @@ public void CopyPixelDataTo_Success(bool disco, bool byteSpan) } byte[] expected = TestUtils.FillImageWithRandomBytes(image); - byte[] actual = new byte[expected.Length]; + Span actual = new byte[expected.Length]; if (byteSpan) { image.CopyPixelDataTo(actual); From 7a5be7287e8428cb4e89871bd5c49bf88c491340 Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Thu, 20 Feb 2025 18:36:25 +0100 Subject: [PATCH 14/17] Add test cases for tiled lzw compressed images --- .../Decompressors/DeflateTiffCompression.cs | 2 +- .../Decompressors/LzwTiffCompression.cs | 20 +++++++++++++++++-- .../Tiff/Compression/HorizontalPredictor.cs | 7 +++++++ .../Compression/TiffDecompressorsFactory.cs | 2 +- .../Compression/LzwTiffCompressionTests.cs | 2 +- .../Formats/Tiff/TiffDecoderTests.cs | 17 ++++++++++++++++ tests/ImageSharp.Tests/TestImages.cs | 15 ++++++++++++++ ...t_big_endian_lzw_compressed_predictor.tiff | 3 +++ ...ittle_endian_lzw_compressed_predictor.tiff | 3 +++ ...t_big_endian_lzw_compressed_predictor.tiff | 3 +++ ...ittle_endian_lzw_compressed_predictor.tiff | 3 +++ .../tiled_gray_lzw_compressed_predictor.tiff | 3 +++ ...t_big_endian_lzw_compressed_predictor.tiff | 3 +++ ...ittle_endian_lzw_compressed_predictor.tiff | 3 +++ ...t_big_endian_lzw_compressed_predictor.tiff | 3 +++ ...ittle_endian_lzw_compressed_predictor.tiff | 3 +++ ...t_big_endian_lzw_compressed_predictor.tiff | 3 +++ ...ittle_endian_lzw_compressed_predictor.tiff | 3 +++ .../tiled_rgb_lzw_compressed_predictor.tiff | 3 +++ ...t_big_endian_lzw_compressed_predictor.tiff | 3 +++ ...ittle_endian_lzw_compressed_predictor.tiff | 3 +++ .../tiled_rgba_lzw_compressed_predictor.tiff | 3 +++ 22 files changed, 105 insertions(+), 5 deletions(-) create mode 100644 tests/Images/Input/Tiff/tiled_gray_16bit_big_endian_lzw_compressed_predictor.tiff create mode 100644 tests/Images/Input/Tiff/tiled_gray_16bit_little_endian_lzw_compressed_predictor.tiff create mode 100644 tests/Images/Input/Tiff/tiled_gray_32bit_big_endian_lzw_compressed_predictor.tiff create mode 100644 tests/Images/Input/Tiff/tiled_gray_32bit_little_endian_lzw_compressed_predictor.tiff create mode 100644 tests/Images/Input/Tiff/tiled_gray_lzw_compressed_predictor.tiff create mode 100644 tests/Images/Input/Tiff/tiled_rgb_48bit_big_endian_lzw_compressed_predictor.tiff create mode 100644 tests/Images/Input/Tiff/tiled_rgb_48bit_little_endian_lzw_compressed_predictor.tiff create mode 100644 tests/Images/Input/Tiff/tiled_rgb_64bit_big_endian_lzw_compressed_predictor.tiff create mode 100644 tests/Images/Input/Tiff/tiled_rgb_64bit_little_endian_lzw_compressed_predictor.tiff create mode 100644 tests/Images/Input/Tiff/tiled_rgb_96bit_big_endian_lzw_compressed_predictor.tiff create mode 100644 tests/Images/Input/Tiff/tiled_rgb_96bit_little_endian_lzw_compressed_predictor.tiff create mode 100644 tests/Images/Input/Tiff/tiled_rgb_lzw_compressed_predictor.tiff create mode 100644 tests/Images/Input/Tiff/tiled_rgba_128bit_big_endian_lzw_compressed_predictor.tiff create mode 100644 tests/Images/Input/Tiff/tiled_rgba_128bit_little_endian_lzw_compressed_predictor.tiff create mode 100644 tests/Images/Input/Tiff/tiled_rgba_lzw_compressed_predictor.tiff diff --git a/src/ImageSharp/Formats/Tiff/Compression/Decompressors/DeflateTiffCompression.cs b/src/ImageSharp/Formats/Tiff/Compression/Decompressors/DeflateTiffCompression.cs index 12aadbea6e..3fcbd292d2 100644 --- a/src/ImageSharp/Formats/Tiff/Compression/Decompressors/DeflateTiffCompression.cs +++ b/src/ImageSharp/Formats/Tiff/Compression/Decompressors/DeflateTiffCompression.cs @@ -76,11 +76,11 @@ protected override void Decompress(BufferedReadStream stream, int byteCount, int } } - // 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 01591e138b..5995cbc8fe 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 @@ protected override void Decompress(BufferedReadStream stream, int byteCount, int 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 e15584f3fd..6bd0230a19 100644 --- a/src/ImageSharp/Formats/Tiff/Compression/HorizontalPredictor.cs +++ b/src/ImageSharp/Formats/Tiff/Compression/HorizontalPredictor.cs @@ -62,6 +62,13 @@ public static void Undo(Span pixelBytes, int width, TiffColorType colorTyp } } + /// + /// 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 3274f5729c..eec1efcb26 100644 --- a/src/ImageSharp/Formats/Tiff/Compression/TiffDecompressorsFactory.cs +++ b/src/ImageSharp/Formats/Tiff/Compression/TiffDecompressorsFactory.cs @@ -45,7 +45,7 @@ public static TiffBaseDecompressor Create( 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 635a3a33e4..86da731863 100644 --- a/tests/ImageSharp.Tests/Formats/Tiff/Compression/LzwTiffCompressionTests.cs +++ b/tests/ImageSharp.Tests/Formats/Tiff/Compression/LzwTiffCompressionTests.cs @@ -37,7 +37,7 @@ public void Compress_Decompress_Roundtrip_Works(byte[] data) 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 16d3ade0ef..819547c519 100644 --- a/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs @@ -107,6 +107,23 @@ public void TiffDecoder_CanDecode_Tiled(TestImageProvider provid 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 000cf4d2e1..6982a28223 100644 --- a/tests/ImageSharp.Tests/TestImages.cs +++ b/tests/ImageSharp.Tests/TestImages.cs @@ -1003,6 +1003,21 @@ public static class Tiff 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 0000000000..6600ab8c2c --- /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 0000000000..d4508e32ad --- /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 0000000000..adf2c55e00 --- /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 0000000000..2f7abc69a2 --- /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 0000000000..b226121cce --- /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 0000000000..843268cad4 --- /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 0000000000..e3457633e0 --- /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 0000000000..9c442bf340 --- /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 0000000000..456f57cbd6 --- /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 0000000000..90a73d7061 --- /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 0000000000..3eba8648a6 --- /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 0000000000..144fdc0a06 --- /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 0000000000..6aee230d8b --- /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 0000000000..2a35d0f1c2 --- /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 0000000000..efc09ced58 --- /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 From 8f97280e0fc24a49d364c302925df06b73072ec9 Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Thu, 20 Feb 2025 18:56:28 +0100 Subject: [PATCH 15/17] Add tiled rgba 16 bit each channel test files --- .../tiled_rgba_64bit_big_endian_lzw_compressed_predictor.tiff | 3 +++ ...iled_rgba_64bit_little_endian_lzw_compressed_predictor.tiff | 3 +++ 2 files changed, 6 insertions(+) create mode 100644 tests/Images/Input/Tiff/tiled_rgba_64bit_big_endian_lzw_compressed_predictor.tiff create mode 100644 tests/Images/Input/Tiff/tiled_rgba_64bit_little_endian_lzw_compressed_predictor.tiff diff --git a/tests/Images/Input/Tiff/tiled_rgba_64bit_big_endian_lzw_compressed_predictor.tiff b/tests/Images/Input/Tiff/tiled_rgba_64bit_big_endian_lzw_compressed_predictor.tiff new file mode 100644 index 0000000000..9c442bf340 --- /dev/null +++ b/tests/Images/Input/Tiff/tiled_rgba_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_rgba_64bit_little_endian_lzw_compressed_predictor.tiff b/tests/Images/Input/Tiff/tiled_rgba_64bit_little_endian_lzw_compressed_predictor.tiff new file mode 100644 index 0000000000..456f57cbd6 --- /dev/null +++ b/tests/Images/Input/Tiff/tiled_rgba_64bit_little_endian_lzw_compressed_predictor.tiff @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d8e05d9ca953045d732c4304575588d2db2ead50177b2ed9416922568760ee1f +size 244625 From 18f8de983ebb837f9b98d25ce5cef72839b3741b Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Sat, 22 Feb 2025 19:40:13 +0100 Subject: [PATCH 16/17] Do not ignore tileHeight when undoing horizontal predictor --- .../Compression/Decompressors/DeflateTiffCompression.cs | 8 ++++++-- .../Tiff/Compression/Decompressors/LzwTiffCompression.cs | 8 ++++++-- .../Formats/Tiff/Compression/HorizontalPredictor.cs | 7 ++++--- .../Formats/Tiff/Compression/TiffDecompressorsFactory.cs | 7 ++++--- src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs | 7 ++++--- .../Tiff/Compression/DeflateTiffCompressionTests.cs | 2 +- .../Formats/Tiff/Compression/LzwTiffCompressionTests.cs | 2 +- 7 files changed, 26 insertions(+), 15 deletions(-) diff --git a/src/ImageSharp/Formats/Tiff/Compression/Decompressors/DeflateTiffCompression.cs b/src/ImageSharp/Formats/Tiff/Compression/Decompressors/DeflateTiffCompression.cs index 3fcbd292d2..64e702f1be 100644 --- a/src/ImageSharp/Formats/Tiff/Compression/Decompressors/DeflateTiffCompression.cs +++ b/src/ImageSharp/Formats/Tiff/Compression/Decompressors/DeflateTiffCompression.cs @@ -26,6 +26,8 @@ internal sealed class DeflateTiffCompression : TiffBaseDecompressor private readonly int tileWidth; + private readonly int tileHeight; + /// /// Initializes a new instance of the class. /// @@ -37,13 +39,15 @@ internal sealed class DeflateTiffCompression : TiffBaseDecompressor /// if set to true decodes the pixel data as big endian, otherwise as little endian. /// Flag indicates, if the image is a tiled image. /// 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) + /// Number of rows in a tile. + public DeflateTiffCompression(MemoryAllocator memoryAllocator, int width, int bitsPerPixel, TiffColorType colorType, TiffPredictor predictor, bool isBigEndian, bool isTiled, int tileWidth, int tileHeight) : base(memoryAllocator, width, bitsPerPixel, predictor) { this.colorType = colorType; this.isBigEndian = isBigEndian; this.isTiled = isTiled; this.tileWidth = tileWidth; + this.tileHeight = tileHeight; } /// @@ -81,7 +85,7 @@ protected override void Decompress(BufferedReadStream stream, int byteCount, int 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); + HorizontalPredictor.UndoTile(buffer, this.tileWidth, this.tileHeight, 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 5995cbc8fe..2402927186 100644 --- a/src/ImageSharp/Formats/Tiff/Compression/Decompressors/LzwTiffCompression.cs +++ b/src/ImageSharp/Formats/Tiff/Compression/Decompressors/LzwTiffCompression.cs @@ -21,6 +21,8 @@ internal sealed class LzwTiffCompression : TiffBaseDecompressor private readonly int tileWidth; + private readonly int tileHeight; + /// /// Initializes a new instance of the class. /// @@ -32,13 +34,15 @@ internal sealed class LzwTiffCompression : TiffBaseDecompressor /// if set to true decodes the pixel data as big endian, otherwise as little endian. /// 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) + /// Number of rows in a tile. + public LzwTiffCompression(MemoryAllocator memoryAllocator, int width, int bitsPerPixel, TiffColorType colorType, TiffPredictor predictor, bool isBigEndian, bool isTiled, int tileWidth, int tileHeight) : base(memoryAllocator, width, bitsPerPixel, predictor) { this.colorType = colorType; this.isBigEndian = isBigEndian; this.isTiled = isTiled; this.tileWidth = tileWidth; + this.tileHeight = tileHeight; } /// @@ -52,7 +56,7 @@ protected override void Decompress(BufferedReadStream stream, int byteCount, int 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); + HorizontalPredictor.UndoTile(buffer, this.tileWidth, this.tileHeight, this.colorType, this.isBigEndian); } else { diff --git a/src/ImageSharp/Formats/Tiff/Compression/HorizontalPredictor.cs b/src/ImageSharp/Formats/Tiff/Compression/HorizontalPredictor.cs index 6bd0230a19..706e6a38c1 100644 --- a/src/ImageSharp/Formats/Tiff/Compression/HorizontalPredictor.cs +++ b/src/ImageSharp/Formats/Tiff/Compression/HorizontalPredictor.cs @@ -66,12 +66,13 @@ public static void Undo(Span pixelBytes, int width, TiffColorType colorTyp /// Inverts the horizontal predictor for each tile row. /// /// Buffer with decompressed pixel data for a tile. - /// Tile with in pixels. + /// Tile width in pixels. + /// Tile height 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) + public static void UndoTile(Span pixelBytes, int tileWidth, int tileHeight, TiffColorType colorType, bool isBigEndian) { - for (int y = 0; y < tileWidth; y++) + for (int y = 0; y < tileHeight; y++) { UndoRow(pixelBytes, tileWidth, y, colorType, isBigEndian); } diff --git a/src/ImageSharp/Formats/Tiff/Compression/TiffDecompressorsFactory.cs b/src/ImageSharp/Formats/Tiff/Compression/TiffDecompressorsFactory.cs index eec1efcb26..3e1df261b8 100644 --- a/src/ImageSharp/Formats/Tiff/Compression/TiffDecompressorsFactory.cs +++ b/src/ImageSharp/Formats/Tiff/Compression/TiffDecompressorsFactory.cs @@ -25,7 +25,8 @@ public static TiffBaseDecompressor Create( TiffFillOrder fillOrder, ByteOrder byteOrder, bool isTiled = false, - int tileWidth = 0) + int tileWidth = 0, + int tileHeight = 0) { switch (method) { @@ -41,11 +42,11 @@ public static TiffBaseDecompressor Create( 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, tileWidth); + return new DeflateTiffCompression(allocator, width, bitsPerPixel, colorType, predictor, byteOrder == ByteOrder.BigEndian, isTiled, tileWidth, tileHeight); 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, isTiled, tileWidth); + return new LzwTiffCompression(allocator, width, bitsPerPixel, colorType, predictor, byteOrder == ByteOrder.BigEndian, isTiled, tileWidth, tileHeight); case TiffDecoderCompressionType.T4: DebugGuard.IsTrue(predictor == TiffPredictor.None, "Predictor should only be used with lzw or deflate compression"); diff --git a/src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs b/src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs index c642f6734d..d8ebb1e9e5 100644 --- a/src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs +++ b/src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs @@ -679,7 +679,7 @@ private void DecodeTilesChunky( using IMemoryOwner tileBuffer = this.memoryAllocator.Allocate(bytesPerTileRow * tileLength, AllocationOptions.Clean); Span tileBufferSpan = tileBuffer.GetSpan(); - using TiffBaseDecompressor decompressor = this.CreateDecompressor(frame.Width, bitsPerPixel, true, tileWidth); + using TiffBaseDecompressor decompressor = this.CreateDecompressor(frame.Width, bitsPerPixel, true, tileWidth, tileLength); TiffBaseColorDecoder colorDecoder = this.CreateChunkyColorDecoder(); int tileIndex = 0; @@ -747,7 +747,7 @@ private TiffBasePlanarColorDecoder CreatePlanarColorDecoder() this.YcbcrSubSampling, this.byteOrder); - private TiffBaseDecompressor CreateDecompressor(int frameWidth, int bitsPerPixel, bool isTiled = false, int tileWidth = 0) + private TiffBaseDecompressor CreateDecompressor(int frameWidth, int bitsPerPixel, bool isTiled = false, int tileWidth = 0, int tileHeight = 0) where TPixel : unmanaged, IPixel => TiffDecompressorsFactory.Create( this.Options, @@ -764,7 +764,8 @@ private TiffBaseDecompressor CreateDecompressor(int frameWidth, int bits this.FillOrder, this.byteOrder, isTiled, - tileWidth); + tileWidth, + tileHeight); 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 3db142d6d5..b16119f338 100644 --- a/tests/ImageSharp.Tests/Formats/Tiff/Compression/DeflateTiffCompressionTests.cs +++ b/tests/ImageSharp.Tests/Formats/Tiff/Compression/DeflateTiffCompressionTests.cs @@ -23,7 +23,7 @@ public void Compress_Decompress_Roundtrip_Works(byte[] data) 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, 0); + using var decompressor = new DeflateTiffCompression(Configuration.Default.MemoryAllocator, 10, 8, TiffColorType.BlackIsZero8, TiffPredictor.None, false, false, 0, 0); decompressor.Decompress(stream, 0, (uint)stream.Length, 1, buffer, default); diff --git a/tests/ImageSharp.Tests/Formats/Tiff/Compression/LzwTiffCompressionTests.cs b/tests/ImageSharp.Tests/Formats/Tiff/Compression/LzwTiffCompressionTests.cs index 86da731863..8c21e346af 100644 --- a/tests/ImageSharp.Tests/Formats/Tiff/Compression/LzwTiffCompressionTests.cs +++ b/tests/ImageSharp.Tests/Formats/Tiff/Compression/LzwTiffCompressionTests.cs @@ -37,7 +37,7 @@ public void Compress_Decompress_Roundtrip_Works(byte[] data) 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, false, 0); + using var decompressor = new LzwTiffCompression(Configuration.Default.MemoryAllocator, 10, 8, TiffColorType.BlackIsZero8, TiffPredictor.None, false, false, 0, 0); decompressor.Decompress(stream, 0, (uint)stream.Length, 1, buffer, default); Assert.Equal(data, buffer); From 23cfdd28641997417c114eff5854345a8c6ed0b8 Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Sun, 23 Feb 2025 18:40:58 +0100 Subject: [PATCH 17/17] Better test images for tiled tiff: tile width and height is not the same --- ...ed_gray_16bit_big_endian_deflate_compressed_predictor.tiff | 4 ++-- .../tiled_gray_16bit_big_endian_lzw_compressed_predictor.tiff | 4 ++-- ...ed_gray_32bit_big_endian_deflate_compressed_predictor.tiff | 4 ++-- .../tiled_gray_32bit_big_endian_lzw_compressed_predictor.tiff | 4 ++-- ...gray_32bit_little_endian_deflate_compressed_predictor.tiff | 4 ++-- ...led_gray_32bit_little_endian_lzw_compressed_predictor.tiff | 4 ++-- .../Input/Tiff/tiled_gray_deflate_compressed_predictor.tiff | 4 ++-- .../Input/Tiff/tiled_gray_lzw_compressed_predictor.tiff | 4 ++-- ...led_rgb_48bit_big_endian_deflate_compressed_predictor.tiff | 4 ++-- .../tiled_rgb_48bit_big_endian_lzw_compressed_predictor.tiff | 4 ++-- ..._rgb_48bit_little_endian_deflate_compressed_predictor.tiff | 4 ++-- ...iled_rgb_48bit_little_endian_lzw_compressed_predictor.tiff | 4 ++-- ...led_rgb_64bit_big_endian_deflate_compressed_predictor.tiff | 3 +++ .../tiled_rgb_64bit_big_endian_lzw_compressed_predictor.tiff | 4 ++-- ..._rgb_64bit_little_endian_deflate_compressed_predictor.tiff | 3 +++ ...iled_rgb_64bit_little_endian_lzw_compressed_predictor.tiff | 4 ++-- ...led_rgb_96bit_big_endian_deflate_compressed_predictor.tiff | 4 ++-- .../tiled_rgb_96bit_big_endian_lzw_compressed_predictor.tiff | 4 ++-- ..._rgb_96bit_little_endian_deflate_compressed_predictor.tiff | 4 ++-- ...iled_rgb_96bit_little_endian_lzw_compressed_predictor.tiff | 4 ++-- .../Input/Tiff/tiled_rgb_deflate_compressed_predictor.tiff | 4 ++-- .../Images/Input/Tiff/tiled_rgb_lzw_compressed_predictor.tiff | 4 ++-- ...d_rgba_128bit_big_endian_deflate_compressed_predictor.tiff | 4 ++-- ...tiled_rgba_128bit_big_endian_lzw_compressed_predictor.tiff | 4 ++-- ...gba_128bit_little_endian_deflate_compressed_predictor.tiff | 4 ++-- ...ed_rgba_128bit_little_endian_lzw_compressed_predictor.tiff | 4 ++-- .../Input/Tiff/tiled_rgba_deflate_compressed_predictor.tiff | 4 ++-- .../Input/Tiff/tiled_rgba_lzw_compressed_predictor.tiff | 4 ++-- 28 files changed, 58 insertions(+), 52 deletions(-) create mode 100644 tests/Images/Input/Tiff/tiled_rgb_64bit_big_endian_deflate_compressed_predictor.tiff create mode 100644 tests/Images/Input/Tiff/tiled_rgb_64bit_little_endian_deflate_compressed_predictor.tiff diff --git a/tests/Images/Input/Tiff/tiled_gray_16bit_big_endian_deflate_compressed_predictor.tiff b/tests/Images/Input/Tiff/tiled_gray_16bit_big_endian_deflate_compressed_predictor.tiff index 778601cd8b..f99c06f3fa 100644 --- a/tests/Images/Input/Tiff/tiled_gray_16bit_big_endian_deflate_compressed_predictor.tiff +++ b/tests/Images/Input/Tiff/tiled_gray_16bit_big_endian_deflate_compressed_predictor.tiff @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e267cf78bebba51628f0aca98c8720e8ea8013b9e5f96c8f12df1c153f34f065 -size 80195 +oid sha256:af45780d252025f690e039738f37a6656fea72ecdc8b816eea354259af46ebed +size 87491 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 index 6600ab8c2c..fbeb462fbc 100644 --- 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 @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d1cf5098ff98ded0a55cfa73f823cef9c324a66e38ce4a82bae2d3ef4c058c3e -size 78817 +oid sha256:190a4968abd4bbd39273020f0f8bee0e0e48573931653eaea5e49b49d3961206 +size 87301 diff --git a/tests/Images/Input/Tiff/tiled_gray_32bit_big_endian_deflate_compressed_predictor.tiff b/tests/Images/Input/Tiff/tiled_gray_32bit_big_endian_deflate_compressed_predictor.tiff index 17866b164a..e7c527c9cb 100644 --- a/tests/Images/Input/Tiff/tiled_gray_32bit_big_endian_deflate_compressed_predictor.tiff +++ b/tests/Images/Input/Tiff/tiled_gray_32bit_big_endian_deflate_compressed_predictor.tiff @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b674439ce46a39377279755ffa372c5bd863ac7787165e95590c0a9c6c5d681e -size 82469 +oid sha256:ac571a8aa1274bd11f79d7d428d72e46d25ffcb331630f5eb114b94283055f7e +size 90547 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 index adf2c55e00..76f83f3973 100644 --- 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 @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:41140a44fde93ea15514b153f1fd4d15f8e69fc8ca0c88336f01c700c4d06f93 -size 104333 +oid sha256:f4bebd7e62dbe54456923981b27dcc1415362c30a7c3c0ca665acf8dbdfe1cc8 +size 115129 diff --git a/tests/Images/Input/Tiff/tiled_gray_32bit_little_endian_deflate_compressed_predictor.tiff b/tests/Images/Input/Tiff/tiled_gray_32bit_little_endian_deflate_compressed_predictor.tiff index b524237c9a..8ca8fba8f5 100644 --- a/tests/Images/Input/Tiff/tiled_gray_32bit_little_endian_deflate_compressed_predictor.tiff +++ b/tests/Images/Input/Tiff/tiled_gray_32bit_little_endian_deflate_compressed_predictor.tiff @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3acfecebb3db8b549b7a20a3fdd967ba5a4cbb95cbb9b4a59d332fa6ec809278 -size 82519 +oid sha256:bec8072a0062101c08e0c1c1f4265150a53276d2568ada482b0ad554b13d658d +size 90585 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 index 2f7abc69a2..53aac39e78 100644 --- 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 @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b7c32da6db17088b0c3e2c21ffbdd7c43fc4944b03c2cdb9b863c296656b898d -size 103239 +oid sha256:e618556125236e2b0034b8654ab7b3e8956cf6db3c7c35ae365445ce85b2ea3d +size 114137 diff --git a/tests/Images/Input/Tiff/tiled_gray_deflate_compressed_predictor.tiff b/tests/Images/Input/Tiff/tiled_gray_deflate_compressed_predictor.tiff index ed9cd4bc05..563af83ac2 100644 --- a/tests/Images/Input/Tiff/tiled_gray_deflate_compressed_predictor.tiff +++ b/tests/Images/Input/Tiff/tiled_gray_deflate_compressed_predictor.tiff @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b5133a684a86dbc9ef48f1f988ec505765f086861c96033d350b7565ebd28271 -size 52663 +oid sha256:ce5c12864099fa02c5702a5da3f5af8cadcf7822ff95ee117a3b8d846518d9d8 +size 59361 diff --git a/tests/Images/Input/Tiff/tiled_gray_lzw_compressed_predictor.tiff b/tests/Images/Input/Tiff/tiled_gray_lzw_compressed_predictor.tiff index b226121cce..ed05c4b526 100644 --- a/tests/Images/Input/Tiff/tiled_gray_lzw_compressed_predictor.tiff +++ b/tests/Images/Input/Tiff/tiled_gray_lzw_compressed_predictor.tiff @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:63deeb0eecf0ce51000a5bba275d5a7e40fb833a962b50e6b85c4493a3719911 -size 61555 +oid sha256:2942e3a2e83ee1e10cc238299c21dcc9ccad7058b0b389f69dcf3186cbd215a1 +size 67849 diff --git a/tests/Images/Input/Tiff/tiled_rgb_48bit_big_endian_deflate_compressed_predictor.tiff b/tests/Images/Input/Tiff/tiled_rgb_48bit_big_endian_deflate_compressed_predictor.tiff index f6b92c92ce..c9a2e6fd22 100644 --- a/tests/Images/Input/Tiff/tiled_rgb_48bit_big_endian_deflate_compressed_predictor.tiff +++ b/tests/Images/Input/Tiff/tiled_rgb_48bit_big_endian_deflate_compressed_predictor.tiff @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:0880733f8463aff1feefcc08ce21860d7fb1c8c32e19aa96143bf5679a353fba -size 201673 +oid sha256:e5ffcad0698d5485dfaffc8fa8368e62e45ec54b715f82c93b0854a41875ea11 +size 220425 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 index 843268cad4..d3dc3f332a 100644 --- 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 @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:45f06403f1dc24991450331c3388ba8c4f5fd004f48787c541fad0b1c104b964 -size 212595 +oid sha256:8f69c65b66041cc34bfe894628bbe39a9e09cc9a8e7eccaefad42b672b2d2e3b +size 234705 diff --git a/tests/Images/Input/Tiff/tiled_rgb_48bit_little_endian_deflate_compressed_predictor.tiff b/tests/Images/Input/Tiff/tiled_rgb_48bit_little_endian_deflate_compressed_predictor.tiff index f6b92c92ce..cf11248642 100644 --- a/tests/Images/Input/Tiff/tiled_rgb_48bit_little_endian_deflate_compressed_predictor.tiff +++ b/tests/Images/Input/Tiff/tiled_rgb_48bit_little_endian_deflate_compressed_predictor.tiff @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:0880733f8463aff1feefcc08ce21860d7fb1c8c32e19aa96143bf5679a353fba -size 201673 +oid sha256:c3ea3976405c5512d676a0830c5d2d7a4d2c12128e56b0cf1c722b7152f4e255 +size 220415 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 index e3457633e0..b8d98e5d77 100644 --- 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 @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:4fdb91eda4e04df41df9dfb98702349308b0f104ca49051726db084c595d912b -size 212463 +oid sha256:c6715b725ac4ac2ba57f7c9f6b8fd89182b6d2c5a6b8d9141f204783bc44a8c5 +size 234697 diff --git a/tests/Images/Input/Tiff/tiled_rgb_64bit_big_endian_deflate_compressed_predictor.tiff b/tests/Images/Input/Tiff/tiled_rgb_64bit_big_endian_deflate_compressed_predictor.tiff new file mode 100644 index 0000000000..827584750d --- /dev/null +++ b/tests/Images/Input/Tiff/tiled_rgb_64bit_big_endian_deflate_compressed_predictor.tiff @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f4b95d268817cfd2e261d76a6698b51f2ccb7fbda39dc26737c9572d445f3e0e +size 240737 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 index 9c442bf340..2cb3db6007 100644 --- 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 @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a0ddd2ec8f73c784b060ff790e70f586bba70905b75f3cf8ae18f2b054e1eb06 -size 244677 +oid sha256:74dbdcc550fd0c9a425a02bb48a458e2c285030fd3fdaa8e6359bae1f4e06096 +size 270201 diff --git a/tests/Images/Input/Tiff/tiled_rgb_64bit_little_endian_deflate_compressed_predictor.tiff b/tests/Images/Input/Tiff/tiled_rgb_64bit_little_endian_deflate_compressed_predictor.tiff new file mode 100644 index 0000000000..61f2d10271 --- /dev/null +++ b/tests/Images/Input/Tiff/tiled_rgb_64bit_little_endian_deflate_compressed_predictor.tiff @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:8601908cea23f1cb15d46472c53424a7222213a8f1a3aa8df984f64068c6654c +size 240651 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 index 456f57cbd6..93d046f1c5 100644 --- 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 @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d8e05d9ca953045d732c4304575588d2db2ead50177b2ed9416922568760ee1f -size 244625 +oid sha256:e7364b83b36201d4f40144a619c7bf551f0ff27509aba3db3c7a1dbc01a881d8 +size 270305 diff --git a/tests/Images/Input/Tiff/tiled_rgb_96bit_big_endian_deflate_compressed_predictor.tiff b/tests/Images/Input/Tiff/tiled_rgb_96bit_big_endian_deflate_compressed_predictor.tiff index 34090a9e9b..9863b2271b 100644 --- a/tests/Images/Input/Tiff/tiled_rgb_96bit_big_endian_deflate_compressed_predictor.tiff +++ b/tests/Images/Input/Tiff/tiled_rgb_96bit_big_endian_deflate_compressed_predictor.tiff @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:67014dc658ced8b9f2a091f6b4e446d19babec2fb7b4bc14f010e570708d4d57 -size 209979 +oid sha256:1ad32fab0240fdd87752857d349768802305a4eed73cc42146ad92a25525963e +size 232587 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 index 90a73d7061..107a311535 100644 --- 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 @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f99d456c3fbf25ca307026a355230d7e68ac89c73d5739cceca1a2a600214483 -size 282887 +oid sha256:1c0b50066a4480b02c36ee97885e30498b0c9a702de6d317c648a7908a2d119d +size 313111 diff --git a/tests/Images/Input/Tiff/tiled_rgb_96bit_little_endian_deflate_compressed_predictor.tiff b/tests/Images/Input/Tiff/tiled_rgb_96bit_little_endian_deflate_compressed_predictor.tiff index 1a85de4ba4..28ee6d3f61 100644 --- a/tests/Images/Input/Tiff/tiled_rgb_96bit_little_endian_deflate_compressed_predictor.tiff +++ b/tests/Images/Input/Tiff/tiled_rgb_96bit_little_endian_deflate_compressed_predictor.tiff @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:535c6bc0231ef2510076bb7362412e337d9df4fc5564dc80a67a48a69ce304a9 -size 210047 +oid sha256:6022edc75314270ca5afb198113d74d5598b50663eda27a9a40563b7384d5976 +size 232667 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 index 3eba8648a6..c636b5872c 100644 --- 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 @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3bdbf90168ec824eab9f66ebd12d5dd09971363719a7b382111f50344751bbfa -size 281055 +oid sha256:02e12574235e0861f4cad850869f53893b35334142c36d7c27d317382167ed68 +size 311165 diff --git a/tests/Images/Input/Tiff/tiled_rgb_deflate_compressed_predictor.tiff b/tests/Images/Input/Tiff/tiled_rgb_deflate_compressed_predictor.tiff index d897aa94cb..71b4b29ce5 100644 --- a/tests/Images/Input/Tiff/tiled_rgb_deflate_compressed_predictor.tiff +++ b/tests/Images/Input/Tiff/tiled_rgb_deflate_compressed_predictor.tiff @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ca9253037bde106e4af13f6264a866d5e98945f471eec6fb43e3a4108631fba6 -size 145991 +oid sha256:ba8740738c2d86a22cc1bf43b1036e296e7caca8dad1ae70fd090edd9579f2cd +size 163803 diff --git a/tests/Images/Input/Tiff/tiled_rgb_lzw_compressed_predictor.tiff b/tests/Images/Input/Tiff/tiled_rgb_lzw_compressed_predictor.tiff index 144fdc0a06..a1b1bbfdd5 100644 --- a/tests/Images/Input/Tiff/tiled_rgb_lzw_compressed_predictor.tiff +++ b/tests/Images/Input/Tiff/tiled_rgb_lzw_compressed_predictor.tiff @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:12382128d89ddddf8b7ec0cf70bdfcac26c9b093bb1a2b77f61ddf75a824bfd7 -size 163249 +oid sha256:c47d681bfefa0cb12a25d685f13cc9fd01b3e0cb99828b97ccd948b43c138cfa +size 180641 diff --git a/tests/Images/Input/Tiff/tiled_rgba_128bit_big_endian_deflate_compressed_predictor.tiff b/tests/Images/Input/Tiff/tiled_rgba_128bit_big_endian_deflate_compressed_predictor.tiff index 27055256ed..c980ae69fe 100644 --- a/tests/Images/Input/Tiff/tiled_rgba_128bit_big_endian_deflate_compressed_predictor.tiff +++ b/tests/Images/Input/Tiff/tiled_rgba_128bit_big_endian_deflate_compressed_predictor.tiff @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:2d3f46e8555f014ef3a7b848c7e2e88645913c01fc70b6aeb215e9a2385a635f -size 239355 +oid sha256:a8b7aad5756525ba52e43e309a982bc318197b68a168d2cf08bae6ee4422f59c +size 264637 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 index 6aee230d8b..09edf13030 100644 --- 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 @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:81819483cbde5fddbbbf274da327a85a38db7d9946187cb5fa8c00cb03e2828d -size 336229 +oid sha256:9b8e0812543f47ce79701ddc57a6473f8f3c6e016520cdc76cf4c1c11a5f54a0 +size 370941 diff --git a/tests/Images/Input/Tiff/tiled_rgba_128bit_little_endian_deflate_compressed_predictor.tiff b/tests/Images/Input/Tiff/tiled_rgba_128bit_little_endian_deflate_compressed_predictor.tiff index b29d10c826..5f589070a8 100644 --- a/tests/Images/Input/Tiff/tiled_rgba_128bit_little_endian_deflate_compressed_predictor.tiff +++ b/tests/Images/Input/Tiff/tiled_rgba_128bit_little_endian_deflate_compressed_predictor.tiff @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:39029aaf35c923c2136e35b9fd5fae1e9c9178791e47714b8f26cb53a0091608 -size 239441 +oid sha256:0405c620eb35ce375a2a3e198ab4208e450d420a1eea17846d69fd810b7bf0aa +size 264749 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 index 2a35d0f1c2..5eb324e931 100644 --- 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 @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ed8cd226de68190ea5740d59ec0ef95095a6802ffb40539e9e2db0d9cd0ab276 -size 334413 +oid sha256:50620e1aeeb1d99fc108d08215f51eb7ef648cba506a1b657a74ee138b9e3a5f +size 369133 diff --git a/tests/Images/Input/Tiff/tiled_rgba_deflate_compressed_predictor.tiff b/tests/Images/Input/Tiff/tiled_rgba_deflate_compressed_predictor.tiff index f30e29ec85..79bf1f6b76 100644 --- a/tests/Images/Input/Tiff/tiled_rgba_deflate_compressed_predictor.tiff +++ b/tests/Images/Input/Tiff/tiled_rgba_deflate_compressed_predictor.tiff @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c4f44a67086fafc1d8784922a491e0b944b4afcd09f14b66d951b042d2745e0c -size 166487 +oid sha256:c0a3ecf077c701f450ce363633583134a79fd9d4d91fff0bd79f4bebe5f18649 +size 185503 diff --git a/tests/Images/Input/Tiff/tiled_rgba_lzw_compressed_predictor.tiff b/tests/Images/Input/Tiff/tiled_rgba_lzw_compressed_predictor.tiff index efc09ced58..6cc0f28dc7 100644 --- a/tests/Images/Input/Tiff/tiled_rgba_lzw_compressed_predictor.tiff +++ b/tests/Images/Input/Tiff/tiled_rgba_lzw_compressed_predictor.tiff @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3b9a1da29756a4bbac7ea7266067748f8468619191e9a7635e84e5eac8acc3b8 -size 183629 +oid sha256:183e011bc22048d65cd1945d60dc25dc9cb688d9141afefa1c66ae0edfca8309 +size 202825