|
|
@ -16,7 +16,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Compression; |
|
|
internal static class HorizontalPredictor |
|
|
internal static class HorizontalPredictor |
|
|
{ |
|
|
{ |
|
|
/// <summary>
|
|
|
/// <summary>
|
|
|
/// Inverts the horizontal prediction.
|
|
|
/// Inverts the horizontal predictor.
|
|
|
/// </summary>
|
|
|
/// </summary>
|
|
|
/// <param name="pixelBytes">Buffer with decompressed pixel data.</param>
|
|
|
/// <param name="pixelBytes">Buffer with decompressed pixel data.</param>
|
|
|
/// <param name="width">The width of the image or strip.</param>
|
|
|
/// <param name="width">The width of the image or strip.</param>
|
|
|
@ -62,6 +62,126 @@ internal static class HorizontalPredictor |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Inverts the horizontal predictor for each tile row.
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="pixelBytes">Buffer with decompressed pixel data for a tile.</param>
|
|
|
|
|
|
/// <param name="tileWidth">Tile width in pixels.</param>
|
|
|
|
|
|
/// <param name="tileHeight">Tile height in pixels.</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 UndoTile(Span<byte> pixelBytes, int tileWidth, int tileHeight, TiffColorType colorType, bool isBigEndian) |
|
|
|
|
|
{ |
|
|
|
|
|
for (int y = 0; y < tileHeight; y++) |
|
|
|
|
|
{ |
|
|
|
|
|
UndoRow(pixelBytes, tileWidth, y, colorType, isBigEndian); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/// <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) |
|
|
|
|
|
{ |
|
|
|
|
|
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<byte> rows, int width, int bitsPerPixel) |
|
|
public static void ApplyHorizontalPrediction(Span<byte> rows, int width, int bitsPerPixel) |
|
|
{ |
|
|
{ |
|
|
if (bitsPerPixel == 8) |
|
|
if (bitsPerPixel == 8) |
|
|
@ -152,14 +272,11 @@ internal static class HorizontalPredictor |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
private static void UndoGray8Bit(Span<byte> pixelBytes, int width) |
|
|
private static void UndoGray8BitRow(Span<byte> pixelBytes, int width, int y) |
|
|
{ |
|
|
{ |
|
|
int rowBytesCount = width; |
|
|
int rowBytesCount = width; |
|
|
int height = pixelBytes.Length / rowBytesCount; |
|
|
int height = pixelBytes.Length / rowBytesCount; |
|
|
for (int y = 0; y < height; y++) |
|
|
|
|
|
{ |
|
|
|
|
|
Span<byte> rowBytes = pixelBytes.Slice(y * rowBytesCount, rowBytesCount); |
|
|
Span<byte> rowBytes = pixelBytes.Slice(y * rowBytesCount, rowBytesCount); |
|
|
|
|
|
|
|
|
byte pixelValue = rowBytes[0]; |
|
|
byte pixelValue = rowBytes[0]; |
|
|
for (int x = 1; x < width; x++) |
|
|
for (int x = 1; x < width; x++) |
|
|
{ |
|
|
{ |
|
|
@ -167,16 +284,21 @@ internal static class HorizontalPredictor |
|
|
rowBytes[x] = pixelValue; |
|
|
rowBytes[x] = pixelValue; |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private static void UndoGray16Bit(Span<byte> pixelBytes, int width, bool isBigEndian) |
|
|
private static void UndoGray8Bit(Span<byte> pixelBytes, int width) |
|
|
{ |
|
|
{ |
|
|
int rowBytesCount = width * 2; |
|
|
int rowBytesCount = width; |
|
|
int height = pixelBytes.Length / rowBytesCount; |
|
|
int height = pixelBytes.Length / rowBytesCount; |
|
|
if (isBigEndian) |
|
|
|
|
|
{ |
|
|
|
|
|
for (int y = 0; y < height; y++) |
|
|
for (int y = 0; y < height; y++) |
|
|
{ |
|
|
{ |
|
|
|
|
|
UndoGray8BitRow(pixelBytes, width, y); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private static void UndoGray16BitBigEndianRow(Span<byte> pixelBytes, int width, int y) |
|
|
|
|
|
{ |
|
|
|
|
|
int rowBytesCount = width * 2; |
|
|
|
|
|
int height = pixelBytes.Length / rowBytesCount; |
|
|
int offset = 0; |
|
|
int offset = 0; |
|
|
Span<byte> rowBytes = pixelBytes.Slice(y * rowBytesCount, rowBytesCount); |
|
|
Span<byte> rowBytes = pixelBytes.Slice(y * rowBytesCount, rowBytesCount); |
|
|
ushort pixelValue = TiffUtilities.ConvertToUShortBigEndian(rowBytes.Slice(offset, 2)); |
|
|
ushort pixelValue = TiffUtilities.ConvertToUShortBigEndian(rowBytes.Slice(offset, 2)); |
|
|
@ -191,11 +313,11 @@ internal static class HorizontalPredictor |
|
|
offset += 2; |
|
|
offset += 2; |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
else |
|
|
private static void UndoGray16BitLittleEndianRow(Span<byte> pixelBytes, int width, int y) |
|
|
{ |
|
|
|
|
|
for (int y = 0; y < height; y++) |
|
|
|
|
|
{ |
|
|
{ |
|
|
|
|
|
int rowBytesCount = width * 2; |
|
|
|
|
|
int height = pixelBytes.Length / rowBytesCount; |
|
|
int offset = 0; |
|
|
int offset = 0; |
|
|
Span<byte> rowBytes = pixelBytes.Slice(y * rowBytesCount, rowBytesCount); |
|
|
Span<byte> rowBytes = pixelBytes.Slice(y * rowBytesCount, rowBytesCount); |
|
|
ushort pixelValue = TiffUtilities.ConvertToUShortLittleEndian(rowBytes.Slice(offset, 2)); |
|
|
ushort pixelValue = TiffUtilities.ConvertToUShortLittleEndian(rowBytes.Slice(offset, 2)); |
|
|
@ -210,17 +332,32 @@ internal static class HorizontalPredictor |
|
|
offset += 2; |
|
|
offset += 2; |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private static void UndoGray32Bit(Span<byte> pixelBytes, int width, bool isBigEndian) |
|
|
private static void UndoGray16Bit(Span<byte> pixelBytes, int width, bool isBigEndian) |
|
|
{ |
|
|
{ |
|
|
int rowBytesCount = width * 4; |
|
|
int rowBytesCount = width * 2; |
|
|
int height = pixelBytes.Length / rowBytesCount; |
|
|
int height = pixelBytes.Length / rowBytesCount; |
|
|
if (isBigEndian) |
|
|
if (isBigEndian) |
|
|
{ |
|
|
{ |
|
|
for (int y = 0; y < height; y++) |
|
|
for (int y = 0; y < height; y++) |
|
|
{ |
|
|
{ |
|
|
|
|
|
UndoGray16BitBigEndianRow(pixelBytes, width, y); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
else |
|
|
|
|
|
{ |
|
|
|
|
|
for (int y = 0; y < height; y++) |
|
|
|
|
|
{ |
|
|
|
|
|
UndoGray16BitLittleEndianRow(pixelBytes, width, y); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private static void UndoGray32BitBigEndianRow(Span<byte> pixelBytes, int width, int y) |
|
|
|
|
|
{ |
|
|
|
|
|
int rowBytesCount = width * 4; |
|
|
|
|
|
int height = pixelBytes.Length / rowBytesCount; |
|
|
|
|
|
|
|
|
int offset = 0; |
|
|
int offset = 0; |
|
|
Span<byte> rowBytes = pixelBytes.Slice(y * rowBytesCount, rowBytesCount); |
|
|
Span<byte> rowBytes = pixelBytes.Slice(y * rowBytesCount, rowBytesCount); |
|
|
uint pixelValue = TiffUtilities.ConvertToUIntBigEndian(rowBytes.Slice(offset, 4)); |
|
|
uint pixelValue = TiffUtilities.ConvertToUIntBigEndian(rowBytes.Slice(offset, 4)); |
|
|
@ -235,11 +372,12 @@ internal static class HorizontalPredictor |
|
|
offset += 4; |
|
|
offset += 4; |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
else |
|
|
private static void UndoGray32BitLittleEndianRow(Span<byte> pixelBytes, int width, int y) |
|
|
{ |
|
|
|
|
|
for (int y = 0; y < height; y++) |
|
|
|
|
|
{ |
|
|
{ |
|
|
|
|
|
int rowBytesCount = width * 4; |
|
|
|
|
|
int height = pixelBytes.Length / rowBytesCount; |
|
|
|
|
|
|
|
|
int offset = 0; |
|
|
int offset = 0; |
|
|
Span<byte> rowBytes = pixelBytes.Slice(y * rowBytesCount, rowBytesCount); |
|
|
Span<byte> rowBytes = pixelBytes.Slice(y * rowBytesCount, rowBytesCount); |
|
|
uint pixelValue = TiffUtilities.ConvertToUIntLittleEndian(rowBytes.Slice(offset, 4)); |
|
|
uint pixelValue = TiffUtilities.ConvertToUIntLittleEndian(rowBytes.Slice(offset, 4)); |
|
|
@ -254,15 +392,30 @@ internal static class HorizontalPredictor |
|
|
offset += 4; |
|
|
offset += 4; |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private static void UndoRgb24Bit(Span<byte> pixelBytes, int width) |
|
|
private static void UndoGray32Bit(Span<byte> pixelBytes, int width, bool isBigEndian) |
|
|
{ |
|
|
{ |
|
|
int rowBytesCount = width * 3; |
|
|
int rowBytesCount = width * 4; |
|
|
int height = pixelBytes.Length / rowBytesCount; |
|
|
int height = pixelBytes.Length / rowBytesCount; |
|
|
|
|
|
if (isBigEndian) |
|
|
|
|
|
{ |
|
|
for (int y = 0; y < height; y++) |
|
|
for (int y = 0; y < height; y++) |
|
|
{ |
|
|
{ |
|
|
|
|
|
UndoGray32BitBigEndianRow(pixelBytes, width, y); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
else |
|
|
|
|
|
{ |
|
|
|
|
|
for (int y = 0; y < height; y++) |
|
|
|
|
|
{ |
|
|
|
|
|
UndoGray32BitLittleEndianRow(pixelBytes, width, y); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private static void UndoRgb24BitRow(Span<byte> pixelBytes, int width, int y) |
|
|
|
|
|
{ |
|
|
|
|
|
int rowBytesCount = width * 3; |
|
|
Span<byte> rowBytes = pixelBytes.Slice(y * rowBytesCount, rowBytesCount); |
|
|
Span<byte> rowBytes = pixelBytes.Slice(y * rowBytesCount, rowBytesCount); |
|
|
Span<Rgb24> rowRgb = MemoryMarshal.Cast<byte, Rgb24>(rowBytes)[..width]; |
|
|
Span<Rgb24> rowRgb = MemoryMarshal.Cast<byte, Rgb24>(rowBytes)[..width]; |
|
|
ref Rgb24 rowRgbBase = ref MemoryMarshal.GetReference(rowRgb); |
|
|
ref Rgb24 rowRgbBase = ref MemoryMarshal.GetReference(rowRgb); |
|
|
@ -279,14 +432,21 @@ internal static class HorizontalPredictor |
|
|
pixel = new Rgb24(r, g, b); |
|
|
pixel = new Rgb24(r, g, b); |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private static void UndoRgba32Bit(Span<byte> pixelBytes, int width) |
|
|
private static void UndoRgb24Bit(Span<byte> pixelBytes, int width) |
|
|
{ |
|
|
{ |
|
|
int rowBytesCount = width * 4; |
|
|
int rowBytesCount = width * 3; |
|
|
int height = pixelBytes.Length / rowBytesCount; |
|
|
int height = pixelBytes.Length / rowBytesCount; |
|
|
for (int y = 0; y < height; y++) |
|
|
for (int y = 0; y < height; y++) |
|
|
{ |
|
|
{ |
|
|
|
|
|
UndoRgb24BitRow(pixelBytes, width, y); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private static void UndoRgba32BitRow(Span<byte> pixelBytes, int width, int y) |
|
|
|
|
|
{ |
|
|
|
|
|
int rowBytesCount = width * 4; |
|
|
|
|
|
|
|
|
Span<byte> rowBytes = pixelBytes.Slice(y * rowBytesCount, rowBytesCount); |
|
|
Span<byte> rowBytes = pixelBytes.Slice(y * rowBytesCount, rowBytesCount); |
|
|
Span<Rgba32> rowRgb = MemoryMarshal.Cast<byte, Rgba32>(rowBytes)[..width]; |
|
|
Span<Rgba32> rowRgb = MemoryMarshal.Cast<byte, Rgba32>(rowBytes)[..width]; |
|
|
ref Rgba32 rowRgbBase = ref MemoryMarshal.GetReference(rowRgb); |
|
|
ref Rgba32 rowRgbBase = ref MemoryMarshal.GetReference(rowRgb); |
|
|
@ -305,16 +465,22 @@ internal static class HorizontalPredictor |
|
|
pixel = new Rgba32(r, g, b, a); |
|
|
pixel = new Rgba32(r, g, b, a); |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private static void UndoRgb48Bit(Span<byte> pixelBytes, int width, bool isBigEndian) |
|
|
private static void UndoRgba32Bit(Span<byte> pixelBytes, int width) |
|
|
{ |
|
|
{ |
|
|
int rowBytesCount = width * 6; |
|
|
int rowBytesCount = width * 4; |
|
|
int height = pixelBytes.Length / rowBytesCount; |
|
|
int height = pixelBytes.Length / rowBytesCount; |
|
|
if (isBigEndian) |
|
|
|
|
|
{ |
|
|
|
|
|
for (int y = 0; y < height; y++) |
|
|
for (int y = 0; y < height; y++) |
|
|
{ |
|
|
{ |
|
|
|
|
|
UndoRgba32BitRow(pixelBytes, width, y); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private static void UndoRgb48BitBigEndianRow(Span<byte> pixelBytes, int width, int y) |
|
|
|
|
|
{ |
|
|
|
|
|
int rowBytesCount = width * 6; |
|
|
|
|
|
int height = pixelBytes.Length / rowBytesCount; |
|
|
|
|
|
|
|
|
int offset = 0; |
|
|
int offset = 0; |
|
|
Span<byte> rowBytes = pixelBytes.Slice(y * rowBytesCount, rowBytesCount); |
|
|
Span<byte> rowBytes = pixelBytes.Slice(y * rowBytesCount, rowBytesCount); |
|
|
ushort r = TiffUtilities.ConvertToUShortBigEndian(rowBytes.Slice(offset, 2)); |
|
|
ushort r = TiffUtilities.ConvertToUShortBigEndian(rowBytes.Slice(offset, 2)); |
|
|
@ -345,11 +511,12 @@ internal static class HorizontalPredictor |
|
|
offset += 2; |
|
|
offset += 2; |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
else |
|
|
private static void UndoRgb48BitLittleEndianRow(Span<byte> pixelBytes, int width, int y) |
|
|
{ |
|
|
|
|
|
for (int y = 0; y < height; y++) |
|
|
|
|
|
{ |
|
|
{ |
|
|
|
|
|
int rowBytesCount = width * 6; |
|
|
|
|
|
int height = pixelBytes.Length / rowBytesCount; |
|
|
|
|
|
|
|
|
int offset = 0; |
|
|
int offset = 0; |
|
|
Span<byte> rowBytes = pixelBytes.Slice(y * rowBytesCount, rowBytesCount); |
|
|
Span<byte> rowBytes = pixelBytes.Slice(y * rowBytesCount, rowBytesCount); |
|
|
ushort r = TiffUtilities.ConvertToUShortLittleEndian(rowBytes.Slice(offset, 2)); |
|
|
ushort r = TiffUtilities.ConvertToUShortLittleEndian(rowBytes.Slice(offset, 2)); |
|
|
@ -380,18 +547,32 @@ internal static class HorizontalPredictor |
|
|
offset += 2; |
|
|
offset += 2; |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private static void UndoRgba64Bit(Span<byte> pixelBytes, int width, bool isBigEndian) |
|
|
private static void UndoRgb48Bit(Span<byte> pixelBytes, int width, bool isBigEndian) |
|
|
{ |
|
|
{ |
|
|
int rowBytesCount = width * 8; |
|
|
int rowBytesCount = width * 6; |
|
|
int height = pixelBytes.Length / rowBytesCount; |
|
|
int height = pixelBytes.Length / rowBytesCount; |
|
|
if (isBigEndian) |
|
|
if (isBigEndian) |
|
|
{ |
|
|
{ |
|
|
for (int y = 0; y < height; y++) |
|
|
for (int y = 0; y < height; y++) |
|
|
{ |
|
|
{ |
|
|
|
|
|
UndoRgb48BitBigEndianRow(pixelBytes, width, y); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
else |
|
|
|
|
|
{ |
|
|
|
|
|
for (int y = 0; y < height; y++) |
|
|
|
|
|
{ |
|
|
|
|
|
UndoRgb48BitLittleEndianRow(pixelBytes, width, y); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private static void UndoRgb64BitBigEndianRow(Span<byte> pixelBytes, int width, int y) |
|
|
|
|
|
{ |
|
|
|
|
|
int rowBytesCount = width * 8; |
|
|
int offset = 0; |
|
|
int offset = 0; |
|
|
|
|
|
|
|
|
Span<byte> rowBytes = pixelBytes.Slice(y * rowBytesCount, rowBytesCount); |
|
|
Span<byte> rowBytes = pixelBytes.Slice(y * rowBytesCount, rowBytesCount); |
|
|
ushort r = TiffUtilities.ConvertToUShortBigEndian(rowBytes.Slice(offset, 2)); |
|
|
ushort r = TiffUtilities.ConvertToUShortBigEndian(rowBytes.Slice(offset, 2)); |
|
|
offset += 2; |
|
|
offset += 2; |
|
|
@ -429,12 +610,12 @@ internal static class HorizontalPredictor |
|
|
offset += 2; |
|
|
offset += 2; |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
else |
|
|
private static void UndoRgb64BitLittleEndianRow(Span<byte> pixelBytes, int width, int y) |
|
|
{ |
|
|
|
|
|
for (int y = 0; y < height; y++) |
|
|
|
|
|
{ |
|
|
{ |
|
|
|
|
|
int rowBytesCount = width * 8; |
|
|
int offset = 0; |
|
|
int offset = 0; |
|
|
|
|
|
|
|
|
Span<byte> rowBytes = pixelBytes.Slice(y * rowBytesCount, rowBytesCount); |
|
|
Span<byte> rowBytes = pixelBytes.Slice(y * rowBytesCount, rowBytesCount); |
|
|
ushort r = TiffUtilities.ConvertToUShortLittleEndian(rowBytes.Slice(offset, 2)); |
|
|
ushort r = TiffUtilities.ConvertToUShortLittleEndian(rowBytes.Slice(offset, 2)); |
|
|
offset += 2; |
|
|
offset += 2; |
|
|
@ -472,17 +653,31 @@ internal static class HorizontalPredictor |
|
|
offset += 2; |
|
|
offset += 2; |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private static void UndoRgb96Bit(Span<byte> pixelBytes, int width, bool isBigEndian) |
|
|
private static void UndoRgba64Bit(Span<byte> pixelBytes, int width, bool isBigEndian) |
|
|
{ |
|
|
{ |
|
|
int rowBytesCount = width * 12; |
|
|
int rowBytesCount = width * 8; |
|
|
int height = pixelBytes.Length / rowBytesCount; |
|
|
int height = pixelBytes.Length / rowBytesCount; |
|
|
if (isBigEndian) |
|
|
if (isBigEndian) |
|
|
{ |
|
|
{ |
|
|
for (int y = 0; y < height; y++) |
|
|
for (int y = 0; y < height; y++) |
|
|
{ |
|
|
{ |
|
|
|
|
|
UndoRgb64BitBigEndianRow(pixelBytes, width, y); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
else |
|
|
|
|
|
{ |
|
|
|
|
|
for (int y = 0; y < height; y++) |
|
|
|
|
|
{ |
|
|
|
|
|
UndoRgb64BitLittleEndianRow(pixelBytes, width, y); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private static void UndoRgb96BitBigEndianRow(Span<byte> pixelBytes, int width, int y) |
|
|
|
|
|
{ |
|
|
|
|
|
int rowBytesCount = width * 12; |
|
|
|
|
|
|
|
|
int offset = 0; |
|
|
int offset = 0; |
|
|
Span<byte> rowBytes = pixelBytes.Slice(y * rowBytesCount, rowBytesCount); |
|
|
Span<byte> rowBytes = pixelBytes.Slice(y * rowBytesCount, rowBytesCount); |
|
|
uint r = TiffUtilities.ConvertToUIntBigEndian(rowBytes.Slice(offset, 4)); |
|
|
uint r = TiffUtilities.ConvertToUIntBigEndian(rowBytes.Slice(offset, 4)); |
|
|
@ -513,11 +708,11 @@ internal static class HorizontalPredictor |
|
|
offset += 4; |
|
|
offset += 4; |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
else |
|
|
private static void UndoRgb96BitLittleEndianRow(Span<byte> pixelBytes, int width, int y) |
|
|
{ |
|
|
|
|
|
for (int y = 0; y < height; y++) |
|
|
|
|
|
{ |
|
|
{ |
|
|
|
|
|
int rowBytesCount = width * 12; |
|
|
|
|
|
|
|
|
int offset = 0; |
|
|
int offset = 0; |
|
|
Span<byte> rowBytes = pixelBytes.Slice(y * rowBytesCount, rowBytesCount); |
|
|
Span<byte> rowBytes = pixelBytes.Slice(y * rowBytesCount, rowBytesCount); |
|
|
uint r = TiffUtilities.ConvertToUIntLittleEndian(rowBytes.Slice(offset, 4)); |
|
|
uint r = TiffUtilities.ConvertToUIntLittleEndian(rowBytes.Slice(offset, 4)); |
|
|
@ -548,17 +743,31 @@ internal static class HorizontalPredictor |
|
|
offset += 4; |
|
|
offset += 4; |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private static void UndoRgba128Bit(Span<byte> pixelBytes, int width, bool isBigEndian) |
|
|
private static void UndoRgb96Bit(Span<byte> pixelBytes, int width, bool isBigEndian) |
|
|
{ |
|
|
{ |
|
|
int rowBytesCount = width * 16; |
|
|
int rowBytesCount = width * 12; |
|
|
int height = pixelBytes.Length / rowBytesCount; |
|
|
int height = pixelBytes.Length / rowBytesCount; |
|
|
if (isBigEndian) |
|
|
if (isBigEndian) |
|
|
{ |
|
|
{ |
|
|
for (int y = 0; y < height; y++) |
|
|
for (int y = 0; y < height; y++) |
|
|
{ |
|
|
{ |
|
|
|
|
|
UndoRgb96BitBigEndianRow(pixelBytes, width, y); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
else |
|
|
|
|
|
{ |
|
|
|
|
|
for (int y = 0; y < height; y++) |
|
|
|
|
|
{ |
|
|
|
|
|
UndoRgb96BitLittleEndianRow(pixelBytes, width, y); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private static void UndoRgba128BitBigEndianRow(Span<byte> pixelBytes, int width, int y) |
|
|
|
|
|
{ |
|
|
|
|
|
int rowBytesCount = width * 16; |
|
|
|
|
|
|
|
|
int offset = 0; |
|
|
int offset = 0; |
|
|
Span<byte> rowBytes = pixelBytes.Slice(y * rowBytesCount, rowBytesCount); |
|
|
Span<byte> rowBytes = pixelBytes.Slice(y * rowBytesCount, rowBytesCount); |
|
|
uint r = TiffUtilities.ConvertToUIntBigEndian(rowBytes.Slice(offset, 4)); |
|
|
uint r = TiffUtilities.ConvertToUIntBigEndian(rowBytes.Slice(offset, 4)); |
|
|
@ -597,11 +806,11 @@ internal static class HorizontalPredictor |
|
|
offset += 4; |
|
|
offset += 4; |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
else |
|
|
private static void UndoRgba128BitLittleEndianRow(Span<byte> pixelBytes, int width, int y) |
|
|
{ |
|
|
|
|
|
for (int y = 0; y < height; y++) |
|
|
|
|
|
{ |
|
|
{ |
|
|
|
|
|
int rowBytesCount = width * 16; |
|
|
|
|
|
|
|
|
int offset = 0; |
|
|
int offset = 0; |
|
|
Span<byte> rowBytes = pixelBytes.Slice(y * rowBytesCount, rowBytesCount); |
|
|
Span<byte> rowBytes = pixelBytes.Slice(y * rowBytesCount, rowBytesCount); |
|
|
uint r = TiffUtilities.ConvertToUIntLittleEndian(rowBytes.Slice(offset, 4)); |
|
|
uint r = TiffUtilities.ConvertToUIntLittleEndian(rowBytes.Slice(offset, 4)); |
|
|
@ -640,6 +849,24 @@ internal static class HorizontalPredictor |
|
|
offset += 4; |
|
|
offset += 4; |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private static void UndoRgba128Bit(Span<byte> pixelBytes, int width, bool isBigEndian) |
|
|
|
|
|
{ |
|
|
|
|
|
int rowBytesCount = width * 16; |
|
|
|
|
|
int height = pixelBytes.Length / rowBytesCount; |
|
|
|
|
|
if (isBigEndian) |
|
|
|
|
|
{ |
|
|
|
|
|
for (int y = 0; y < height; y++) |
|
|
|
|
|
{ |
|
|
|
|
|
UndoRgba128BitBigEndianRow(pixelBytes, width, y); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
else |
|
|
|
|
|
{ |
|
|
|
|
|
for (int y = 0; y < height; y++) |
|
|
|
|
|
{ |
|
|
|
|
|
UndoRgba128BitLittleEndianRow(pixelBytes, width, y); |
|
|
|
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|