Browse Source

Add test cases for tiled tiff, deflate compressed with predictor and color type Rgb161616

pull/2878/head
Brian Popow 1 year ago
parent
commit
97133fea55
  1. 143
      src/ImageSharp/Formats/Tiff/Compression/HorizontalPredictor.cs
  2. 2
      tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs
  3. 2
      tests/ImageSharp.Tests/TestImages.cs
  4. 3
      tests/Images/Input/Tiff/tiled_rgb_48bit_big_endian_deflate_compressed_predictor.tiff
  5. 3
      tests/Images/Input/Tiff/tiled_rgb_48bit_little_endian_deflate_compressed_predictor.tiff

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

@ -103,6 +103,17 @@ internal static class HorizontalPredictor
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 @@ internal static class HorizontalPredictor
}
}
private static void UndoRgb48BitBigEndianRow(Span<byte> pixelBytes, int width, int y)
{
int rowBytesCount = width * 6;
int height = pixelBytes.Length / rowBytesCount;
int offset = 0;
Span<byte> 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<byte> 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<byte> pixelBytes, int width, int y)
{
int rowBytesCount = width * 6;
int height = pixelBytes.Length / rowBytesCount;
int offset = 0;
Span<byte> 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<byte> 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<byte> pixelBytes, int width, bool isBigEndian)
{
int rowBytesCount = width * 6;
@ -409,70 +492,14 @@ internal static class HorizontalPredictor
{
for (int y = 0; y < height; y++)
{
int offset = 0;
Span<byte> 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<byte> 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<byte> 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<byte> 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);
}
}
}

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

@ -94,6 +94,8 @@ public class TiffDecoderTests : TiffDecoderBaseTester
[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<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel> => TestTiffDecoder(provider);

2
tests/ImageSharp.Tests/TestImages.cs

@ -993,6 +993,8 @@ public static class TestImages
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";

3
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

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