Skip to content

Commit dec1dc1

Browse files
committed
Add test cases for tiled tiff, deflate compressed with predictor and color type Rgba with 32 bit for each channel
1 parent dacb713 commit dec1dc1

File tree

5 files changed

+122
-77
lines changed

5 files changed

+122
-77
lines changed

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

Lines changed: 109 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Compression;
1616
internal static class HorizontalPredictor
1717
{
1818
/// <summary>
19-
/// Inverts the horizontal prediction.
19+
/// Inverts the horizontal predictor.
2020
/// </summary>
2121
/// <param name="pixelBytes">Buffer with decompressed pixel data.</param>
2222
/// <param name="width">The width of the image or strip.</param>
@@ -62,9 +62,16 @@ public static void Undo(Span<byte> pixelBytes, int width, TiffColorType colorTyp
6262
}
6363
}
6464

65+
/// <summary>
66+
/// Inverts the horizontal predictor for one row.
67+
/// </summary>
68+
/// <param name="pixelBytes">Buffer with decompressed pixel data.</param>
69+
/// <param name="width">The width in pixels of the row.</param>
70+
/// <param name="y">The row index.</param>
71+
/// <param name="colorType">The color type of the pixel data.</param>
72+
/// <param name="isBigEndian">If set to <c>true</c> decodes the pixel data as big endian, otherwise as little endian.</param>
6573
public static void UndoRow(Span<byte> pixelBytes, int width, int y, TiffColorType colorType, bool isBigEndian)
6674
{
67-
// TODO: Implement missing colortypes, see above.
6875
switch (colorType)
6976
{
7077
case TiffColorType.BlackIsZero8:
@@ -143,6 +150,18 @@ public static void UndoRow(Span<byte> pixelBytes, int width, int y, TiffColorTyp
143150
UndoRgb96BitLittleEndianRow(pixelBytes, width, y);
144151
}
145152

153+
break;
154+
155+
case TiffColorType.Rgba32323232:
156+
if (isBigEndian)
157+
{
158+
UndoRgba128BitBigEndianRow(pixelBytes, width, y);
159+
}
160+
else
161+
{
162+
UndoRgba128BitLittleEndianRow(pixelBytes, width, y);
163+
}
164+
146165
break;
147166
}
148167
}
@@ -729,6 +748,92 @@ private static void UndoRgb96Bit(Span<byte> pixelBytes, int width, bool isBigEnd
729748
}
730749
}
731750

