diff --git a/src/ImageSharp/Formats/Tiff/Compression/Decompressors/DeflateTiffCompression.cs b/src/ImageSharp/Formats/Tiff/Compression/Decompressors/DeflateTiffCompression.cs
index 27c311009c..64e702f1be 100644
--- a/src/ImageSharp/Formats/Tiff/Compression/Decompressors/DeflateTiffCompression.cs
+++ b/src/ImageSharp/Formats/Tiff/Compression/Decompressors/DeflateTiffCompression.cs
@@ -22,6 +22,12 @@ internal sealed class DeflateTiffCompression : TiffBaseDecompressor
private readonly TiffColorType colorType;
+ private readonly bool isTiled;
+
+ private readonly int tileWidth;
+
+ private readonly int tileHeight;
+
///
/// Initializes a new instance of the class.
///
@@ -31,11 +37,17 @@ internal sealed class DeflateTiffCompression : TiffBaseDecompressor
/// The color type of the pixel data.
/// The tiff predictor used.
/// if set to true decodes the pixel data as big endian, otherwise as little endian.
- public DeflateTiffCompression(MemoryAllocator memoryAllocator, int width, int bitsPerPixel, TiffColorType colorType, TiffPredictor predictor, bool isBigEndian)
+ /// Flag indicates, if the image is a tiled image.
+ /// Number of pixels in a tile row.
+ /// Number of rows in a tile.
+ public DeflateTiffCompression(MemoryAllocator memoryAllocator, int width, int bitsPerPixel, TiffColorType colorType, TiffPredictor predictor, bool isBigEndian, bool isTiled, int tileWidth, int tileHeight)
: base(memoryAllocator, width, bitsPerPixel, predictor)
{
this.colorType = colorType;
this.isBigEndian = isBigEndian;
+ this.isTiled = isTiled;
+ this.tileWidth = tileWidth;
+ this.tileHeight = tileHeight;
}
///
@@ -70,7 +82,15 @@ protected override void Decompress(BufferedReadStream stream, int byteCount, int
if (this.Predictor == TiffPredictor.Horizontal)
{
- HorizontalPredictor.Undo(buffer, this.Width, this.colorType, this.isBigEndian);
+ if (this.isTiled)
+ {
+ // When the image is tiled, undoing the horizontal predictor will be done for each tile row.
+ HorizontalPredictor.UndoTile(buffer, this.tileWidth, this.tileHeight, this.colorType, this.isBigEndian);
+ }
+ else
+ {
+ HorizontalPredictor.Undo(buffer, this.Width, this.colorType, this.isBigEndian);
+ }
}
}
diff --git a/src/ImageSharp/Formats/Tiff/Compression/Decompressors/LzwTiffCompression.cs b/src/ImageSharp/Formats/Tiff/Compression/Decompressors/LzwTiffCompression.cs
index 01591e138b..2402927186 100644
--- a/src/ImageSharp/Formats/Tiff/Compression/Decompressors/LzwTiffCompression.cs
+++ b/src/ImageSharp/Formats/Tiff/Compression/Decompressors/LzwTiffCompression.cs
@@ -17,6 +17,12 @@ internal sealed class LzwTiffCompression : TiffBaseDecompressor
private readonly TiffColorType colorType;
+ private readonly bool isTiled;
+
+ private readonly int tileWidth;
+
+ private readonly int tileHeight;
+
///
/// Initializes a new instance of the class.
///
@@ -26,11 +32,17 @@ internal sealed class LzwTiffCompression : TiffBaseDecompressor
/// The color type of the pixel data.
/// The tiff predictor used.
/// if set to true decodes the pixel data as big endian, otherwise as little endian.
- public LzwTiffCompression(MemoryAllocator memoryAllocator, int width, int bitsPerPixel, TiffColorType colorType, TiffPredictor predictor, bool isBigEndian)
+ /// Flag indicates, if the image is a tiled image.
+ /// Number of pixels in a tile row.
+ /// Number of rows in a tile.
+ public LzwTiffCompression(MemoryAllocator memoryAllocator, int width, int bitsPerPixel, TiffColorType colorType, TiffPredictor predictor, bool isBigEndian, bool isTiled, int tileWidth, int tileHeight)
: base(memoryAllocator, width, bitsPerPixel, predictor)
{
this.colorType = colorType;
this.isBigEndian = isBigEndian;
+ this.isTiled = isTiled;
+ this.tileWidth = tileWidth;
+ this.tileHeight = tileHeight;
}
///
@@ -41,7 +53,15 @@ protected override void Decompress(BufferedReadStream stream, int byteCount, int
if (this.Predictor == TiffPredictor.Horizontal)
{
- HorizontalPredictor.Undo(buffer, this.Width, this.colorType, this.isBigEndian);
+ if (this.isTiled)
+ {
+ // When the image is tiled, undoing the horizontal predictor will be done for each tile row.
+ HorizontalPredictor.UndoTile(buffer, this.tileWidth, this.tileHeight, this.colorType, this.isBigEndian);
+ }
+ else
+ {
+ HorizontalPredictor.Undo(buffer, this.Width, this.colorType, this.isBigEndian);
+ }
}
}
diff --git a/src/ImageSharp/Formats/Tiff/Compression/HorizontalPredictor.cs b/src/ImageSharp/Formats/Tiff/Compression/HorizontalPredictor.cs
index 30a9335286..706e6a38c1 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,6 +62,126 @@ public static void Undo(Span pixelBytes, int width, TiffColorType colorTyp
}
}
+ ///
+ /// Inverts the horizontal predictor for each tile row.
+ ///
+ /// Buffer with decompressed pixel data for a tile.
+ /// Tile width in pixels.
+ /// Tile height in pixels.
+ /// 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 UndoTile(Span pixelBytes, int tileWidth, int tileHeight, TiffColorType colorType, bool isBigEndian)
+ {
+ for (int y = 0; y < tileHeight; y++)
+ {
+ UndoRow(pixelBytes, tileWidth, y, colorType, isBigEndian);
+ }
+ }
+
+ ///
+ /// 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)
+ {
+ switch (colorType)
+ {
+ case TiffColorType.BlackIsZero8:
+ case TiffColorType.WhiteIsZero8:
+ case TiffColorType.PaletteColor:
+ UndoGray8BitRow(pixelBytes, width, y);
+ break;
+
+ case TiffColorType.BlackIsZero16:
+ case TiffColorType.WhiteIsZero16:
+ if (isBigEndian)
+ {
+ UndoGray16BitBigEndianRow(pixelBytes, width, y);
+ }
+ else
+ {
+ UndoGray16BitLittleEndianRow(pixelBytes, width, y);
+ }
+
+ break;
+
+ case TiffColorType.BlackIsZero32:
+ case TiffColorType.WhiteIsZero32:
+ if (isBigEndian)
+ {
+ UndoGray32BitBigEndianRow(pixelBytes, width, y);
+ }
+ else
+ {
+ UndoGray32BitLittleEndianRow(pixelBytes, width, y);
+ }
+
+ 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)
+ {
+ UndoRgb48BitBigEndianRow(pixelBytes, width, y);
+ }
+ else
+ {
+ UndoRgb48BitLittleEndianRow(pixelBytes, width, y);
+ }
+
+ break;
+
+ case TiffColorType.Rgba16161616:
+ if (isBigEndian)
+ {
+ UndoRgb64BitBigEndianRow(pixelBytes, width, y);
+ }
+ else
+ {
+ UndoRgb64BitLittleEndianRow(pixelBytes, width, y);
+ }
+
+ break;
+
+ case TiffColorType.Rgb323232:
+ if (isBigEndian)
+ {
+ UndoRgb96BitBigEndianRow(pixelBytes, width, y);
+ }
+ else
+ {
+ UndoRgb96BitLittleEndianRow(pixelBytes, width, y);
+ }
+
+ break;
+
+ case TiffColorType.Rgba32323232:
+ if (isBigEndian)
+ {
+ UndoRgba128BitBigEndianRow(pixelBytes, width, y);
+ }
+ else
+ {
+ UndoRgba128BitLittleEndianRow(pixelBytes, width, y);
+ }
+
+ break;
+ }
+ }
+
public static void ApplyHorizontalPrediction(Span rows, int width, int bitsPerPixel)
{
if (bitsPerPixel == 8)
@@ -152,20 +272,64 @@ private static void ApplyHorizontalPrediction8Bit(Span rows, int width)
}
}
+ private static void UndoGray8BitRow(Span pixelBytes, int width, int y)
+ {
+ int rowBytesCount = width;
+ int height = pixelBytes.Length / rowBytesCount;
+ Span rowBytes = pixelBytes.Slice(y * rowBytesCount, rowBytesCount);
+ byte pixelValue = rowBytes[0];
+ for (int x = 1; x < width; x++)
+ {
+ pixelValue += rowBytes[x];
+ rowBytes[x] = pixelValue;
+ }
+ }
+
private static void UndoGray8Bit(Span pixelBytes, int width)
{
int rowBytesCount = width;
int height = pixelBytes.Length / rowBytesCount;
for (int y = 0; y < height; y++)
{
- Span rowBytes = pixelBytes.Slice(y * rowBytesCount, rowBytesCount);
+ UndoGray8BitRow(pixelBytes, width, y);
+ }
+ }
- byte pixelValue = rowBytes[0];
- for (int x = 1; x < width; x++)
- {
- pixelValue += rowBytes[x];
- rowBytes[x] = pixelValue;
- }
+ private static void UndoGray16BitBigEndianRow(Span pixelBytes, int width, int y)
+ {
+ int rowBytesCount = width * 2;
+ int height = pixelBytes.Length / rowBytesCount;
+ int offset = 0;
+ Span rowBytes = pixelBytes.Slice(y * rowBytesCount, rowBytesCount);
+ ushort pixelValue = TiffUtilities.ConvertToUShortBigEndian(rowBytes.Slice(offset, 2));
+ offset += 2;
+
+ for (int x = 1; x < width; x++)
+ {
+ Span rowSpan = rowBytes.Slice(offset, 2);
+ ushort diff = TiffUtilities.ConvertToUShortBigEndian(rowSpan);
+ pixelValue += diff;
+ BinaryPrimitives.WriteUInt16BigEndian(rowSpan, pixelValue);
+ offset += 2;
+ }
+ }
+
+ private static void UndoGray16BitLittleEndianRow(Span pixelBytes, int width, int y)
+ {
+ int rowBytesCount = width * 2;
+ int height = pixelBytes.Length / rowBytesCount;
+ int offset = 0;
+ Span rowBytes = pixelBytes.Slice(y * rowBytesCount, rowBytesCount);
+ ushort pixelValue = TiffUtilities.ConvertToUShortLittleEndian(rowBytes.Slice(offset, 2));
+ offset += 2;
+
+ for (int x = 1; x < width; x++)
+ {
+ Span rowSpan = rowBytes.Slice(offset, 2);
+ ushort diff = TiffUtilities.ConvertToUShortLittleEndian(rowSpan);
+ pixelValue += diff;
+ BinaryPrimitives.WriteUInt16LittleEndian(rowSpan, pixelValue);
+ offset += 2;
}
}
@@ -177,42 +341,58 @@ private static void UndoGray16Bit(Span pixelBytes, int width, bool isBigEn
{
for (int y = 0; y < height; y++)
{
- int offset = 0;
- Span rowBytes = pixelBytes.Slice(y * rowBytesCount, rowBytesCount);
- ushort pixelValue = TiffUtilities.ConvertToUShortBigEndian(rowBytes.Slice(offset, 2));
- offset += 2;
-
- for (int x = 1; x < width; x++)
- {
- Span rowSpan = rowBytes.Slice(offset, 2);
- ushort diff = TiffUtilities.ConvertToUShortBigEndian(rowSpan);
- pixelValue += diff;
- BinaryPrimitives.WriteUInt16BigEndian(rowSpan, pixelValue);
- offset += 2;
- }
+ UndoGray16BitBigEndianRow(pixelBytes, width, y);
}
}
else
{
for (int y = 0; y < height; y++)
{
- int offset = 0;
- Span rowBytes = pixelBytes.Slice(y * rowBytesCount, rowBytesCount);
- ushort pixelValue = TiffUtilities.ConvertToUShortLittleEndian(rowBytes.Slice(offset, 2));
- offset += 2;
-
- for (int x = 1; x < width; x++)
- {
- Span rowSpan = rowBytes.Slice(offset, 2);
- ushort diff = TiffUtilities.ConvertToUShortLittleEndian(rowSpan);
- pixelValue += diff;
- BinaryPrimitives.WriteUInt16LittleEndian(rowSpan, pixelValue);
- offset += 2;
- }
+ UndoGray16BitLittleEndianRow(pixelBytes, width, y);
}
}
}
+ private static void UndoGray32BitBigEndianRow(Span pixelBytes, int width, int y)
+ {
+ int rowBytesCount = width * 4;
+ int height = pixelBytes.Length / rowBytesCount;
+
+ int offset = 0;
+ Span rowBytes = pixelBytes.Slice(y * rowBytesCount, rowBytesCount);
+ uint pixelValue = TiffUtilities.ConvertToUIntBigEndian(rowBytes.Slice(offset, 4));
+ offset += 4;
+
+ for (int x = 1; x < width; x++)
+ {
+ Span rowSpan = rowBytes.Slice(offset, 4);
+ uint diff = TiffUtilities.ConvertToUIntBigEndian(rowSpan);
+ pixelValue += diff;
+ BinaryPrimitives.WriteUInt32BigEndian(rowSpan, pixelValue);
+ offset += 4;
+ }
+ }
+
+ private static void UndoGray32BitLittleEndianRow(Span pixelBytes, int width, int y)
+ {
+ int rowBytesCount = width * 4;
+ int height = pixelBytes.Length / rowBytesCount;
+
+ int offset = 0;
+ Span rowBytes = pixelBytes.Slice(y * rowBytesCount, rowBytesCount);
+ uint pixelValue = TiffUtilities.ConvertToUIntLittleEndian(rowBytes.Slice(offset, 4));
+ offset += 4;
+
+ for (int x = 1; x < width; x++)
+ {
+ Span rowSpan = rowBytes.Slice(offset, 4);
+ uint diff = TiffUtilities.ConvertToUIntLittleEndian(rowSpan);
+ pixelValue += diff;
+ BinaryPrimitives.WriteUInt32LittleEndian(rowSpan, pixelValue);
+ offset += 4;
+ }
+ }
+
private static void UndoGray32Bit(Span pixelBytes, int width, bool isBigEndian)
{
int rowBytesCount = width * 4;
@@ -221,63 +401,68 @@ private static void UndoGray32Bit(Span pixelBytes, int width, bool isBigEn
{
for (int y = 0; y < height; y++)
{
- int offset = 0;
- Span rowBytes = pixelBytes.Slice(y * rowBytesCount, rowBytesCount);
- uint pixelValue = TiffUtilities.ConvertToUIntBigEndian(rowBytes.Slice(offset, 4));
- offset += 4;
-
- for (int x = 1; x < width; x++)
- {
- Span rowSpan = rowBytes.Slice(offset, 4);
- uint diff = TiffUtilities.ConvertToUIntBigEndian(rowSpan);
- pixelValue += diff;
- BinaryPrimitives.WriteUInt32BigEndian(rowSpan, pixelValue);
- offset += 4;
- }
+ UndoGray32BitBigEndianRow(pixelBytes, width, y);
}
}
else
{
for (int y = 0; y < height; y++)
{
- int offset = 0;
- Span rowBytes = pixelBytes.Slice(y * rowBytesCount, rowBytesCount);
- uint pixelValue = TiffUtilities.ConvertToUIntLittleEndian(rowBytes.Slice(offset, 4));
- offset += 4;
-
- for (int x = 1; x < width; x++)
- {
- Span rowSpan = rowBytes.Slice(offset, 4);
- uint diff = TiffUtilities.ConvertToUIntLittleEndian(rowSpan);
- pixelValue += diff;
- BinaryPrimitives.WriteUInt32LittleEndian(rowSpan, pixelValue);
- offset += 4;
- }
+ UndoGray32BitLittleEndianRow(pixelBytes, width, y);
}
}
}
+ private static void UndoRgb24BitRow(Span pixelBytes, int width, int y)
+ {
+ int rowBytesCount = width * 3;
+ Span rowBytes = pixelBytes.Slice(y * rowBytesCount, rowBytesCount);
+ Span rowRgb = MemoryMarshal.Cast(rowBytes)[..width];
+ ref Rgb24 rowRgbBase = ref MemoryMarshal.GetReference(rowRgb);
+ byte r = rowRgbBase.R;
+ byte g = rowRgbBase.G;
+ byte b = rowRgbBase.B;
+
+ for (int x = 1; x < rowRgb.Length; x++)
+ {
+ ref Rgb24 pixel = ref rowRgb[x];
+ r += pixel.R;
+ g += pixel.G;
+ b += pixel.B;
+ pixel = new Rgb24(r, g, b);
+ }
+ }
+
private static void UndoRgb24Bit(Span pixelBytes, int width)
{
int rowBytesCount = width * 3;
int height = pixelBytes.Length / rowBytesCount;
for (int y = 0; y < height; y++)
{
- Span rowBytes = pixelBytes.Slice(y * rowBytesCount, rowBytesCount);
- Span rowRgb = MemoryMarshal.Cast(rowBytes)[..width];
- ref Rgb24 rowRgbBase = ref MemoryMarshal.GetReference(rowRgb);
- byte r = rowRgbBase.R;
- byte g = rowRgbBase.G;
- byte b = rowRgbBase.B;
+ UndoRgb24BitRow(pixelBytes, width, y);
+ }
+ }
- for (int x = 1; x < rowRgb.Length; x++)
- {
- ref Rgb24 pixel = ref rowRgb[x];
- r += pixel.R;
- g += pixel.G;
- b += pixel.B;
- pixel = new Rgb24(r, g, b);
- }
+ private static void UndoRgba32BitRow(Span pixelBytes, int width, int y)
+ {
+ int rowBytesCount = width * 4;
+
+ Span rowBytes = pixelBytes.Slice(y * rowBytesCount, rowBytesCount);
+ Span rowRgb = MemoryMarshal.Cast(rowBytes)[..width];
+ ref Rgba32 rowRgbBase = ref MemoryMarshal.GetReference(rowRgb);
+ byte r = rowRgbBase.R;
+ byte g = rowRgbBase.G;
+ byte b = rowRgbBase.B;
+ byte a = rowRgbBase.A;
+
+ for (int x = 1; x < rowRgb.Length; x++)
+ {
+ ref Rgba32 pixel = ref rowRgb[x];
+ r += pixel.R;
+ g += pixel.G;
+ b += pixel.B;
+ a += pixel.A;
+ pixel = new Rgba32(r, g, b, a);
}
}
@@ -287,23 +472,79 @@ private static void UndoRgba32Bit(Span pixelBytes, int width)
int height = pixelBytes.Length / rowBytesCount;
for (int y = 0; y < height; y++)
{
- Span rowBytes = pixelBytes.Slice(y * rowBytesCount, rowBytesCount);
- Span rowRgb = MemoryMarshal.Cast(rowBytes)[..width];
- ref Rgba32 rowRgbBase = ref MemoryMarshal.GetReference(rowRgb);
- byte r = rowRgbBase.R;
- byte g = rowRgbBase.G;
- byte b = rowRgbBase.B;
- byte a = rowRgbBase.A;
+ UndoRgba32BitRow(pixelBytes, width, y);
+ }
+ }
- for (int x = 1; x < rowRgb.Length; x++)
- {
- ref Rgba32 pixel = ref rowRgb[x];
- r += pixel.R;
- g += pixel.G;
- b += pixel.B;
- a += pixel.A;
- pixel = new Rgba32(r, g, b, a);
- }
+ private static void UndoRgb48BitBigEndianRow(Span pixelBytes, int width, int y)
+ {
+ int rowBytesCount = width * 6;
+ int height = pixelBytes.Length / rowBytesCount;
+
+ int offset = 0;
+ Span 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 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 pixelBytes, int width, int y)
+ {
+ int rowBytesCount = width * 6;
+ int height = pixelBytes.Length / rowBytesCount;
+
+ int offset = 0;
+ Span 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 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;
}
}
@@ -315,74 +556,104 @@ private static void UndoRgb48Bit(Span pixelBytes, int width, bool isBigEnd
{
for (int y = 0; y < height; y++)
{
- int offset = 0;
- Span 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 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 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 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);
}
}
}
+ private static void UndoRgb64BitBigEndianRow(Span pixelBytes, int width, int y)
+ {
+ int rowBytesCount = width * 8;
+ int offset = 0;
+
+ Span 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;
+ ushort a = TiffUtilities.ConvertToUShortBigEndian(rowBytes.Slice(offset, 2));
+ offset += 2;
+
+ for (int x = 1; x < width; x++)
+ {
+ Span 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;
+
+ rowSpan = rowBytes.Slice(offset, 2);
+ ushort deltaA = TiffUtilities.ConvertToUShortBigEndian(rowSpan);
+ a += deltaA;
+ BinaryPrimitives.WriteUInt16BigEndian(rowSpan, a);
+ offset += 2;
+ }
+ }
+
+ private static void UndoRgb64BitLittleEndianRow(Span pixelBytes, int width, int y)
+ {
+ int rowBytesCount = width * 8;
+ int offset = 0;
+
+ Span 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;
+ ushort a = TiffUtilities.ConvertToUShortLittleEndian(rowBytes.Slice(offset, 2));
+ offset += 2;
+
+ for (int x = 1; x < width; x++)
+ {
+ Span 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;
+
+ rowSpan = rowBytes.Slice(offset, 2);
+ ushort deltaA = TiffUtilities.ConvertToUShortLittleEndian(rowSpan);
+ a += deltaA;
+ BinaryPrimitives.WriteUInt16LittleEndian(rowSpan, a);
+ offset += 2;
+ }
+ }
+
private static void UndoRgba64Bit(Span pixelBytes, int width, bool isBigEndian)
{
int rowBytesCount = width * 8;
@@ -391,90 +662,88 @@ private static void UndoRgba64Bit(Span pixelBytes, int width, bool isBigEn
{
for (int y = 0; y < height; y++)
{
- int offset = 0;
- Span 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;
- ushort a = TiffUtilities.ConvertToUShortBigEndian(rowBytes.Slice(offset, 2));
- offset += 2;
-
- for (int x = 1; x < width; x++)
- {
- Span 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;
-
- rowSpan = rowBytes.Slice(offset, 2);
- ushort deltaA = TiffUtilities.ConvertToUShortBigEndian(rowSpan);
- a += deltaA;
- BinaryPrimitives.WriteUInt16BigEndian(rowSpan, a);
- offset += 2;
- }
+ UndoRgb64BitBigEndianRow(pixelBytes, width, y);
}
}
else
{
for (int y = 0; y < height; y++)
{
- int offset = 0;
- Span 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;
- ushort a = TiffUtilities.ConvertToUShortLittleEndian(rowBytes.Slice(offset, 2));
- offset += 2;
-
- for (int x = 1; x < width; x++)
- {
- Span 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;
-
- rowSpan = rowBytes.Slice(offset, 2);
- ushort deltaA = TiffUtilities.ConvertToUShortLittleEndian(rowSpan);
- a += deltaA;
- BinaryPrimitives.WriteUInt16LittleEndian(rowSpan, a);
- offset += 2;
- }
+ UndoRgb64BitLittleEndianRow(pixelBytes, width, y);
}
}
}
+ 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;
@@ -483,74 +752,104 @@ private static void UndoRgb96Bit(Span pixelBytes, int width, bool isBigEnd
{
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);
}
}
}
+ 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;
@@ -559,86 +858,14 @@ private static void UndoRgba128Bit(Span pixelBytes, int width, bool isBigE
{
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/src/ImageSharp/Formats/Tiff/Compression/TiffDecompressorsFactory.cs b/src/ImageSharp/Formats/Tiff/Compression/TiffDecompressorsFactory.cs
index 720e376b9d..3e1df261b8 100644
--- a/src/ImageSharp/Formats/Tiff/Compression/TiffDecompressorsFactory.cs
+++ b/src/ImageSharp/Formats/Tiff/Compression/TiffDecompressorsFactory.cs
@@ -4,7 +4,6 @@
using SixLabors.ImageSharp.Formats.Tiff.Compression.Decompressors;
using SixLabors.ImageSharp.Formats.Tiff.Constants;
using SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation;
-using SixLabors.ImageSharp.Formats.Webp;
using SixLabors.ImageSharp.Memory;
namespace SixLabors.ImageSharp.Formats.Tiff.Compression;
@@ -24,7 +23,10 @@ public static TiffBaseDecompressor Create(
byte[] jpegTables,
uint oldJpegStartOfImageMarker,
TiffFillOrder fillOrder,
- ByteOrder byteOrder)
+ ByteOrder byteOrder,
+ bool isTiled = false,
+ int tileWidth = 0,
+ int tileHeight = 0)
{
switch (method)
{
@@ -40,11 +42,11 @@ public static TiffBaseDecompressor Create(
case TiffDecoderCompressionType.Deflate:
DebugGuard.IsTrue(faxOptions == FaxCompressionOptions.None, "No fax compression options are expected");
- return new DeflateTiffCompression(allocator, width, bitsPerPixel, colorType, predictor, byteOrder == ByteOrder.BigEndian);
+ return new DeflateTiffCompression(allocator, width, bitsPerPixel, colorType, predictor, byteOrder == ByteOrder.BigEndian, isTiled, tileWidth, tileHeight);
case TiffDecoderCompressionType.Lzw:
DebugGuard.IsTrue(faxOptions == FaxCompressionOptions.None, "No fax compression options are expected");
- return new LzwTiffCompression(allocator, width, bitsPerPixel, colorType, predictor, byteOrder == ByteOrder.BigEndian);
+ return new LzwTiffCompression(allocator, width, bitsPerPixel, colorType, predictor, byteOrder == ByteOrder.BigEndian, isTiled, tileWidth, tileHeight);
case TiffDecoderCompressionType.T4:
DebugGuard.IsTrue(predictor == TiffPredictor.None, "Predictor should only be used with lzw or deflate compression");
diff --git a/src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs b/src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs
index 7336924602..d8ebb1e9e5 100644
--- a/src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs
+++ b/src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs
@@ -679,7 +679,7 @@ private void DecodeTilesChunky(
using IMemoryOwner tileBuffer = this.memoryAllocator.Allocate(bytesPerTileRow * tileLength, AllocationOptions.Clean);
Span tileBufferSpan = tileBuffer.GetSpan();
- using TiffBaseDecompressor decompressor = this.CreateDecompressor(frame.Width, bitsPerPixel);
+ using TiffBaseDecompressor decompressor = this.CreateDecompressor(frame.Width, bitsPerPixel, true, tileWidth, tileLength);
TiffBaseColorDecoder colorDecoder = this.CreateChunkyColorDecoder();
int tileIndex = 0;
@@ -747,7 +747,7 @@ private TiffBasePlanarColorDecoder CreatePlanarColorDecoder()
this.YcbcrSubSampling,
this.byteOrder);
- private TiffBaseDecompressor CreateDecompressor(int frameWidth, int bitsPerPixel)
+ private TiffBaseDecompressor CreateDecompressor(int frameWidth, int bitsPerPixel, bool isTiled = false, int tileWidth = 0, int tileHeight = 0)
where TPixel : unmanaged, IPixel =>
TiffDecompressorsFactory.Create(
this.Options,
@@ -762,7 +762,10 @@ private TiffBaseDecompressor CreateDecompressor(int frameWidth, int bits
this.JpegTables,
this.OldJpegCompressionStartOfImageMarker.GetValueOrDefault(),
this.FillOrder,
- this.byteOrder);
+ this.byteOrder,
+ isTiled,
+ tileWidth,
+ tileHeight);
private IMemoryOwner ConvertNumbers(Array array, out Span span)
{
diff --git a/tests/ImageSharp.Tests/Formats/Tiff/Compression/DeflateTiffCompressionTests.cs b/tests/ImageSharp.Tests/Formats/Tiff/Compression/DeflateTiffCompressionTests.cs
index 1b12adac23..b16119f338 100644
--- a/tests/ImageSharp.Tests/Formats/Tiff/Compression/DeflateTiffCompressionTests.cs
+++ b/tests/ImageSharp.Tests/Formats/Tiff/Compression/DeflateTiffCompressionTests.cs
@@ -23,7 +23,7 @@ public void Compress_Decompress_Roundtrip_Works(byte[] data)
using BufferedReadStream stream = CreateCompressedStream(data);
byte[] buffer = new byte[data.Length];
- using var decompressor = new DeflateTiffCompression(Configuration.Default.MemoryAllocator, 10, 8, TiffColorType.BlackIsZero8, TiffPredictor.None, false);
+ using var decompressor = new DeflateTiffCompression(Configuration.Default.MemoryAllocator, 10, 8, TiffColorType.BlackIsZero8, TiffPredictor.None, false, false, 0, 0);
decompressor.Decompress(stream, 0, (uint)stream.Length, 1, buffer, default);
diff --git a/tests/ImageSharp.Tests/Formats/Tiff/Compression/LzwTiffCompressionTests.cs b/tests/ImageSharp.Tests/Formats/Tiff/Compression/LzwTiffCompressionTests.cs
index 635a3a33e4..8c21e346af 100644
--- a/tests/ImageSharp.Tests/Formats/Tiff/Compression/LzwTiffCompressionTests.cs
+++ b/tests/ImageSharp.Tests/Formats/Tiff/Compression/LzwTiffCompressionTests.cs
@@ -37,7 +37,7 @@ public void Compress_Decompress_Roundtrip_Works(byte[] data)
using BufferedReadStream stream = CreateCompressedStream(data);
byte[] buffer = new byte[data.Length];
- using var decompressor = new LzwTiffCompression(Configuration.Default.MemoryAllocator, 10, 8, TiffColorType.BlackIsZero8, TiffPredictor.None, false);
+ using var decompressor = new LzwTiffCompression(Configuration.Default.MemoryAllocator, 10, 8, TiffColorType.BlackIsZero8, TiffPredictor.None, false, false, 0, 0);
decompressor.Decompress(stream, 0, (uint)stream.Length, 1, buffer, default);
Assert.Equal(data, buffer);
diff --git a/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs
index 09cfe2cbea..819547c519 100644
--- a/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs
+++ b/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs
@@ -90,6 +90,40 @@ public void TiffDecoder_CanDecode_Planar(TestImageProvider provi
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)]
+ [WithFile(TiledGray16BitLittleEndianDeflateCompressedWithPredictor, PixelTypes.Rgba32)]
+ [WithFile(TiledGray16BitBigEndianDeflateCompressedWithPredictor, PixelTypes.Rgba32)]
+ [WithFile(TiledGray32BitLittleEndianDeflateCompressedWithPredictor, PixelTypes.Rgba32)]
+ [WithFile(TiledGray32BitBigEndianDeflateCompressedWithPredictor, PixelTypes.Rgba32)]
+ [WithFile(TiledRgb48BitLittleEndianDeflateCompressedWithPredictor, PixelTypes.Rgba32)]
+ [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_Deflate_Compressed(TestImageProvider provider)
+ where TPixel : unmanaged, IPixel => TestTiffDecoder(provider);
+
+ [Theory]
+ [WithFile(TiledRgbaLzwCompressedWithPredictor, PixelTypes.Rgba32)]
+ [WithFile(TiledRgbLzwCompressedWithPredictor, PixelTypes.Rgba32)]
+ [WithFile(TiledGrayLzwCompressedWithPredictor, PixelTypes.Rgba32)]
+ [WithFile(TiledGray16BitLittleEndianLzwCompressedWithPredictor, PixelTypes.Rgba32)]
+ [WithFile(TiledGray16BitBigEndianLzwCompressedWithPredictor, PixelTypes.Rgba32)]
+ [WithFile(TiledGray32BitLittleEndianLzwCompressedWithPredictor, PixelTypes.Rgba32)]
+ [WithFile(TiledGray32BitBigEndianLzwCompressedWithPredictor, PixelTypes.Rgba32)]
+ [WithFile(TiledRgb48BitLittleEndianLzwCompressedWithPredictor, PixelTypes.Rgba32)]
+ [WithFile(TiledRgb48BitBigEndianLzwCompressedWithPredictor, PixelTypes.Rgba32)]
+ [WithFile(TiledRgba64BitLittleEndianLzwCompressedWithPredictor, PixelTypes.Rgba32)]
+ [WithFile(TiledRgba64BitBigEndianLzwCompressedWithPredictor, PixelTypes.Rgba32)]
+ [WithFile(TiledRgb96BitLittleEndianLzwCompressedWithPredictor, PixelTypes.Rgba32)]
+ [WithFile(TiledRgb96BitBigEndianDeflateCompressedWithPredictor, PixelTypes.Rgba32)]
+ public void TiffDecoder_CanDecode_Tiled_Lzw_Compressed(TestImageProvider provider)
+ where TPixel : unmanaged, IPixel => TestTiffDecoder(provider);
+
[Theory]
[WithFile(Rgba8BitPlanarUnassociatedAlpha, PixelTypes.Rgba32)]
public void TiffDecoder_CanDecode_Planar_32Bit(TestImageProvider provider)
diff --git a/tests/ImageSharp.Tests/Formats/WebP/WebpCommonUtilsTests.cs b/tests/ImageSharp.Tests/Formats/WebP/WebpCommonUtilsTests.cs
index a3fe028db5..80302db393 100644
--- a/tests/ImageSharp.Tests/Formats/WebP/WebpCommonUtilsTests.cs
+++ b/tests/ImageSharp.Tests/Formats/WebP/WebpCommonUtilsTests.cs
@@ -106,7 +106,7 @@ private static void RunCheckNoneOpaqueWithNoneOpaquePixelsTest()
174, 183, 189, 255,
148, 158, 158, 255,
};
- Span row = MemoryMarshal.Cast(rowBytes);
+ Span row = MemoryMarshal.Cast((Span)rowBytes);
bool noneOpaque;
for (int length = 8; length < row.Length; length += 8)
@@ -188,7 +188,7 @@ private static void RunCheckNoneOpaqueWithOpaquePixelsTest()
174, 183, 189, 255,
148, 158, 158, 255,
};
- Span row = MemoryMarshal.Cast(rowBytes);
+ Span row = MemoryMarshal.Cast((Span)rowBytes);
bool noneOpaque;
for (int length = 8; length < row.Length; length += 8)
diff --git a/tests/ImageSharp.Tests/Image/ImageFrameTests.cs b/tests/ImageSharp.Tests/Image/ImageFrameTests.cs
index e09ef487a8..ef5b5f4def 100644
--- a/tests/ImageSharp.Tests/Image/ImageFrameTests.cs
+++ b/tests/ImageSharp.Tests/Image/ImageFrameTests.cs
@@ -112,7 +112,7 @@ public void CopyPixelDataTo_Success(bool disco, bool byteSpan)
}
byte[] expected = TestUtils.FillImageWithRandomBytes(image);
- byte[] actual = new byte[expected.Length];
+ Span actual = new byte[expected.Length];
if (byteSpan)
{
image.Frames.RootFrame.CopyPixelDataTo(actual);
diff --git a/tests/ImageSharp.Tests/Image/ImageTests.cs b/tests/ImageSharp.Tests/Image/ImageTests.cs
index ac91ea948e..16b8962c70 100644
--- a/tests/ImageSharp.Tests/Image/ImageTests.cs
+++ b/tests/ImageSharp.Tests/Image/ImageTests.cs
@@ -190,7 +190,7 @@ public void CopyPixelDataTo_Success(bool disco, bool byteSpan)
}
byte[] expected = TestUtils.FillImageWithRandomBytes(image);
- byte[] actual = new byte[expected.Length];
+ Span actual = new byte[expected.Length];
if (byteSpan)
{
image.CopyPixelDataTo(actual);
diff --git a/tests/ImageSharp.Tests/TestImages.cs b/tests/ImageSharp.Tests/TestImages.cs
index fafa1d2429..6982a28223 100644
--- a/tests/ImageSharp.Tests/TestImages.cs
+++ b/tests/ImageSharp.Tests/TestImages.cs
@@ -988,6 +988,36 @@ public static class Tiff
public const string QuadTile = "Tiff/quad-tile.tiff";
public const string TiledChunky = "Tiff/rgb_uncompressed_tiled_chunky.tiff";
public const string TiledPlanar = "Tiff/rgb_uncompressed_tiled_planar.tiff";
+ public const string TiledRgbaDeflateCompressedWithPredictor = "Tiff/tiled_rgba_deflate_compressed_predictor.tiff";
+ public const string TiledRgbDeflateCompressedWithPredictor = "Tiff/tiled_rgb_deflate_compressed_predictor.tiff";
+ public const string TiledGrayDeflateCompressedWithPredictor = "Tiff/tiled_gray_deflate_compressed_predictor.tiff";
+ public const string TiledGray16BitLittleEndianDeflateCompressedWithPredictor = "Tiff/tiled_gray_16bit_little_endian_deflate_compressed_predictor.tiff";
+ 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";
+ 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";
+ 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";
+ public const string TiledRgbaLzwCompressedWithPredictor = "Tiff/tiled_rgba_lzw_compressed_predictor.tiff";
+ public const string TiledRgbLzwCompressedWithPredictor = "Tiff/tiled_rgb_lzw_compressed_predictor.tiff";
+ public const string TiledGrayLzwCompressedWithPredictor = "Tiff/tiled_gray_lzw_compressed_predictor.tiff";
+ public const string TiledGray16BitLittleEndianLzwCompressedWithPredictor = "Tiff/tiled_gray_16bit_little_endian_lzw_compressed_predictor.tiff";
+ public const string TiledGray16BitBigEndianLzwCompressedWithPredictor = "Tiff/tiled_gray_16bit_big_endian_lzw_compressed_predictor.tiff";
+ public const string TiledGray32BitLittleEndianLzwCompressedWithPredictor = "Tiff/tiled_gray_32bit_little_endian_lzw_compressed_predictor.tiff";
+ public const string TiledGray32BitBigEndianLzwCompressedWithPredictor = "Tiff/tiled_gray_32bit_big_endian_lzw_compressed_predictor.tiff";
+ public const string TiledRgb48BitLittleEndianLzwCompressedWithPredictor = "Tiff/tiled_rgb_48bit_little_endian_lzw_compressed_predictor.tiff";
+ public const string TiledRgb48BitBigEndianLzwCompressedWithPredictor = "Tiff/tiled_rgb_48bit_big_endian_lzw_compressed_predictor.tiff";
+ public const string TiledRgba64BitLittleEndianLzwCompressedWithPredictor = "Tiff/tiled_rgba_64bit_little_endian_lzw_compressed_predictor.tiff";
+ public const string TiledRgba64BitBigEndianLzwCompressedWithPredictor = "Tiff/tiled_rgba_64bit_big_endian_lzw_compressed_predictor.tiff";
+ public const string TiledRgb96BitLittleEndianLzwCompressedWithPredictor = "Tiff/tiled_rgb_96bit_little_endian_lzw_compressed_predictor.tiff";
+ public const string TiledRgb96BitBigEndianLzwCompressedWithPredictor = "Tiff/tiled_rgb_96bit_big_endian_lzw_compressed_predictor.tiff";
+ public const string TiledRgba128BitLittleEndianLzwCompressedWithPredictor = "Tiff/tiled_rgba_128bit_little_endian_lzw_compressed_predictor.tiff";
+ public const string TiledRgba128BitBigEndianLzwCompressedWithPredictor = "Tiff/tiled_rgba_128bit_big_endian_lzw_compressed_predictor.tiff";
// Images with alpha channel.
public const string Rgba2BitUnassociatedAlpha = "Tiff/RgbaUnassociatedAlpha2bit.tiff";
diff --git a/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/MagickReferenceDecoder.cs b/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/MagickReferenceDecoder.cs
index 74015a4eff..57813f66ac 100644
--- a/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/MagickReferenceDecoder.cs
+++ b/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/MagickReferenceDecoder.cs
@@ -79,7 +79,7 @@ protected override Image Decode(DecoderOptions options, Stream s
FromRgba32Bytes(configuration, data, framePixels);
}
- else if (magicFrame.Depth is 16 or 14)
+ else if (magicFrame.Depth is 14 or 16 or 32)
{
if (this.imageFormat is PngFormat png)
{
diff --git a/tests/Images/Input/Tiff/tiled_gray_16bit_big_endian_deflate_compressed_predictor.tiff b/tests/Images/Input/Tiff/tiled_gray_16bit_big_endian_deflate_compressed_predictor.tiff
new file mode 100644
index 0000000000..f99c06f3fa
--- /dev/null
+++ b/tests/Images/Input/Tiff/tiled_gray_16bit_big_endian_deflate_compressed_predictor.tiff
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:af45780d252025f690e039738f37a6656fea72ecdc8b816eea354259af46ebed
+size 87491
diff --git a/tests/Images/Input/Tiff/tiled_gray_16bit_big_endian_lzw_compressed_predictor.tiff b/tests/Images/Input/Tiff/tiled_gray_16bit_big_endian_lzw_compressed_predictor.tiff
new file mode 100644
index 0000000000..fbeb462fbc
--- /dev/null
+++ b/tests/Images/Input/Tiff/tiled_gray_16bit_big_endian_lzw_compressed_predictor.tiff
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:190a4968abd4bbd39273020f0f8bee0e0e48573931653eaea5e49b49d3961206
+size 87301
diff --git a/tests/Images/Input/Tiff/tiled_gray_16bit_little_endian_deflate_compressed_predictor.tiff b/tests/Images/Input/Tiff/tiled_gray_16bit_little_endian_deflate_compressed_predictor.tiff
new file mode 100644
index 0000000000..2fbe32e6fa
--- /dev/null
+++ b/tests/Images/Input/Tiff/tiled_gray_16bit_little_endian_deflate_compressed_predictor.tiff
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:19b4a2ee8761e0016a598f66f12eb62edf4c4d30f33694d30986ce84516ac454
+size 80177
diff --git a/tests/Images/Input/Tiff/tiled_gray_16bit_little_endian_lzw_compressed_predictor.tiff b/tests/Images/Input/Tiff/tiled_gray_16bit_little_endian_lzw_compressed_predictor.tiff
new file mode 100644
index 0000000000..d4508e32ad
--- /dev/null
+++ b/tests/Images/Input/Tiff/tiled_gray_16bit_little_endian_lzw_compressed_predictor.tiff
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:879bacee73f5fea767439071aa6057d66d2d61bc554b109abb7b79765873730b
+size 78795
diff --git a/tests/Images/Input/Tiff/tiled_gray_32bit_big_endian_deflate_compressed_predictor.tiff b/tests/Images/Input/Tiff/tiled_gray_32bit_big_endian_deflate_compressed_predictor.tiff
new file mode 100644
index 0000000000..e7c527c9cb
--- /dev/null
+++ b/tests/Images/Input/Tiff/tiled_gray_32bit_big_endian_deflate_compressed_predictor.tiff
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:ac571a8aa1274bd11f79d7d428d72e46d25ffcb331630f5eb114b94283055f7e
+size 90547
diff --git a/tests/Images/Input/Tiff/tiled_gray_32bit_big_endian_lzw_compressed_predictor.tiff b/tests/Images/Input/Tiff/tiled_gray_32bit_big_endian_lzw_compressed_predictor.tiff
new file mode 100644
index 0000000000..76f83f3973
--- /dev/null
+++ b/tests/Images/Input/Tiff/tiled_gray_32bit_big_endian_lzw_compressed_predictor.tiff
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:f4bebd7e62dbe54456923981b27dcc1415362c30a7c3c0ca665acf8dbdfe1cc8
+size 115129
diff --git a/tests/Images/Input/Tiff/tiled_gray_32bit_little_endian_deflate_compressed_predictor.tiff b/tests/Images/Input/Tiff/tiled_gray_32bit_little_endian_deflate_compressed_predictor.tiff
new file mode 100644
index 0000000000..8ca8fba8f5
--- /dev/null
+++ b/tests/Images/Input/Tiff/tiled_gray_32bit_little_endian_deflate_compressed_predictor.tiff
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:bec8072a0062101c08e0c1c1f4265150a53276d2568ada482b0ad554b13d658d
+size 90585
diff --git a/tests/Images/Input/Tiff/tiled_gray_32bit_little_endian_lzw_compressed_predictor.tiff b/tests/Images/Input/Tiff/tiled_gray_32bit_little_endian_lzw_compressed_predictor.tiff
new file mode 100644
index 0000000000..53aac39e78
--- /dev/null
+++ b/tests/Images/Input/Tiff/tiled_gray_32bit_little_endian_lzw_compressed_predictor.tiff
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:e618556125236e2b0034b8654ab7b3e8956cf6db3c7c35ae365445ce85b2ea3d
+size 114137
diff --git a/tests/Images/Input/Tiff/tiled_gray_deflate_compressed_predictor.tiff b/tests/Images/Input/Tiff/tiled_gray_deflate_compressed_predictor.tiff
new file mode 100644
index 0000000000..563af83ac2
--- /dev/null
+++ b/tests/Images/Input/Tiff/tiled_gray_deflate_compressed_predictor.tiff
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:ce5c12864099fa02c5702a5da3f5af8cadcf7822ff95ee117a3b8d846518d9d8
+size 59361
diff --git a/tests/Images/Input/Tiff/tiled_gray_lzw_compressed_predictor.tiff b/tests/Images/Input/Tiff/tiled_gray_lzw_compressed_predictor.tiff
new file mode 100644
index 0000000000..ed05c4b526
--- /dev/null
+++ b/tests/Images/Input/Tiff/tiled_gray_lzw_compressed_predictor.tiff
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:2942e3a2e83ee1e10cc238299c21dcc9ccad7058b0b389f69dcf3186cbd215a1
+size 67849
diff --git a/tests/Images/Input/Tiff/tiled_rgb_48bit_big_endian_deflate_compressed_predictor.tiff b/tests/Images/Input/Tiff/tiled_rgb_48bit_big_endian_deflate_compressed_predictor.tiff
new file mode 100644
index 0000000000..c9a2e6fd22
--- /dev/null
+++ b/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:e5ffcad0698d5485dfaffc8fa8368e62e45ec54b715f82c93b0854a41875ea11
+size 220425
diff --git a/tests/Images/Input/Tiff/tiled_rgb_48bit_big_endian_lzw_compressed_predictor.tiff b/tests/Images/Input/Tiff/tiled_rgb_48bit_big_endian_lzw_compressed_predictor.tiff
new file mode 100644
index 0000000000..d3dc3f332a
--- /dev/null
+++ b/tests/Images/Input/Tiff/tiled_rgb_48bit_big_endian_lzw_compressed_predictor.tiff
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:8f69c65b66041cc34bfe894628bbe39a9e09cc9a8e7eccaefad42b672b2d2e3b
+size 234705
diff --git a/tests/Images/Input/Tiff/tiled_rgb_48bit_little_endian_deflate_compressed_predictor.tiff b/tests/Images/Input/Tiff/tiled_rgb_48bit_little_endian_deflate_compressed_predictor.tiff
new file mode 100644
index 0000000000..cf11248642
--- /dev/null
+++ b/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:c3ea3976405c5512d676a0830c5d2d7a4d2c12128e56b0cf1c722b7152f4e255
+size 220415
diff --git a/tests/Images/Input/Tiff/tiled_rgb_48bit_little_endian_lzw_compressed_predictor.tiff b/tests/Images/Input/Tiff/tiled_rgb_48bit_little_endian_lzw_compressed_predictor.tiff
new file mode 100644
index 0000000000..b8d98e5d77
--- /dev/null
+++ b/tests/Images/Input/Tiff/tiled_rgb_48bit_little_endian_lzw_compressed_predictor.tiff
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:c6715b725ac4ac2ba57f7c9f6b8fd89182b6d2c5a6b8d9141f204783bc44a8c5
+size 234697
diff --git a/tests/Images/Input/Tiff/tiled_rgb_64bit_big_endian_deflate_compressed_predictor.tiff b/tests/Images/Input/Tiff/tiled_rgb_64bit_big_endian_deflate_compressed_predictor.tiff
new file mode 100644
index 0000000000..827584750d
--- /dev/null
+++ b/tests/Images/Input/Tiff/tiled_rgb_64bit_big_endian_deflate_compressed_predictor.tiff
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:f4b95d268817cfd2e261d76a6698b51f2ccb7fbda39dc26737c9572d445f3e0e
+size 240737
diff --git a/tests/Images/Input/Tiff/tiled_rgb_64bit_big_endian_lzw_compressed_predictor.tiff b/tests/Images/Input/Tiff/tiled_rgb_64bit_big_endian_lzw_compressed_predictor.tiff
new file mode 100644
index 0000000000..2cb3db6007
--- /dev/null
+++ b/tests/Images/Input/Tiff/tiled_rgb_64bit_big_endian_lzw_compressed_predictor.tiff
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:74dbdcc550fd0c9a425a02bb48a458e2c285030fd3fdaa8e6359bae1f4e06096
+size 270201
diff --git a/tests/Images/Input/Tiff/tiled_rgb_64bit_little_endian_deflate_compressed_predictor.tiff b/tests/Images/Input/Tiff/tiled_rgb_64bit_little_endian_deflate_compressed_predictor.tiff
new file mode 100644
index 0000000000..61f2d10271
--- /dev/null
+++ b/tests/Images/Input/Tiff/tiled_rgb_64bit_little_endian_deflate_compressed_predictor.tiff
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:8601908cea23f1cb15d46472c53424a7222213a8f1a3aa8df984f64068c6654c
+size 240651
diff --git a/tests/Images/Input/Tiff/tiled_rgb_64bit_little_endian_lzw_compressed_predictor.tiff b/tests/Images/Input/Tiff/tiled_rgb_64bit_little_endian_lzw_compressed_predictor.tiff
new file mode 100644
index 0000000000..93d046f1c5
--- /dev/null
+++ b/tests/Images/Input/Tiff/tiled_rgb_64bit_little_endian_lzw_compressed_predictor.tiff
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:e7364b83b36201d4f40144a619c7bf551f0ff27509aba3db3c7a1dbc01a881d8
+size 270305
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..9863b2271b
--- /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:1ad32fab0240fdd87752857d349768802305a4eed73cc42146ad92a25525963e
+size 232587
diff --git a/tests/Images/Input/Tiff/tiled_rgb_96bit_big_endian_lzw_compressed_predictor.tiff b/tests/Images/Input/Tiff/tiled_rgb_96bit_big_endian_lzw_compressed_predictor.tiff
new file mode 100644
index 0000000000..107a311535
--- /dev/null
+++ b/tests/Images/Input/Tiff/tiled_rgb_96bit_big_endian_lzw_compressed_predictor.tiff
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:1c0b50066a4480b02c36ee97885e30498b0c9a702de6d317c648a7908a2d119d
+size 313111
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..28ee6d3f61
--- /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:6022edc75314270ca5afb198113d74d5598b50663eda27a9a40563b7384d5976
+size 232667
diff --git a/tests/Images/Input/Tiff/tiled_rgb_96bit_little_endian_lzw_compressed_predictor.tiff b/tests/Images/Input/Tiff/tiled_rgb_96bit_little_endian_lzw_compressed_predictor.tiff
new file mode 100644
index 0000000000..c636b5872c
--- /dev/null
+++ b/tests/Images/Input/Tiff/tiled_rgb_96bit_little_endian_lzw_compressed_predictor.tiff
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:02e12574235e0861f4cad850869f53893b35334142c36d7c27d317382167ed68
+size 311165
diff --git a/tests/Images/Input/Tiff/tiled_rgb_deflate_compressed_predictor.tiff b/tests/Images/Input/Tiff/tiled_rgb_deflate_compressed_predictor.tiff
new file mode 100644
index 0000000000..71b4b29ce5
--- /dev/null
+++ b/tests/Images/Input/Tiff/tiled_rgb_deflate_compressed_predictor.tiff
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:ba8740738c2d86a22cc1bf43b1036e296e7caca8dad1ae70fd090edd9579f2cd
+size 163803
diff --git a/tests/Images/Input/Tiff/tiled_rgb_lzw_compressed_predictor.tiff b/tests/Images/Input/Tiff/tiled_rgb_lzw_compressed_predictor.tiff
new file mode 100644
index 0000000000..a1b1bbfdd5
--- /dev/null
+++ b/tests/Images/Input/Tiff/tiled_rgb_lzw_compressed_predictor.tiff
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:c47d681bfefa0cb12a25d685f13cc9fd01b3e0cb99828b97ccd948b43c138cfa
+size 180641
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 0000000000..c980ae69fe
--- /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:a8b7aad5756525ba52e43e309a982bc318197b68a168d2cf08bae6ee4422f59c
+size 264637
diff --git a/tests/Images/Input/Tiff/tiled_rgba_128bit_big_endian_lzw_compressed_predictor.tiff b/tests/Images/Input/Tiff/tiled_rgba_128bit_big_endian_lzw_compressed_predictor.tiff
new file mode 100644
index 0000000000..09edf13030
--- /dev/null
+++ b/tests/Images/Input/Tiff/tiled_rgba_128bit_big_endian_lzw_compressed_predictor.tiff
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:9b8e0812543f47ce79701ddc57a6473f8f3c6e016520cdc76cf4c1c11a5f54a0
+size 370941
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 0000000000..5f589070a8
--- /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:0405c620eb35ce375a2a3e198ab4208e450d420a1eea17846d69fd810b7bf0aa
+size 264749
diff --git a/tests/Images/Input/Tiff/tiled_rgba_128bit_little_endian_lzw_compressed_predictor.tiff b/tests/Images/Input/Tiff/tiled_rgba_128bit_little_endian_lzw_compressed_predictor.tiff
new file mode 100644
index 0000000000..5eb324e931
--- /dev/null
+++ b/tests/Images/Input/Tiff/tiled_rgba_128bit_little_endian_lzw_compressed_predictor.tiff
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:50620e1aeeb1d99fc108d08215f51eb7ef648cba506a1b657a74ee138b9e3a5f
+size 369133
diff --git a/tests/Images/Input/Tiff/tiled_rgba_64bit_big_endian_deflate_compressed_predictor.tiff b/tests/Images/Input/Tiff/tiled_rgba_64bit_big_endian_deflate_compressed_predictor.tiff
new file mode 100644
index 0000000000..0def244601
--- /dev/null
+++ b/tests/Images/Input/Tiff/tiled_rgba_64bit_big_endian_deflate_compressed_predictor.tiff
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:f456272c6948159ea17d6fa7d2a89e30521c1d4e29f0ad0b1a79894f122d2153
+size 220119
diff --git a/tests/Images/Input/Tiff/tiled_rgba_64bit_big_endian_lzw_compressed_predictor.tiff b/tests/Images/Input/Tiff/tiled_rgba_64bit_big_endian_lzw_compressed_predictor.tiff
new file mode 100644
index 0000000000..9c442bf340
--- /dev/null
+++ b/tests/Images/Input/Tiff/tiled_rgba_64bit_big_endian_lzw_compressed_predictor.tiff
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:a0ddd2ec8f73c784b060ff790e70f586bba70905b75f3cf8ae18f2b054e1eb06
+size 244677
diff --git a/tests/Images/Input/Tiff/tiled_rgba_64bit_little_endian_deflate_compressed_predictor.tiff b/tests/Images/Input/Tiff/tiled_rgba_64bit_little_endian_deflate_compressed_predictor.tiff
new file mode 100644
index 0000000000..bcd96a88bb
--- /dev/null
+++ b/tests/Images/Input/Tiff/tiled_rgba_64bit_little_endian_deflate_compressed_predictor.tiff
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:ee63d8b0d63fd091390678a4a2600df5c14a122002a4d9c93e7d01082a2ee347
+size 220045
diff --git a/tests/Images/Input/Tiff/tiled_rgba_64bit_little_endian_lzw_compressed_predictor.tiff b/tests/Images/Input/Tiff/tiled_rgba_64bit_little_endian_lzw_compressed_predictor.tiff
new file mode 100644
index 0000000000..456f57cbd6
--- /dev/null
+++ b/tests/Images/Input/Tiff/tiled_rgba_64bit_little_endian_lzw_compressed_predictor.tiff
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:d8e05d9ca953045d732c4304575588d2db2ead50177b2ed9416922568760ee1f
+size 244625
diff --git a/tests/Images/Input/Tiff/tiled_rgba_deflate_compressed_predictor.tiff b/tests/Images/Input/Tiff/tiled_rgba_deflate_compressed_predictor.tiff
new file mode 100644
index 0000000000..79bf1f6b76
--- /dev/null
+++ b/tests/Images/Input/Tiff/tiled_rgba_deflate_compressed_predictor.tiff
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:c0a3ecf077c701f450ce363633583134a79fd9d4d91fff0bd79f4bebe5f18649
+size 185503
diff --git a/tests/Images/Input/Tiff/tiled_rgba_lzw_compressed_predictor.tiff b/tests/Images/Input/Tiff/tiled_rgba_lzw_compressed_predictor.tiff
new file mode 100644
index 0000000000..6cc0f28dc7
--- /dev/null
+++ b/tests/Images/Input/Tiff/tiled_rgba_lzw_compressed_predictor.tiff
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:183e011bc22048d65cd1945d60dc25dc9cb688d9141afefa1c66ae0edfca8309
+size 202825