diff --git a/src/ImageSharp/Formats/Tiff/Compression/HorizontalPredictor.cs b/src/ImageSharp/Formats/Tiff/Compression/HorizontalPredictor.cs
index a2b28e6f7..c7f25f118 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 @@ internal static class HorizontalPredictor
}
}
+ ///
+ /// 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 @@ internal static class HorizontalPredictor
UndoRgb96BitLittleEndianRow(pixelBytes, width, y);
}
+ break;
+
+ case TiffColorType.Rgba32323232:
+ if (isBigEndian)
+ {
+ UndoRgba128BitBigEndianRow(pixelBytes, width, y);
+ }
+ else
+ {
+ UndoRgba128BitLittleEndianRow(pixelBytes, width, y);
+ }
+
break;
}
}
@@ -729,6 +748,92 @@ internal static class HorizontalPredictor
}
}
+ 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 @@ internal static class HorizontalPredictor
{
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 2ca081eff..16d3ade0e 100644
--- a/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs
+++ b/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs
@@ -87,6 +87,10 @@ public class TiffDecoderTests : TiffDecoderBaseTester
[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 class TiffDecoderTests : TiffDecoderBaseTester
[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 51a56e152..c65f9ba5e 100644
--- a/tests/ImageSharp.Tests/TestImages.cs
+++ b/tests/ImageSharp.Tests/TestImages.cs
@@ -999,6 +999,8 @@ public static class TestImages
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 000000000..27055256e
--- /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 000000000..b29d10c82
--- /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