751+
private static void UndoRgba128BitBigEndianRow(Span<byte> pixelBytes, int width, int y)
752+
{
753+
int rowBytesCount = width * 16;
754+
755+
int offset = 0;
756+
Span<byte> rowBytes = pixelBytes.Slice(y * rowBytesCount, rowBytesCount);
757+
uint r = TiffUtilities.ConvertToUIntBigEndian(rowBytes.Slice(offset, 4));
758+
offset += 4;
759+
uint g = TiffUtilities.ConvertToUIntBigEndian(rowBytes.Slice(offset, 4));
760+
offset += 4;
761+
uint b = TiffUtilities.ConvertToUIntBigEndian(rowBytes.Slice(offset, 4));
762+
offset += 4;
763+
uint a = TiffUtilities.ConvertToUIntBigEndian(rowBytes.Slice(offset, 4));
764+
offset += 4;
765+
766+
for (int x = 1; x < width; x++)
767+
{
768+
Span<byte> rowSpan = rowBytes.Slice(offset, 4);
769+
uint deltaR = TiffUtilities.ConvertToUIntBigEndian(rowSpan);
770+
r += deltaR;
771+
BinaryPrimitives.WriteUInt32BigEndian(rowSpan, r);
772+
offset += 4;
773+
774+
rowSpan = rowBytes.Slice(offset, 4);
775+
uint deltaG = TiffUtilities.ConvertToUIntBigEndian(rowSpan);
776+
g += deltaG;
777+
BinaryPrimitives.WriteUInt32BigEndian(rowSpan, g);
778+
offset += 4;
779+
780+
rowSpan = rowBytes.Slice(offset, 4);
781+
uint deltaB = TiffUtilities.ConvertToUIntBigEndian(rowSpan);
782+
b += deltaB;
783+
BinaryPrimitives.WriteUInt32BigEndian(rowSpan, b);
784+
offset += 4;
785+
786+
rowSpan = rowBytes.Slice(offset, 4);
787+
uint deltaA = TiffUtilities.ConvertToUIntBigEndian(rowSpan);
788+
a += deltaA;
789+
BinaryPrimitives.WriteUInt32BigEndian(rowSpan, a);
790+
offset += 4;
791+
}
792+
}
793+
794+
private static void UndoRgba128BitLittleEndianRow(Span<byte> pixelBytes, int width, int y)
795+
{
796+
int rowBytesCount = width * 16;
797+
798+
int offset = 0;
799+
Span<byte> rowBytes = pixelBytes.Slice(y * rowBytesCount, rowBytesCount);
800+
uint r = TiffUtilities.ConvertToUIntLittleEndian(rowBytes.Slice(offset, 4));
801+
offset += 4;
802+
uint g = TiffUtilities.ConvertToUIntLittleEndian(rowBytes.Slice(offset, 4));
803+
offset += 4;
804+
uint b = TiffUtilities.ConvertToUIntLittleEndian(rowBytes.Slice(offset, 4));
805+
offset += 4;
806+
uint a = TiffUtilities.ConvertToUIntLittleEndian(rowBytes.Slice(offset, 4));
807+
offset += 4;
808+
809+
for (int x = 1; x < width; x++)
810+
{
811+
Span<byte> rowSpan = rowBytes.Slice(offset, 4);
812+
uint deltaR = TiffUtilities.ConvertToUIntLittleEndian(rowSpan);
813+
r += deltaR;
814+
BinaryPrimitives.WriteUInt32LittleEndian(rowSpan, r);
815+
offset += 4;
816+
817+
rowSpan = rowBytes.Slice(offset, 4);
818+
uint deltaG = TiffUtilities.ConvertToUIntLittleEndian(rowSpan);
819+
g += deltaG;
820+
BinaryPrimitives.WriteUInt32LittleEndian(rowSpan, g);
821+
offset += 4;
822+
823+
rowSpan = rowBytes.Slice(offset, 4);
824+
uint deltaB = TiffUtilities.ConvertToUIntLittleEndian(rowSpan);
825+
b += deltaB;
826+
BinaryPrimitives.WriteUInt32LittleEndian(rowSpan, b);
827+
offset += 4;
828+
829+
rowSpan = rowBytes.Slice(offset, 4);
830+
uint deltaA = TiffUtilities.ConvertToUIntLittleEndian(rowSpan);
831+
a += deltaA;
832+
BinaryPrimitives.WriteUInt32LittleEndian(rowSpan, a);
833+
offset += 4;
834+
}
835+
}
836+
732837
private static void UndoRgba128Bit(Span<byte> pixelBytes, int width, bool isBigEndian)
733838
{
734839
int rowBytesCount = width * 16;
@@ -737,86 +842,14 @@ private static void UndoRgba128Bit(Span<byte> pixelBytes, int width, bool isBigE
737842
{
738843
for (int y = 0; y < height; y++)
739844
{
740-
int offset = 0;
741-
Span<byte> rowBytes = pixelBytes.Slice(y * rowBytesCount, rowBytesCount);
742-
uint r = TiffUtilities.ConvertToUIntBigEndian(rowBytes.Slice(offset, 4));
743-
offset += 4;
744-
uint g = TiffUtilities.ConvertToUIntBigEndian(rowBytes.Slice(offset, 4));
745-
offset += 4;
746-
uint b = TiffUtilities.ConvertToUIntBigEndian(rowBytes.Slice(offset, 4));
747-
offset += 4;
748-
uint a = TiffUtilities.ConvertToUIntBigEndian(rowBytes.Slice(offset, 4));
749-
offset += 4;
750-
751-
for (int x = 1; x < width; x++)
752-
{
753-
Span<byte> rowSpan = rowBytes.Slice(offset, 4);
754-
uint deltaR = TiffUtilities.ConvertToUIntBigEndian(rowSpan);
755-
r += deltaR;
756-
BinaryPrimitives.WriteUInt32BigEndian(rowSpan, r);
757-
offset += 4;
758-
759-
rowSpan = rowBytes.Slice(offset, 4);
760-
uint deltaG = TiffUtilities.ConvertToUIntBigEndian(rowSpan);
761-
g += deltaG;
762-
BinaryPrimitives.WriteUInt32BigEndian(rowSpan, g);
763-
offset += 4;
764-
765-
rowSpan = rowBytes.Slice(offset, 4);
766-
uint deltaB = TiffUtilities.ConvertToUIntBigEndian(rowSpan);
767-
b += deltaB;
768-
BinaryPrimitives.WriteUInt32BigEndian(rowSpan, b);
769-
offset += 4;
770-
771-
rowSpan = rowBytes.Slice(offset, 4);
772-
uint deltaA = TiffUtilities.ConvertToUIntBigEndian(rowSpan);
773-
a += deltaA;
774-
BinaryPrimitives.WriteUInt32BigEndian(rowSpan, a);
775-
offset += 4;
776-
}
845+
UndoRgba128BitBigEndianRow(pixelBytes, width, y);
777846
}
778847
}
779848
else
780849
{
781850
for (int y = 0; y < height; y++)
782851
{
783-
int offset = 0;
784-
Span<byte> rowBytes = pixelBytes.Slice(y * rowBytesCount, rowBytesCount);
785-
uint r = TiffUtilities.ConvertToUIntLittleEndian(rowBytes.Slice(offset, 4));
786-
offset += 4;
787-
uint g = TiffUtilities.ConvertToUIntLittleEndian(rowBytes.Slice(offset, 4));
788-
offset += 4;
789-
uint b = TiffUtilities.ConvertToUIntLittleEndian(rowBytes.Slice(offset, 4));
790-
offset += 4;
791-
uint a = TiffUtilities.ConvertToUIntLittleEndian(rowBytes.Slice(offset, 4));
792-
offset += 4;
793-
794-
for (int x = 1; x < width; x++)
795-
{
796-
Span<byte> rowSpan = rowBytes.Slice(offset, 4);
797-
uint deltaR = TiffUtilities.ConvertToUIntLittleEndian(rowSpan);
798-
r += deltaR;
799-
BinaryPrimitives.WriteUInt32LittleEndian(rowSpan, r);
800-
offset += 4;
801-
802-
rowSpan = rowBytes.Slice(offset, 4);
803-
uint deltaG = TiffUtilities.ConvertToUIntLittleEndian(rowSpan);
804-
g += deltaG;
805-
BinaryPrimitives.WriteUInt32LittleEndian(rowSpan, g);
806-
offset += 4;
807-
808-
rowSpan = rowBytes.Slice(offset, 4);
809-
uint deltaB = TiffUtilities.ConvertToUIntLittleEndian(rowSpan);
810-
b += deltaB;
811-
BinaryPrimitives.WriteUInt32LittleEndian(rowSpan, b);
812-
offset += 4;
813-
814-
rowSpan = rowBytes.Slice(offset, 4);
815-
uint deltaA = TiffUtilities.ConvertToUIntLittleEndian(rowSpan);
816-
a += deltaA;
817-
BinaryPrimitives.WriteUInt32LittleEndian(rowSpan, a);
818-
offset += 4;
819-
}
852+
UndoRgba128BitLittleEndianRow(pixelBytes, width, y);
820853
}
821854
}
822855
}

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

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,10 @@ public void TiffDecoder_CanDecode_Planar<TPixel>(TestImageProvider<TPixel> provi
8787
[WithFile(QuadTile, PixelTypes.Rgba32)]
8888
[WithFile(TiledChunky, PixelTypes.Rgba32)]
8989
[WithFile(TiledPlanar, PixelTypes.Rgba32)]
90+
public void TiffDecoder_CanDecode_Tiled<TPixel>(TestImageProvider<TPixel> provider)
91+
where TPixel : unmanaged, IPixel<TPixel> => TestTiffDecoder(provider);
92+
93+
[Theory]
9094
[WithFile(TiledRgbaDeflateCompressedWithPredictor, PixelTypes.Rgba32)]
9195
[WithFile(TiledRgbDeflateCompressedWithPredictor, PixelTypes.Rgba32)]
9296
[WithFile(TiledGrayDeflateCompressedWithPredictor, PixelTypes.Rgba32)]
@@ -100,7 +104,7 @@ public void TiffDecoder_CanDecode_Planar<TPixel>(TestImageProvider<TPixel> provi
100104
[WithFile(TiledRgba64BitBigEndianDeflateCompressedWithPredictor, PixelTypes.Rgba32)]
101105
[WithFile(TiledRgb96BitLittleEndianDeflateCompressedWithPredictor, PixelTypes.Rgba32)]
102106
[WithFile(TiledRgb96BitBigEndianDeflateCompressedWithPredictor, PixelTypes.Rgba32)]
103-
public void TiffDecoder_CanDecode_Tiled<TPixel>(TestImageProvider<TPixel> provider)
107+
public void TiffDecoder_CanDecode_Tiled_Deflate_Compressed<TPixel>(TestImageProvider<TPixel> provider)
104108
where TPixel : unmanaged, IPixel<TPixel> => TestTiffDecoder(provider);
105109

106110
[Theory]

tests/ImageSharp.Tests/TestImages.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -999,6 +999,8 @@ public static class Tiff
999999
public const string TiledRgba64BitBigEndianDeflateCompressedWithPredictor = "Tiff/tiled_rgba_64bit_big_endian_deflate_compressed_predictor.tiff";
10001000
public const string TiledRgb96BitLittleEndianDeflateCompressedWithPredictor = "Tiff/tiled_rgb_96bit_little_endian_deflate_compressed_predictor.tiff";
10011001
public const string TiledRgb96BitBigEndianDeflateCompressedWithPredictor = "Tiff/tiled_rgb_96bit_big_endian_deflate_compressed_predictor.tiff";
1002+
public const string TiledRgba128BitLittleEndianDeflateCompressedWithPredictor = "Tiff/tiled_rgba_128bit_little_endian_deflate_compressed_predictor.tiff";
1003+
public const string TiledRgba128BitBigEndianDeflateCompressedWithPredictor = "Tiff/tiled_rgba_128bit_big_endian_deflate_compressed_predictor.tiff";
10021004

10031005
// Images with alpha channel.
10041006
public const string Rgba2BitUnassociatedAlpha = "Tiff/RgbaUnassociatedAlpha2bit.tiff";
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
version https://git-lfs.github.com/spec/v1
2+
oid sha256:2d3f46e8555f014ef3a7b848c7e2e88645913c01fc70b6aeb215e9a2385a635f
3+
size 239355
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
version https://git-lfs.github.com/spec/v1
2+
oid sha256:39029aaf35c923c2136e35b9fd5fae1e9c9178791e47714b8f26cb53a0091608
3+
size 239441

0 commit comments

Comments
 (0)