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 @@ internal static class HorizontalPredictor case TiffColorType.PaletteColor: UndoGray8BitRow(pixelBytes, width, y); break; + case TiffColorType.BlackIsZero16: case TiffColorType.WhiteIsZero16: if (isBigEndian) @@ -84,6 +85,7 @@ internal static class HorizontalPredictor } break; + case TiffColorType.BlackIsZero32: case TiffColorType.WhiteIsZero32: if (isBigEndian) @@ -96,14 +98,17 @@ internal static class HorizontalPredictor } 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 @@ internal static class HorizontalPredictor } break; + case TiffColorType.Rgba16161616: if (isBigEndian) { @@ -125,6 +131,18 @@ internal static class HorizontalPredictor UndoRgb64BitLittleEndianRow(pixelBytes, width, y); } + break; + + case TiffColorType.Rgb323232: + if (isBigEndian) + { + UndoRgb96BitBigEndianRow(pixelBytes, width, y); + } + else + { + UndoRgb96BitLittleEndianRow(pixelBytes, width, y); + } + break; } } @@ -621,6 +639,76 @@ internal static class HorizontalPredictor } } + 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 @@ 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; - - 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 class TiffDecoderTests : TiffDecoderBaseTester [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 TestImages 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