Browse Source

Add test cases for tiled tiff, deflate compressed with predictor and color type Rgba with 32 bit for each channel

pull/2878/head
Brian Popow 1 year ago
parent
commit
dec1dc1c6b
  1. 185
      src/ImageSharp/Formats/Tiff/Compression/HorizontalPredictor.cs
  2. 6
      tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs
  3. 2
      tests/ImageSharp.Tests/TestImages.cs
  4. 3
      tests/Images/Input/Tiff/tiled_rgba_128bit_big_endian_deflate_compressed_predictor.tiff
  5. 3
      tests/Images/Input/Tiff/tiled_rgba_128bit_little_endian_deflate_compressed_predictor.tiff

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

@ -16,7 +16,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Compression;
internal static class HorizontalPredictor
{
/// <summary>
/// Inverts the horizontal prediction.
/// Inverts the horizontal predictor.
/// </summary>
/// <param name="pixelBytes">Buffer with decompressed pixel data.</param>
/// <param name="width">The width of the image or strip.</param>
@ -62,9 +62,16 @@ internal static class HorizontalPredictor
}
}
/// <summary>
/// Inverts the horizontal predictor for one row.
/// </summary>
/// <param name="pixelBytes">Buffer with decompressed pixel data.</param>
/// <param name="width">The width in pixels of the row.</param>
/// <param name="y">The row index.</param>
/// <param name="colorType">The color type of the pixel data.</param>
/// <param name="isBigEndian">If set to <c>true</c> decodes the pixel data as big endian, otherwise as little endian.</param>
public static void UndoRow(Span<byte> 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<byte> pixelBytes, int width, int y)
{
int rowBytesCount = width * 16;
int offset = 0;
Span<byte> 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<byte> 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<byte> pixelBytes, int width, int y)
{
int rowBytesCount = width * 16;
int offset = 0;
Span<byte> 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<byte> 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<byte> 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<byte> 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<byte> 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<byte> 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<byte> 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);
}
}
}

6
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<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel> => 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<TPixel>(TestImageProvider<TPixel> provider)
public void TiffDecoder_CanDecode_Tiled_Deflate_Compressed<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel> => TestTiffDecoder(provider);
[Theory]

2
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";

3
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

3
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
Loading…
Cancel
Save