diff --git a/src/ImageSharp/Common/Helpers/Numerics.cs b/src/ImageSharp/Common/Helpers/Numerics.cs
index bfbaa1b31c..301bef297f 100644
--- a/src/ImageSharp/Common/Helpers/Numerics.cs
+++ b/src/ImageSharp/Common/Helpers/Numerics.cs
@@ -75,6 +75,12 @@ public static int LeastCommonMultiple(int a, int b)
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int Modulo8(int x) => x & 7;
+ ///
+ /// Calculates % 8
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static nint Modulo8(nint x) => x & 7;
+
///
/// Fast (x mod m) calculator, with the restriction that
/// should be power of 2.
diff --git a/src/ImageSharp/Formats/Tiff/Compression/BitWriterUtils.cs b/src/ImageSharp/Formats/Tiff/Compression/BitWriterUtils.cs
index 08d1475268..37e2a6efcb 100644
--- a/src/ImageSharp/Formats/Tiff/Compression/BitWriterUtils.cs
+++ b/src/ImageSharp/Formats/Tiff/Compression/BitWriterUtils.cs
@@ -2,21 +2,23 @@
// Licensed under the Apache License, Version 2.0.
using System;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
namespace SixLabors.ImageSharp.Formats.Tiff.Compression
{
internal static class BitWriterUtils
{
- public static void WriteBits(Span buffer, int pos, uint count, byte value)
+ public static void WriteBits(Span buffer, nint pos, nint count, byte value)
{
- int bitPos = pos % 8;
- int bufferPos = pos / 8;
- int startIdx = bufferPos + bitPos;
- int endIdx = (int)(startIdx + count);
+ nint bitPos = Numerics.Modulo8(pos);
+ nint bufferPos = pos / 8;
+ nint startIdx = bufferPos + bitPos;
+ nint endIdx = startIdx + count;
if (value == 1)
{
- for (int i = startIdx; i < endIdx; i++)
+ for (nint i = startIdx; i < endIdx; i++)
{
WriteBit(buffer, bufferPos, bitPos);
@@ -30,7 +32,7 @@ public static void WriteBits(Span buffer, int pos, uint count, byte value)
}
else
{
- for (int i = startIdx; i < endIdx; i++)
+ for (nint i = startIdx; i < endIdx; i++)
{
WriteZeroBit(buffer, bufferPos, bitPos);
@@ -44,8 +46,18 @@ public static void WriteBits(Span buffer, int pos, uint count, byte value)
}
}
- public static void WriteBit(Span buffer, int bufferPos, int bitPos) => buffer[bufferPos] |= (byte)(1 << (7 - bitPos));
+ [MethodImpl(InliningOptions.ShortMethod)]
+ public static void WriteBit(Span buffer, nint bufferPos, nint bitPos)
+ {
+ ref byte b = ref Unsafe.Add(ref MemoryMarshal.GetReference(buffer), bufferPos);
+ b |= (byte)(1 << (int)(7 - bitPos));
+ }
- public static void WriteZeroBit(Span buffer, int bufferPos, int bitPos) => buffer[bufferPos] = (byte)(buffer[bufferPos] & ~(1 << (7 - bitPos)));
+ [MethodImpl(InliningOptions.ShortMethod)]
+ public static void WriteZeroBit(Span buffer, nint bufferPos, nint bitPos)
+ {
+ ref byte b = ref Unsafe.Add(ref MemoryMarshal.GetReference(buffer), bufferPos);
+ b = (byte)(b & ~(1 << (int)(7 - bitPos)));
+ }
}
}
diff --git a/src/ImageSharp/Formats/Tiff/Compression/Compressors/TiffCcittCompressor.cs b/src/ImageSharp/Formats/Tiff/Compression/Compressors/TiffCcittCompressor.cs
index 3166106216..f92cf1822a 100644
--- a/src/ImageSharp/Formats/Tiff/Compression/Compressors/TiffCcittCompressor.cs
+++ b/src/ImageSharp/Formats/Tiff/Compression/Compressors/TiffCcittCompressor.cs
@@ -23,28 +23,28 @@ internal abstract class TiffCcittCompressor : TiffBaseCompressor
64, 128, 192, 256, 320, 384, 448, 512, 576, 640, 704, 768, 832, 896, 960, 1024, 1088, 1152, 1216, 1280, 1344, 1408, 1472, 1536, 1600, 1664, 1728, 1792, 1856, 1920, 1984, 2048, 2112, 2176, 2240, 2304, 2368, 2432, 2496, 2560
};
- private static readonly Dictionary WhiteLen4TermCodes = new Dictionary()
+ private static readonly Dictionary WhiteLen4TermCodes = new()
{
{ 2, 0x7 }, { 3, 0x8 }, { 4, 0xB }, { 5, 0xC }, { 6, 0xE }, { 7, 0xF }
};
- private static readonly Dictionary WhiteLen5TermCodes = new Dictionary()
+ private static readonly Dictionary WhiteLen5TermCodes = new()
{
{ 8, 0x13 }, { 9, 0x14 }, { 10, 0x7 }, { 11, 0x8 }
};
- private static readonly Dictionary WhiteLen6TermCodes = new Dictionary()
+ private static readonly Dictionary WhiteLen6TermCodes = new()
{
{ 1, 0x7 }, { 12, 0x8 }, { 13, 0x3 }, { 14, 0x34 }, { 15, 0x35 }, { 16, 0x2A }, { 17, 0x2B }
};
- private static readonly Dictionary WhiteLen7TermCodes = new Dictionary()
+ private static readonly Dictionary WhiteLen7TermCodes = new()
{
{ 18, 0x27 }, { 19, 0xC }, { 20, 0x8 }, { 21, 0x17 }, { 22, 0x3 }, { 23, 0x4 }, { 24, 0x28 }, { 25, 0x2B }, { 26, 0x13 },
{ 27, 0x24 }, { 28, 0x18 }
};
- private static readonly Dictionary WhiteLen8TermCodes = new Dictionary()
+ private static readonly Dictionary WhiteLen8TermCodes = new()
{
{ 0, WhiteZeroRunTermCode }, { 29, 0x2 }, { 30, 0x3 }, { 31, 0x1A }, { 32, 0x1B }, { 33, 0x12 }, { 34, 0x13 }, { 35, 0x14 },
{ 36, 0x15 }, { 37, 0x16 }, { 38, 0x17 }, { 39, 0x28 }, { 40, 0x29 }, { 41, 0x2A }, { 42, 0x2B }, { 43, 0x2C }, { 44, 0x2D },
@@ -53,57 +53,57 @@ internal abstract class TiffCcittCompressor : TiffBaseCompressor
{ 63, 0x34 }
};
- private static readonly Dictionary BlackLen2TermCodes = new Dictionary()
+ private static readonly Dictionary BlackLen2TermCodes = new()
{
{ 2, 0x3 }, { 3, 0x2 }
};
- private static readonly Dictionary BlackLen3TermCodes = new Dictionary()
+ private static readonly Dictionary BlackLen3TermCodes = new()
{
{ 1, 0x2 }, { 4, 0x3 }
};
- private static readonly Dictionary BlackLen4TermCodes = new Dictionary()
+ private static readonly Dictionary BlackLen4TermCodes = new()
{
{ 5, 0x3 }, { 6, 0x2 }
};
- private static readonly Dictionary BlackLen5TermCodes = new Dictionary()
+ private static readonly Dictionary BlackLen5TermCodes = new()
{
{ 7, 0x3 }
};
- private static readonly Dictionary BlackLen6TermCodes = new Dictionary()
+ private static readonly Dictionary BlackLen6TermCodes = new()
{
{ 8, 0x5 }, { 9, 0x4 }
};
- private static readonly Dictionary BlackLen7TermCodes = new Dictionary()
+ private static readonly Dictionary BlackLen7TermCodes = new()
{
{ 10, 0x4 }, { 11, 0x5 }, { 12, 0x7 }
};
- private static readonly Dictionary BlackLen8TermCodes = new Dictionary()
+ private static readonly Dictionary BlackLen8TermCodes = new()
{
{ 13, 0x4 }, { 14, 0x7 }
};
- private static readonly Dictionary BlackLen9TermCodes = new Dictionary()
+ private static readonly Dictionary BlackLen9TermCodes = new()
{
{ 15, 0x18 }
};
- private static readonly Dictionary BlackLen10TermCodes = new Dictionary()
+ private static readonly Dictionary BlackLen10TermCodes = new()
{
{ 0, BlackZeroRunTermCode }, { 16, 0x17 }, { 17, 0x18 }, { 18, 0x8 }
};
- private static readonly Dictionary BlackLen11TermCodes = new Dictionary()
+ private static readonly Dictionary BlackLen11TermCodes = new()
{
{ 19, 0x67 }, { 20, 0x68 }, { 21, 0x6C }, { 22, 0x37 }, { 23, 0x28 }, { 24, 0x17 }, { 25, 0x18 }
};
- private static readonly Dictionary BlackLen12TermCodes = new Dictionary()
+ private static readonly Dictionary BlackLen12TermCodes = new()
{
{ 26, 0xCA }, { 27, 0xCB }, { 28, 0xCC }, { 29, 0xCD }, { 30, 0x68 }, { 31, 0x69 }, { 32, 0x6A }, { 33, 0x6B }, { 34, 0xD2 },
{ 35, 0xD3 }, { 36, 0xD4 }, { 37, 0xD5 }, { 38, 0xD6 }, { 39, 0xD7 }, { 40, 0x6C }, { 41, 0x6D }, { 42, 0xDA }, { 43, 0xDB },
@@ -112,62 +112,62 @@ internal abstract class TiffCcittCompressor : TiffBaseCompressor
{ 62, 0x66 }, { 63, 0x67 }
};
- private static readonly Dictionary WhiteLen5MakeupCodes = new Dictionary()
+ private static readonly Dictionary WhiteLen5MakeupCodes = new()
{
{ 64, 0x1B }, { 128, 0x12 }
};
- private static readonly Dictionary WhiteLen6MakeupCodes = new Dictionary()
+ private static readonly Dictionary WhiteLen6MakeupCodes = new()
{
{ 192, 0x17 }, { 1664, 0x18 }
};
- private static readonly Dictionary WhiteLen8MakeupCodes = new Dictionary()
+ private static readonly Dictionary WhiteLen8MakeupCodes = new()
{
{ 320, 0x36 }, { 384, 0x37 }, { 448, 0x64 }, { 512, 0x65 }, { 576, 0x68 }, { 640, 0x67 }
};
- private static readonly Dictionary WhiteLen7MakeupCodes = new Dictionary()
+ private static readonly Dictionary WhiteLen7MakeupCodes = new()
{
{ 256, 0x37 }
};
- private static readonly Dictionary WhiteLen9MakeupCodes = new Dictionary()
+ private static readonly Dictionary WhiteLen9MakeupCodes = new()
{
{ 704, 0xCC }, { 768, 0xCD }, { 832, 0xD2 }, { 896, 0xD3 }, { 960, 0xD4 }, { 1024, 0xD5 }, { 1088, 0xD6 },
{ 1152, 0xD7 }, { 1216, 0xD8 }, { 1280, 0xD9 }, { 1344, 0xDA }, { 1408, 0xDB }, { 1472, 0x98 }, { 1536, 0x99 },
{ 1600, 0x9A }, { 1728, 0x9B }
};
- private static readonly Dictionary WhiteLen11MakeupCodes = new Dictionary()
+ private static readonly Dictionary WhiteLen11MakeupCodes = new()
{
{ 1792, 0x8 }, { 1856, 0xC }, { 1920, 0xD }
};
- private static readonly Dictionary WhiteLen12MakeupCodes = new Dictionary()
+ private static readonly Dictionary WhiteLen12MakeupCodes = new()
{
{ 1984, 0x12 }, { 2048, 0x13 }, { 2112, 0x14 }, { 2176, 0x15 }, { 2240, 0x16 }, { 2304, 0x17 }, { 2368, 0x1C },
{ 2432, 0x1D }, { 2496, 0x1E }, { 2560, 0x1F }
};
- private static readonly Dictionary BlackLen10MakeupCodes = new Dictionary()
+ private static readonly Dictionary BlackLen10MakeupCodes = new()
{
{ 64, 0xF }
};
- private static readonly Dictionary BlackLen11MakeupCodes = new Dictionary()
+ private static readonly Dictionary BlackLen11MakeupCodes = new()
{
{ 1792, 0x8 }, { 1856, 0xC }, { 1920, 0xD }
};
- private static readonly Dictionary BlackLen12MakeupCodes = new Dictionary()
+ private static readonly Dictionary BlackLen12MakeupCodes = new()
{
{ 128, 0xC8 }, { 192, 0xC9 }, { 256, 0x5B }, { 320, 0x33 }, { 384, 0x34 }, { 448, 0x35 },
{ 1984, 0x12 }, { 2048, 0x13 }, { 2112, 0x14 }, { 2176, 0x15 }, { 2240, 0x16 }, { 2304, 0x17 }, { 2368, 0x1C },
{ 2432, 0x1D }, { 2496, 0x1E }, { 2560, 0x1F }
};
- private static readonly Dictionary BlackLen13MakeupCodes = new Dictionary()
+ private static readonly Dictionary BlackLen13MakeupCodes = new()
{
{ 512, 0x6C }, { 576, 0x6D }, { 640, 0x4A }, { 704, 0x4B }, { 768, 0x4C }, { 832, 0x4D }, { 896, 0x72 },
{ 960, 0x73 }, { 1024, 0x74 }, { 1088, 0x75 }, { 1152, 0x76 }, { 1216, 0x77 }, { 1280, 0x52 }, { 1344, 0x53 },
@@ -442,16 +442,16 @@ protected uint GetMakeupCode(uint runLength, out uint codeLength, bool isWhiteRu
}
///
- /// Pads output to the next byte
+ /// Pads output to the next byte.
///
///
/// If the output is not currently on a byte boundary,
- /// zero-pad it to the next byte
+ /// zero-pad it to the next byte.
///
protected void PadByte()
{
// Check if padding is necessary.
- if (this.bitPosition % 8 != 0)
+ if (Numerics.Modulo8(this.bitPosition) != 0)
{
// Skip padding bits, move to next byte.
this.bytePosition++;
diff --git a/src/ImageSharp/Formats/Tiff/Compression/Decompressors/CcittReferenceScanline.cs b/src/ImageSharp/Formats/Tiff/Compression/Decompressors/CcittReferenceScanline.cs
index 0aec2361c3..5b0c64cf18 100644
--- a/src/ImageSharp/Formats/Tiff/Compression/Decompressors/CcittReferenceScanline.cs
+++ b/src/ImageSharp/Formats/Tiff/Compression/Decompressors/CcittReferenceScanline.cs
@@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0.
using System;
+using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.Formats.Tiff.Compression.Decompressors
{
@@ -130,6 +131,7 @@ private int FindB1ForNormalLine(int a0, byte a0Byte)
return index + offset;
}
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
private int FindB2ForImaginaryWhiteLine() => this.width;
private int FindB2ForNormalLine(int b1)
diff --git a/src/ImageSharp/Formats/Tiff/Compression/Decompressors/CcittTwoDimensionalCode.cs b/src/ImageSharp/Formats/Tiff/Compression/Decompressors/CcittTwoDimensionalCode.cs
index 74a17b9075..9543499d7f 100644
--- a/src/ImageSharp/Formats/Tiff/Compression/Decompressors/CcittTwoDimensionalCode.cs
+++ b/src/ImageSharp/Formats/Tiff/Compression/Decompressors/CcittTwoDimensionalCode.cs
@@ -13,15 +13,21 @@ internal readonly struct CcittTwoDimensionalCode
///
/// Initializes a new instance of the struct.
///
- /// The type.
+ /// The code word.
+ /// The type of the code.
/// The bits required.
/// The extension bits.
- public CcittTwoDimensionalCode(CcittTwoDimensionalCodeType type, int bitsRequired, int extensionBits = 0)
- => this.value = (ushort)((byte)type | ((bitsRequired & 0b1111) << 8) | ((extensionBits & 0b111) << 11));
+ public CcittTwoDimensionalCode(int code, CcittTwoDimensionalCodeType type, int bitsRequired, int extensionBits = 0)
+ {
+ this.Code = code;
+ this.value = (ushort)((byte)type | ((bitsRequired & 0b1111) << 8) | ((extensionBits & 0b111) << 11));
+ }
///
/// Gets the code type.
///
public CcittTwoDimensionalCodeType Type => (CcittTwoDimensionalCodeType)(this.value & 0b11111111);
+
+ public int Code { get; }
}
}
diff --git a/src/ImageSharp/Formats/Tiff/Compression/Decompressors/ModifiedHuffmanBitReader.cs b/src/ImageSharp/Formats/Tiff/Compression/Decompressors/ModifiedHuffmanBitReader.cs
index 89cdf7ea2b..8306e91a34 100644
--- a/src/ImageSharp/Formats/Tiff/Compression/Decompressors/ModifiedHuffmanBitReader.cs
+++ b/src/ImageSharp/Formats/Tiff/Compression/Decompressors/ModifiedHuffmanBitReader.cs
@@ -1,9 +1,8 @@
// Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0.
-using System.IO;
using SixLabors.ImageSharp.Formats.Tiff.Constants;
-using SixLabors.ImageSharp.Memory;
+using SixLabors.ImageSharp.IO;
namespace SixLabors.ImageSharp.Formats.Tiff.Compression.Decompressors
{
@@ -19,14 +18,13 @@ internal sealed class ModifiedHuffmanBitReader : T4BitReader
/// The compressed input stream.
/// The logical order of bits within a byte.
/// The number of bytes to read from the stream.
- /// The memory allocator.
- public ModifiedHuffmanBitReader(Stream input, TiffFillOrder fillOrder, int bytesToRead, MemoryAllocator allocator)
- : base(input, fillOrder, bytesToRead, allocator)
+ public ModifiedHuffmanBitReader(BufferedReadStream input, TiffFillOrder fillOrder, int bytesToRead)
+ : base(input, fillOrder, bytesToRead)
{
}
///
- public override bool HasMoreData => this.Position < (ulong)this.DataLength - 1 || ((uint)(this.BitsRead - 1) < (7 - 1));
+ public override bool HasMoreData => this.Position < (ulong)this.DataLength - 1 || (uint)(this.BitsRead - 1) < 6;
///
public override bool IsEndOfScanLine
@@ -53,12 +51,11 @@ public override void StartNewRow()
{
base.StartNewRow();
- int remainder = this.BitsRead & 7; // bit-hack for % 8
+ int remainder = Numerics.Modulo8(this.BitsRead);
if (remainder != 0)
{
// Skip padding bits, move to next byte.
- this.Position++;
- this.ResetBitsRead();
+ this.AdvancePosition();
}
}
diff --git a/src/ImageSharp/Formats/Tiff/Compression/Decompressors/ModifiedHuffmanTiffCompression.cs b/src/ImageSharp/Formats/Tiff/Compression/Decompressors/ModifiedHuffmanTiffCompression.cs
index 453f7d10dd..54c94525c5 100644
--- a/src/ImageSharp/Formats/Tiff/Compression/Decompressors/ModifiedHuffmanTiffCompression.cs
+++ b/src/ImageSharp/Formats/Tiff/Compression/Decompressors/ModifiedHuffmanTiffCompression.cs
@@ -42,11 +42,12 @@ public ModifiedHuffmanTiffCompression(MemoryAllocator allocator, TiffFillOrder f
///
protected override void Decompress(BufferedReadStream stream, int byteCount, int stripHeight, Span buffer)
{
- using var bitReader = new ModifiedHuffmanBitReader(stream, this.FillOrder, byteCount, this.Allocator);
+ var bitReader = new ModifiedHuffmanBitReader(stream, this.FillOrder, byteCount);
buffer.Clear();
- uint bitsWritten = 0;
- uint pixelsWritten = 0;
+ nint bitsWritten = 0;
+ nuint pixelsWritten = 0;
+ nint rowsWritten = 0;
while (bitReader.HasMoreData)
{
bitReader.ReadNextRun();
@@ -55,32 +56,39 @@ protected override void Decompress(BufferedReadStream stream, int byteCount, int
{
if (bitReader.IsWhiteRun)
{
- BitWriterUtils.WriteBits(buffer, (int)bitsWritten, bitReader.RunLength, this.whiteValue);
+ BitWriterUtils.WriteBits(buffer, bitsWritten, (int)bitReader.RunLength, this.whiteValue);
}
else
{
- BitWriterUtils.WriteBits(buffer, (int)bitsWritten, bitReader.RunLength, this.blackValue);
+ BitWriterUtils.WriteBits(buffer, bitsWritten, (int)bitReader.RunLength, this.blackValue);
}
- bitsWritten += bitReader.RunLength;
+ bitsWritten += (int)bitReader.RunLength;
pixelsWritten += bitReader.RunLength;
}
- if (pixelsWritten == this.Width)
+ if (pixelsWritten == (ulong)this.Width)
{
- bitReader.StartNewRow();
+ rowsWritten++;
pixelsWritten = 0;
// Write padding bits, if necessary.
- uint pad = 8 - (bitsWritten % 8);
+ nint pad = 8 - Numerics.Modulo8(bitsWritten);
if (pad != 8)
{
- BitWriterUtils.WriteBits(buffer, (int)bitsWritten, pad, 0);
+ BitWriterUtils.WriteBits(buffer, bitsWritten, pad, 0);
bitsWritten += pad;
}
+
+ if (rowsWritten >= stripHeight)
+ {
+ break;
+ }
+
+ bitReader.StartNewRow();
}
- if (pixelsWritten > this.Width)
+ if (pixelsWritten > (ulong)this.Width)
{
TiffThrowHelper.ThrowImageFormatException("ccitt compression parsing error, decoded more pixels then image width");
}
diff --git a/src/ImageSharp/Formats/Tiff/Compression/Decompressors/PackBitsTiffCompression.cs b/src/ImageSharp/Formats/Tiff/Compression/Decompressors/PackBitsTiffCompression.cs
index 4093d89871..d7bba88fd9 100644
--- a/src/ImageSharp/Formats/Tiff/Compression/Decompressors/PackBitsTiffCompression.cs
+++ b/src/ImageSharp/Formats/Tiff/Compression/Decompressors/PackBitsTiffCompression.cs
@@ -73,7 +73,7 @@ protected override void Decompress(BufferedReadStream stream, int byteCount, int
byte repeatData = compressedData[compressedOffset + 1];
int repeatLength = 257 - headerByte;
- ArrayCopyRepeat(repeatData, buffer, decompressedOffset, repeatLength);
+ buffer.Slice(decompressedOffset, repeatLength).Fill(repeatData);
compressedOffset += 2;
decompressedOffset += repeatLength;
@@ -81,14 +81,6 @@ protected override void Decompress(BufferedReadStream stream, int byteCount, int
}
}
- private static void ArrayCopyRepeat(byte value, Span destinationArray, int destinationIndex, int length)
- {
- for (int i = 0; i < length; i++)
- {
- destinationArray[i + destinationIndex] = value;
- }
- }
-
///
protected override void Dispose(bool disposing) => this.compressedDataMemory?.Dispose();
}
diff --git a/src/ImageSharp/Formats/Tiff/Compression/Decompressors/T4BitReader.cs b/src/ImageSharp/Formats/Tiff/Compression/Decompressors/T4BitReader.cs
index 9925d5a194..226bfe5dad 100644
--- a/src/ImageSharp/Formats/Tiff/Compression/Decompressors/T4BitReader.cs
+++ b/src/ImageSharp/Formats/Tiff/Compression/Decompressors/T4BitReader.cs
@@ -1,20 +1,17 @@
// Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0.
-using System;
-using System.Buffers;
using System.Collections.Generic;
-using System.IO;
using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.Formats.Tiff.Constants;
-using SixLabors.ImageSharp.Memory;
+using SixLabors.ImageSharp.IO;
namespace SixLabors.ImageSharp.Formats.Tiff.Compression.Decompressors
{
///
/// Bitreader for reading compressed CCITT T4 1D data.
///
- internal class T4BitReader : IDisposable
+ internal class T4BitReader
{
///
/// The logical order of bits within a byte.
@@ -52,28 +49,28 @@ internal class T4BitReader : IDisposable
///
private readonly int maxCodeLength = 13;
- private static readonly Dictionary WhiteLen4TermCodes = new Dictionary()
+ private static readonly Dictionary WhiteLen4TermCodes = new()
{
{ 0x7, 2 }, { 0x8, 3 }, { 0xB, 4 }, { 0xC, 5 }, { 0xE, 6 }, { 0xF, 7 }
};
- private static readonly Dictionary WhiteLen5TermCodes = new Dictionary()
+ private static readonly Dictionary WhiteLen5TermCodes = new()
{
{ 0x13, 8 }, { 0x14, 9 }, { 0x7, 10 }, { 0x8, 11 }
};
- private static readonly Dictionary WhiteLen6TermCodes = new Dictionary()
+ private static readonly Dictionary WhiteLen6TermCodes = new()
{
{ 0x7, 1 }, { 0x8, 12 }, { 0x3, 13 }, { 0x34, 14 }, { 0x35, 15 }, { 0x2A, 16 }, { 0x2B, 17 }
};
- private static readonly Dictionary WhiteLen7TermCodes = new Dictionary()
+ private static readonly Dictionary WhiteLen7TermCodes = new()
{
{ 0x27, 18 }, { 0xC, 19 }, { 0x8, 20 }, { 0x17, 21 }, { 0x3, 22 }, { 0x4, 23 }, { 0x28, 24 }, { 0x2B, 25 }, { 0x13, 26 },
{ 0x24, 27 }, { 0x18, 28 }
};
- private static readonly Dictionary WhiteLen8TermCodes = new Dictionary()
+ private static readonly Dictionary WhiteLen8TermCodes = new()
{
{ 0x35, 0 }, { 0x2, 29 }, { 0x3, 30 }, { 0x1A, 31 }, { 0x1B, 32 }, { 0x12, 33 }, { 0x13, 34 }, { 0x14, 35 }, { 0x15, 36 },
{ 0x16, 37 }, { 0x17, 38 }, { 0x28, 39 }, { 0x29, 40 }, { 0x2A, 41 }, { 0x2B, 42 }, { 0x2C, 43 }, { 0x2D, 44 }, { 0x4, 45 },
@@ -81,57 +78,57 @@ internal class T4BitReader : IDisposable
{ 0x58, 55 }, { 0x59, 56 }, { 0x5A, 57 }, { 0x5B, 58 }, { 0x4A, 59 }, { 0x4B, 60 }, { 0x32, 61 }, { 0x33, 62 }, { 0x34, 63 }
};
- private static readonly Dictionary BlackLen2TermCodes = new Dictionary()
+ private static readonly Dictionary BlackLen2TermCodes = new()
{
{ 0x3, 2 }, { 0x2, 3 }
};
- private static readonly Dictionary BlackLen3TermCodes = new Dictionary()
+ private static readonly Dictionary BlackLen3TermCodes = new()
{
{ 0x2, 1 }, { 0x3, 4 }
};
- private static readonly Dictionary BlackLen4TermCodes = new Dictionary()
+ private static readonly Dictionary BlackLen4TermCodes = new()
{
{ 0x3, 5 }, { 0x2, 6 }
};
- private static readonly Dictionary BlackLen5TermCodes = new Dictionary()
+ private static readonly Dictionary BlackLen5TermCodes = new()
{
{ 0x3, 7 }
};
- private static readonly Dictionary BlackLen6TermCodes = new Dictionary()
+ private static readonly Dictionary BlackLen6TermCodes = new()
{
{ 0x5, 8 }, { 0x4, 9 }
};
- private static readonly Dictionary BlackLen7TermCodes = new Dictionary()
+ private static readonly Dictionary BlackLen7TermCodes = new()
{
{ 0x4, 10 }, { 0x5, 11 }, { 0x7, 12 }
};
- private static readonly Dictionary BlackLen8TermCodes = new Dictionary()
+ private static readonly Dictionary BlackLen8TermCodes = new()
{
{ 0x4, 13 }, { 0x7, 14 }
};
- private static readonly Dictionary BlackLen9TermCodes = new Dictionary()
+ private static readonly Dictionary BlackLen9TermCodes = new()
{
{ 0x18, 15 }
};
- private static readonly Dictionary BlackLen10TermCodes = new Dictionary()
+ private static readonly Dictionary BlackLen10TermCodes = new()
{
{ 0x37, 0 }, { 0x17, 16 }, { 0x18, 17 }, { 0x8, 18 }
};
- private static readonly Dictionary BlackLen11TermCodes = new Dictionary()
+ private static readonly Dictionary BlackLen11TermCodes = new()
{
{ 0x67, 19 }, { 0x68, 20 }, { 0x6C, 21 }, { 0x37, 22 }, { 0x28, 23 }, { 0x17, 24 }, { 0x18, 25 }
};
- private static readonly Dictionary BlackLen12TermCodes = new Dictionary()
+ private static readonly Dictionary BlackLen12TermCodes = new()
{
{ 0xCA, 26 }, { 0xCB, 27 }, { 0xCC, 28 }, { 0xCD, 29 }, { 0x68, 30 }, { 0x69, 31 }, { 0x6A, 32 }, { 0x6B, 33 }, { 0xD2, 34 },
{ 0xD3, 35 }, { 0xD4, 36 }, { 0xD5, 37 }, { 0xD6, 38 }, { 0xD7, 39 }, { 0x6C, 40 }, { 0x6D, 41 }, { 0xDA, 42 }, { 0xDB, 43 },
@@ -140,82 +137,84 @@ internal class T4BitReader : IDisposable
{ 0x66, 62 }, { 0x67, 63 }
};
- private static readonly Dictionary WhiteLen5MakeupCodes = new Dictionary()
+ private static readonly Dictionary WhiteLen5MakeupCodes = new()
{
{ 0x1B, 64 }, { 0x12, 128 }
};
- private static readonly Dictionary WhiteLen6MakeupCodes = new Dictionary()
+ private static readonly Dictionary WhiteLen6MakeupCodes = new()
{
{ 0x17, 192 }, { 0x18, 1664 }
};
- private static readonly Dictionary WhiteLen8MakeupCodes = new Dictionary()
+ private static readonly Dictionary WhiteLen8MakeupCodes = new()
{
{ 0x36, 320 }, { 0x37, 384 }, { 0x64, 448 }, { 0x65, 512 }, { 0x68, 576 }, { 0x67, 640 }
};
- private static readonly Dictionary WhiteLen7MakeupCodes = new Dictionary()
+ private static readonly Dictionary WhiteLen7MakeupCodes = new()
{
{ 0x37, 256 }
};
- private static readonly Dictionary WhiteLen9MakeupCodes = new Dictionary()
+ private static readonly Dictionary WhiteLen9MakeupCodes = new()
{
{ 0xCC, 704 }, { 0xCD, 768 }, { 0xD2, 832 }, { 0xD3, 896 }, { 0xD4, 960 }, { 0xD5, 1024 }, { 0xD6, 1088 },
{ 0xD7, 1152 }, { 0xD8, 1216 }, { 0xD9, 1280 }, { 0xDA, 1344 }, { 0xDB, 1408 }, { 0x98, 1472 }, { 0x99, 1536 },
{ 0x9A, 1600 }, { 0x9B, 1728 }
};
- private static readonly Dictionary WhiteLen11MakeupCodes = new Dictionary()
+ private static readonly Dictionary WhiteLen11MakeupCodes = new()
{
{ 0x8, 1792 }, { 0xC, 1856 }, { 0xD, 1920 }
};
- private static readonly Dictionary WhiteLen12MakeupCodes = new Dictionary()
+ private static readonly Dictionary WhiteLen12MakeupCodes = new()
{
{ 0x12, 1984 }, { 0x13, 2048 }, { 0x14, 2112 }, { 0x15, 2176 }, { 0x16, 2240 }, { 0x17, 2304 }, { 0x1C, 2368 },
{ 0x1D, 2432 }, { 0x1E, 2496 }, { 0x1F, 2560 }
};
- private static readonly Dictionary BlackLen10MakeupCodes = new Dictionary()
+ private static readonly Dictionary BlackLen10MakeupCodes = new()
{
{ 0xF, 64 }
};
- private static readonly Dictionary BlackLen11MakeupCodes = new Dictionary()
+ private static readonly Dictionary BlackLen11MakeupCodes = new()
{
{ 0x8, 1792 }, { 0xC, 1856 }, { 0xD, 1920 }
};
- private static readonly Dictionary BlackLen12MakeupCodes = new Dictionary()
+ private static readonly Dictionary BlackLen12MakeupCodes = new()
{
{ 0xC8, 128 }, { 0xC9, 192 }, { 0x5B, 256 }, { 0x33, 320 }, { 0x34, 384 }, { 0x35, 448 },
{ 0x12, 1984 }, { 0x13, 2048 }, { 0x14, 2112 }, { 0x15, 2176 }, { 0x16, 2240 }, { 0x17, 2304 }, { 0x1C, 2368 },
{ 0x1D, 2432 }, { 0x1E, 2496 }, { 0x1F, 2560 }
};
- private static readonly Dictionary BlackLen13MakeupCodes = new Dictionary()
+ private static readonly Dictionary BlackLen13MakeupCodes = new()
{
{ 0x6C, 512 }, { 0x6D, 576 }, { 0x4A, 640 }, { 0x4B, 704 }, { 0x4C, 768 }, { 0x4D, 832 }, { 0x72, 896 },
{ 0x73, 960 }, { 0x74, 1024 }, { 0x75, 1088 }, { 0x76, 1152 }, { 0x77, 1216 }, { 0x52, 1280 }, { 0x53, 1344 },
{ 0x54, 1408 }, { 0x55, 1472 }, { 0x5A, 1536 }, { 0x5B, 1600 }, { 0x64, 1664 }, { 0x65, 1728 }
};
+ ///
+ /// The compressed input stream.
+ ///
+ private readonly BufferedReadStream stream;
+
///
/// Initializes a new instance of the class.
///
/// The compressed input stream.
/// The logical order of bits within a byte.
/// The number of bytes to read from the stream.
- /// The memory allocator.
/// Indicates, if fill bits have been added as necessary before EOL codes such that EOL always ends on a byte boundary. Defaults to false.
- public T4BitReader(Stream input, TiffFillOrder fillOrder, int bytesToRead, MemoryAllocator allocator, bool eolPadding = false)
+ public T4BitReader(BufferedReadStream input, TiffFillOrder fillOrder, int bytesToRead, bool eolPadding = false)
{
+ this.stream = input;
this.fillOrder = fillOrder;
- this.Data = allocator.Allocate(bytesToRead);
- this.ReadImageDataFromStream(input, bytesToRead);
-
this.DataLength = bytesToRead;
this.BitsRead = 0;
this.Value = 0;
@@ -228,12 +227,19 @@ public T4BitReader(Stream input, TiffFillOrder fillOrder, int bytesToRead, Memor
this.RunLength = 0;
this.eolPadding = eolPadding;
+ this.ReadNextByte();
+
if (this.eolPadding)
{
this.maxCodeLength = 24;
}
}
+ ///
+ /// Gets or sets the byte at the given position.
+ ///
+ private byte DataAtPosition { get; set; }
+
///
/// Gets the current value.
///
@@ -259,11 +265,6 @@ public T4BitReader(Stream input, TiffFillOrder fillOrder, int bytesToRead, Memor
///
protected ulong Position { get; set; }
- ///
- /// Gets the compressed image data.
- ///
- public IMemoryOwner Data { get; }
-
///
/// Gets a value indicating whether there is more data to read left.
///
@@ -390,9 +391,6 @@ public virtual void StartNewRow()
this.terminationCodeFound = false;
}
- ///
- public void Dispose() => this.Data.Dispose();
-
///
/// An EOL is expected before the first data.
///
@@ -436,6 +434,7 @@ protected void Reset(bool resetRunLength = true)
///
/// The number of bits to read.
/// The value read.
+ [MethodImpl(InliningOptions.ShortMethod)]
protected uint ReadValue(int nBits)
{
DebugGuard.MustBeGreaterThan(nBits, 0, nameof(nBits));
@@ -452,6 +451,20 @@ protected uint ReadValue(int nBits)
return v;
}
+ ///
+ /// Advances the position by one byte.
+ ///
+ /// True, if data could be advanced by one byte, otherwise false.
+ protected bool AdvancePosition()
+ {
+ if (this.LoadNewByte())
+ {
+ return true;
+ }
+
+ return false;
+ }
+
private uint WhiteTerminatingCodeRunLength()
{
switch (this.CurValueBitsRead)
@@ -806,44 +819,49 @@ private bool IsBlackTerminatingCode()
return false;
}
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
private uint GetBit()
{
if (this.BitsRead >= 8)
{
- this.LoadNewByte();
+ this.AdvancePosition();
}
- Span dataSpan = this.Data.GetSpan();
int shift = 8 - this.BitsRead - 1;
- uint bit = (uint)((dataSpan[(int)this.Position] & (1 << shift)) != 0 ? 1 : 0);
+ uint bit = (uint)((this.DataAtPosition & (1 << shift)) != 0 ? 1 : 0);
this.BitsRead++;
return bit;
}
- private void LoadNewByte()
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private bool LoadNewByte()
{
- this.Position++;
- this.ResetBitsRead();
-
- if (this.Position >= (ulong)this.DataLength)
+ if (this.Position < (ulong)this.DataLength)
{
- TiffThrowHelper.ThrowImageFormatException("tiff image has invalid ccitt compressed data");
+ this.ReadNextByte();
+ this.Position++;
+ return true;
}
+
+ this.Position++;
+ this.DataAtPosition = 0;
+ return false;
}
- private void ReadImageDataFromStream(Stream input, int bytesToRead)
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private void ReadNextByte()
{
- Span dataSpan = this.Data.GetSpan();
- input.Read(dataSpan, 0, bytesToRead);
-
- if (this.fillOrder == TiffFillOrder.LeastSignificantBitFirst)
+ int nextByte = this.stream.ReadByte();
+ if (nextByte == -1)
{
- for (int i = 0; i < dataSpan.Length; i++)
- {
- dataSpan[i] = ReverseBits(dataSpan[i]);
- }
+ TiffThrowHelper.ThrowImageFormatException("Tiff fax compression error: not enough data.");
}
+
+ this.ResetBitsRead();
+ this.DataAtPosition = this.fillOrder == TiffFillOrder.LeastSignificantBitFirst
+ ? ReverseBits((byte)nextByte)
+ : (byte)nextByte;
}
// http://graphics.stanford.edu/~seander/bithacks.html#ReverseByteWith64Bits
diff --git a/src/ImageSharp/Formats/Tiff/Compression/Decompressors/T4TiffCompression.cs b/src/ImageSharp/Formats/Tiff/Compression/Decompressors/T4TiffCompression.cs
index 158cac9471..7b59e71173 100644
--- a/src/ImageSharp/Formats/Tiff/Compression/Decompressors/T4TiffCompression.cs
+++ b/src/ImageSharp/Formats/Tiff/Compression/Decompressors/T4TiffCompression.cs
@@ -61,11 +61,12 @@ protected override void Decompress(BufferedReadStream stream, int byteCount, int
}
bool eolPadding = this.faxCompressionOptions.HasFlag(FaxCompressionOptions.EolPadding);
- using var bitReader = new T4BitReader(stream, this.FillOrder, byteCount, this.Allocator, eolPadding);
+ var bitReader = new T4BitReader(stream, this.FillOrder, byteCount, eolPadding);
buffer.Clear();
- uint bitsWritten = 0;
- uint pixelWritten = 0;
+ nint bitsWritten = 0;
+ nuint pixelsWritten = 0;
+ nint rowsWritten = 0;
while (bitReader.HasMoreData)
{
bitReader.ReadNextRun();
@@ -74,41 +75,47 @@ protected override void Decompress(BufferedReadStream stream, int byteCount, int
{
this.WritePixelRun(buffer, bitReader, bitsWritten);
- bitsWritten += bitReader.RunLength;
- pixelWritten += bitReader.RunLength;
+ bitsWritten += (int)bitReader.RunLength;
+ pixelsWritten += bitReader.RunLength;
}
if (bitReader.IsEndOfScanLine)
{
// Write padding bytes, if necessary.
- uint pad = 8 - (bitsWritten % 8);
+ nint pad = 8 - Numerics.Modulo8(bitsWritten);
if (pad != 8)
{
- BitWriterUtils.WriteBits(buffer, (int)bitsWritten, pad, 0);
+ BitWriterUtils.WriteBits(buffer, bitsWritten, pad, 0);
bitsWritten += pad;
}
- pixelWritten = 0;
+ pixelsWritten = 0;
+ rowsWritten++;
+
+ if (rowsWritten >= stripHeight)
+ {
+ break;
+ }
}
}
// Edge case for when we are at the last byte, but there are still some unwritten pixels left.
- if (pixelWritten > 0 && pixelWritten < this.width)
+ if (pixelsWritten > 0 && pixelsWritten < (ulong)this.width)
{
bitReader.ReadNextRun();
this.WritePixelRun(buffer, bitReader, bitsWritten);
}
}
- private void WritePixelRun(Span buffer, T4BitReader bitReader, uint bitsWritten)
+ private void WritePixelRun(Span buffer, T4BitReader bitReader, nint bitsWritten)
{
if (bitReader.IsWhiteRun)
{
- BitWriterUtils.WriteBits(buffer, (int)bitsWritten, bitReader.RunLength, this.whiteValue);
+ BitWriterUtils.WriteBits(buffer, bitsWritten, (int)bitReader.RunLength, this.whiteValue);
}
else
{
- BitWriterUtils.WriteBits(buffer, (int)bitsWritten, bitReader.RunLength, this.blackValue);
+ BitWriterUtils.WriteBits(buffer, bitsWritten, (int)bitReader.RunLength, this.blackValue);
}
}
diff --git a/src/ImageSharp/Formats/Tiff/Compression/Decompressors/T6BitReader.cs b/src/ImageSharp/Formats/Tiff/Compression/Decompressors/T6BitReader.cs
index 6b9939b175..0d068bb6fd 100644
--- a/src/ImageSharp/Formats/Tiff/Compression/Decompressors/T6BitReader.cs
+++ b/src/ImageSharp/Formats/Tiff/Compression/Decompressors/T6BitReader.cs
@@ -1,10 +1,9 @@
// Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0.
-using System.Collections.Generic;
-using System.IO;
+using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.Formats.Tiff.Constants;
-using SixLabors.ImageSharp.Memory;
+using SixLabors.ImageSharp.IO;
namespace SixLabors.ImageSharp.Formats.Tiff.Compression.Decompressors
{
@@ -16,38 +15,23 @@ internal sealed class T6BitReader : T4BitReader
{
private readonly int maxCodeLength = 12;
- private static readonly CcittTwoDimensionalCode None = new CcittTwoDimensionalCode(CcittTwoDimensionalCodeType.None, 0);
+ private static readonly CcittTwoDimensionalCode None = new(0, CcittTwoDimensionalCodeType.None, 0);
- private static readonly Dictionary Len1Codes = new Dictionary()
- {
- { 0b1, new CcittTwoDimensionalCode(CcittTwoDimensionalCodeType.Vertical0, 1) }
- };
+ private static readonly CcittTwoDimensionalCode Len1Code1 = new(0b1, CcittTwoDimensionalCodeType.Vertical0, 1);
- private static readonly Dictionary Len3Codes = new Dictionary()
- {
- { 0b001, new CcittTwoDimensionalCode(CcittTwoDimensionalCodeType.Horizontal, 3) },
- { 0b010, new CcittTwoDimensionalCode(CcittTwoDimensionalCodeType.VerticalL1, 3) },
- { 0b011, new CcittTwoDimensionalCode(CcittTwoDimensionalCodeType.VerticalR1, 3) }
- };
+ private static readonly CcittTwoDimensionalCode Len3Code001 = new(0b001, CcittTwoDimensionalCodeType.Horizontal, 3);
+ private static readonly CcittTwoDimensionalCode Len3Code010 = new(0b010, CcittTwoDimensionalCodeType.VerticalL1, 3);
+ private static readonly CcittTwoDimensionalCode Len3Code011 = new(0b011, CcittTwoDimensionalCodeType.VerticalR1, 3);
- private static readonly Dictionary Len4Codes = new Dictionary()
- {
- { 0b0001, new CcittTwoDimensionalCode(CcittTwoDimensionalCodeType.Pass, 4) }
- };
+ private static readonly CcittTwoDimensionalCode Len4Code0001 = new(0b0001, CcittTwoDimensionalCodeType.Pass, 4);
- private static readonly Dictionary Len6Codes = new Dictionary()
- {
- { 0b000011, new CcittTwoDimensionalCode(CcittTwoDimensionalCodeType.VerticalR2, 6) },
- { 0b000010, new CcittTwoDimensionalCode(CcittTwoDimensionalCodeType.VerticalL2, 6) }
- };
+ private static readonly CcittTwoDimensionalCode Len6Code000011 = new(0b000011, CcittTwoDimensionalCodeType.VerticalR2, 6);
+ private static readonly CcittTwoDimensionalCode Len6Code000010 = new(0b000010, CcittTwoDimensionalCodeType.VerticalL2, 6);
- private static readonly Dictionary Len7Codes = new Dictionary()
- {
- { 0b0000011, new CcittTwoDimensionalCode(CcittTwoDimensionalCodeType.VerticalR3, 7) },
- { 0b0000010, new CcittTwoDimensionalCode(CcittTwoDimensionalCodeType.VerticalL3, 7) },
- { 0b0000001, new CcittTwoDimensionalCode(CcittTwoDimensionalCodeType.Extensions2D, 7) },
- { 0b0000000, new CcittTwoDimensionalCode(CcittTwoDimensionalCodeType.Extensions1D, 7) }
- };
+ private static readonly CcittTwoDimensionalCode Len7Code0000011 = new(0b0000011, CcittTwoDimensionalCodeType.VerticalR3, 7);
+ private static readonly CcittTwoDimensionalCode Len7Code0000010 = new(0b0000010, CcittTwoDimensionalCodeType.VerticalL3, 7);
+ private static readonly CcittTwoDimensionalCode Len7Code0000001 = new(0b0000001, CcittTwoDimensionalCodeType.Extensions2D, 7);
+ private static readonly CcittTwoDimensionalCode Len7Code0000000 = new(0b0000000, CcittTwoDimensionalCodeType.Extensions1D, 7);
///
/// Initializes a new instance of the class.
@@ -55,14 +39,13 @@ internal sealed class T6BitReader : T4BitReader
/// The compressed input stream.
/// The logical order of bits within a byte.
/// The number of bytes to read from the stream.
- /// The memory allocator.
- public T6BitReader(Stream input, TiffFillOrder fillOrder, int bytesToRead, MemoryAllocator allocator)
- : base(input, fillOrder, bytesToRead, allocator)
+ public T6BitReader(BufferedReadStream input, TiffFillOrder fillOrder, int bytesToRead)
+ : base(input, fillOrder, bytesToRead)
{
}
///
- public override bool HasMoreData => this.Position < (ulong)this.DataLength - 1 || ((uint)(this.BitsRead - 1) < (7 - 1));
+ public override bool HasMoreData => this.Position < (ulong)this.DataLength - 1 || (uint)(this.BitsRead - 1) < (7 - 1);
///
/// Gets or sets the two dimensional code.
@@ -85,45 +68,81 @@ public bool ReadNextCodeWord()
switch (this.CurValueBitsRead)
{
case 1:
- if (Len1Codes.ContainsKey(value))
+ if (value == Len1Code1.Code)
{
- this.Code = Len1Codes[value];
+ this.Code = Len1Code1;
return false;
}
break;
case 3:
- if (Len3Codes.ContainsKey(value))
+ if (value == Len3Code001.Code)
{
- this.Code = Len3Codes[value];
+ this.Code = Len3Code001;
+ return false;
+ }
+
+ if (value == Len3Code010.Code)
+ {
+ this.Code = Len3Code010;
+ return false;
+ }
+
+ if (value == Len3Code011.Code)
+ {
+ this.Code = Len3Code011;
return false;
}
break;
case 4:
- if (Len4Codes.ContainsKey(value))
+ if (value == Len4Code0001.Code)
{
- this.Code = Len4Codes[value];
+ this.Code = Len4Code0001;
return false;
}
break;
case 6:
- if (Len6Codes.ContainsKey(value))
+ if (value == Len6Code000010.Code)
{
- this.Code = Len6Codes[value];
+ this.Code = Len6Code000010;
+ return false;
+ }
+
+ if (value == Len6Code000011.Code)
+ {
+ this.Code = Len6Code000011;
return false;
}
break;
case 7:
- if (Len7Codes.ContainsKey(value))
+ if (value == Len7Code0000000.Code)
+ {
+ this.Code = Len7Code0000000;
+ return false;
+ }
+
+ if (value == Len7Code0000001.Code)
+ {
+ this.Code = Len7Code0000001;
+ return false;
+ }
+
+ if (value == Len7Code0000011.Code)
+ {
+ this.Code = Len7Code0000011;
+ return false;
+ }
+
+ if (value == Len7Code0000010.Code)
{
- this.Code = Len7Codes[value];
+ this.Code = Len7Code0000010;
return false;
}
@@ -154,6 +173,7 @@ protected override void ReadEolBeforeFirstData()
///
/// Swaps the white run to black run an vise versa.
///
+ [MethodImpl(InliningOptions.ShortMethod)]
public void SwapColor() => this.IsWhiteRun = !this.IsWhiteRun;
}
}
diff --git a/src/ImageSharp/Formats/Tiff/Compression/Decompressors/T6TiffCompression.cs b/src/ImageSharp/Formats/Tiff/Compression/Decompressors/T6TiffCompression.cs
index 972f4d8ff1..7cfcfe12b6 100644
--- a/src/ImageSharp/Formats/Tiff/Compression/Decompressors/T6TiffCompression.cs
+++ b/src/ImageSharp/Formats/Tiff/Compression/Decompressors/T6TiffCompression.cs
@@ -2,6 +2,8 @@
// Licensed under the Apache License, Version 2.0.
using System;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
using SixLabors.ImageSharp.Formats.Tiff.Constants;
using SixLabors.ImageSharp.IO;
using SixLabors.ImageSharp.Memory;
@@ -15,12 +17,10 @@ internal sealed class T6TiffCompression : TiffBaseDecompressor
{
private readonly bool isWhiteZero;
- private readonly byte whiteValue;
-
- private readonly byte blackValue;
-
private readonly int width;
+ private readonly byte white;
+
///
/// Initializes a new instance of the class.
///
@@ -40,8 +40,7 @@ public T6TiffCompression(
this.FillOrder = fillOrder;
this.width = width;
this.isWhiteZero = photometricInterpretation == TiffPhotometricInterpretation.WhiteIsZero;
- this.whiteValue = (byte)(this.isWhiteZero ? 0 : 1);
- this.blackValue = (byte)(this.isWhiteZero ? 1 : 0);
+ this.white = (byte)(this.isWhiteZero ? 0 : 255);
}
///
@@ -58,10 +57,10 @@ protected override void Decompress(BufferedReadStream stream, int byteCount, int
Span scanLine = scanLineBuffer.GetSpan().Slice(0, this.width);
Span referenceScanLineSpan = scanLineBuffer.GetSpan().Slice(this.width, this.width);
- using var bitReader = new T6BitReader(stream, this.FillOrder, byteCount, this.Allocator);
+ var bitReader = new T6BitReader(stream, this.FillOrder, byteCount);
var referenceScanLine = new CcittReferenceScanline(this.isWhiteZero, this.width);
- uint bitsWritten = 0;
+ nint bitsWritten = 0;
for (int y = 0; y < height; y++)
{
scanLine.Clear();
@@ -74,21 +73,34 @@ protected override void Decompress(BufferedReadStream stream, int byteCount, int
}
}
- private uint WriteScanLine(Span buffer, Span scanLine, uint bitsWritten)
+ private nint WriteScanLine(Span buffer, Span scanLine, nint bitsWritten)
{
- byte white = (byte)(this.isWhiteZero ? 0 : 255);
- for (int i = 0; i < scanLine.Length; i++)
+ nint bitPos = Numerics.Modulo8(bitsWritten);
+ nint bufferPos = bitsWritten / 8;
+ ref byte scanLineRef = ref MemoryMarshal.GetReference(scanLine);
+ for (nint i = 0; i < scanLine.Length; i++)
{
- BitWriterUtils.WriteBits(buffer, (int)bitsWritten, 1, scanLine[i] == white ? this.whiteValue : this.blackValue);
+ if (Unsafe.Add(ref scanLineRef, i) != this.white)
+ {
+ BitWriterUtils.WriteBit(buffer, bufferPos, bitPos);
+ }
+
+ bitPos++;
bitsWritten++;
+
+ if (bitPos >= 8)
+ {
+ bitPos = 0;
+ bufferPos++;
+ }
}
// Write padding bytes, if necessary.
- uint remainder = bitsWritten % 8;
+ nint remainder = Numerics.Modulo8(bitsWritten);
if (remainder != 0)
{
- uint padding = 8 - remainder;
- BitWriterUtils.WriteBits(buffer, (int)bitsWritten, padding, 0);
+ nint padding = 8 - remainder;
+ BitWriterUtils.WriteBits(buffer, bitsWritten, padding, 0);
bitsWritten += padding;
}
@@ -122,7 +134,7 @@ private static void Decode2DScanline(T6BitReader bitReader, bool whiteIsZero, Cc
}
else
{
- scanline.Fill((byte)255);
+ scanline.Fill(255);
}
break;
diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/BlackIsZero16TiffColor{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/BlackIsZero16TiffColor{TPixel}.cs
index e605629122..6f3189e706 100644
--- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/BlackIsZero16TiffColor{TPixel}.cs
+++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/BlackIsZero16TiffColor{TPixel}.cs
@@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0.
using System;
+using System.Numerics;
using SixLabors.ImageSharp.Formats.Tiff.Utils;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
@@ -32,11 +33,9 @@ public BlackIsZero16TiffColor(Configuration configuration, bool isBigEndian)
///
public override void Decode(ReadOnlySpan data, Buffer2D pixels, int left, int top, int width, int height)
{
- // Note: due to an issue with netcore 2.1 and default values and unpredictable behavior with those,
- // we define our own defaults as a workaround. See: https://github.com/dotnet/runtime/issues/55623
L16 l16 = TiffUtils.L16Default;
var color = default(TPixel);
- color.FromScaledVector4(TiffUtils.Vector4Default);
+ color.FromScaledVector4(Vector4.Zero);
int offset = 0;
for (int y = top; y < top + height; y++)
diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/BlackIsZero1TiffColor{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/BlackIsZero1TiffColor{TPixel}.cs
index eb749efe62..cf8f8fb734 100644
--- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/BlackIsZero1TiffColor{TPixel}.cs
+++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/BlackIsZero1TiffColor{TPixel}.cs
@@ -2,6 +2,8 @@
// Licensed under the Apache License, Version 2.0.
using System;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
@@ -17,26 +19,65 @@ internal class BlackIsZero1TiffColor : TiffBaseColorDecoder
///
public override void Decode(ReadOnlySpan data, Buffer2D pixels, int left, int top, int width, int height)
{
- var color = default(TPixel);
+ nint offset = 0;
+ var colorBlack = default(TPixel);
+ var colorWhite = default(TPixel);
- int offset = 0;
-
- Color black = Color.Black;
- Color white = Color.White;
- for (int y = top; y < top + height; y++)
+ colorBlack.FromRgba32(Color.Black);
+ colorWhite.FromRgba32(Color.White);
+ ref byte dataRef = ref MemoryMarshal.GetReference(data);
+ for (nint y = top; y < top + height; y++)
{
- for (int x = left; x < left + width; x += 8)
+ Span pixelRowSpan = pixels.DangerousGetRowSpan((int)y);
+ ref TPixel pixelRowRef = ref MemoryMarshal.GetReference(pixelRowSpan);
+ for (nint x = left; x < left + width; x += 8)
{
- byte b = data[offset++];
- int maxShift = Math.Min(left + width - x, 8);
+ byte b = Unsafe.Add(ref dataRef, offset++);
+ nint maxShift = Math.Min(left + width - x, 8);
- for (int shift = 0; shift < maxShift; shift++)
+ if (maxShift == 8)
{
- int bit = (b >> (7 - shift)) & 1;
+ int bit = (b >> 7) & 1;
+ ref TPixel pixel0 = ref Unsafe.Add(ref pixelRowRef, x);
+ pixel0 = bit == 0 ? colorBlack : colorWhite;
+
+ bit = (b >> 6) & 1;
+ ref TPixel pixel1 = ref Unsafe.Add(ref pixelRowRef, x + 1);
+ pixel1 = bit == 0 ? colorBlack : colorWhite;
+
+ bit = (b >> 5) & 1;
+ ref TPixel pixel2 = ref Unsafe.Add(ref pixelRowRef, x + 2);
+ pixel2 = bit == 0 ? colorBlack : colorWhite;
+
+ bit = (b >> 4) & 1;
+ ref TPixel pixel3 = ref Unsafe.Add(ref pixelRowRef, x + 3);
+ pixel3 = bit == 0 ? colorBlack : colorWhite;
+
+ bit = (b >> 3) & 1;
+ ref TPixel pixel4 = ref Unsafe.Add(ref pixelRowRef, x + 4);
+ pixel4 = bit == 0 ? colorBlack : colorWhite;
- color.FromRgba32(bit == 0 ? black : white);
+ bit = (b >> 2) & 1;
+ ref TPixel pixel5 = ref Unsafe.Add(ref pixelRowRef, x + 5);
+ pixel5 = bit == 0 ? colorBlack : colorWhite;
+
+ bit = (b >> 1) & 1;
+ ref TPixel pixel6 = ref Unsafe.Add(ref pixelRowRef, x + 6);
+ pixel6 = bit == 0 ? colorBlack : colorWhite;
+
+ bit = b & 1;
+ ref TPixel pixel7 = ref Unsafe.Add(ref pixelRowRef, x + 7);
+ pixel7 = bit == 0 ? colorBlack : colorWhite;
+ }
+ else
+ {
+ for (int shift = 0; shift < maxShift; shift++)
+ {
+ int bit = (b >> (7 - shift)) & 1;
- pixels[x + shift, y] = color;
+ ref TPixel pixel = ref Unsafe.Add(ref pixelRowRef, x + shift);
+ pixel = bit == 0 ? colorBlack : colorWhite;
+ }
}
}
}
diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/BlackIsZero24TiffColor{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/BlackIsZero24TiffColor{TPixel}.cs
index 7d230dfd5e..9be8dd7741 100644
--- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/BlackIsZero24TiffColor{TPixel}.cs
+++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/BlackIsZero24TiffColor{TPixel}.cs
@@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0.
using System;
+using System.Numerics;
using SixLabors.ImageSharp.Formats.Tiff.Utils;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
@@ -25,14 +26,12 @@ internal class BlackIsZero24TiffColor : TiffBaseColorDecoder
///
public override void Decode(ReadOnlySpan data, Buffer2D pixels, int left, int top, int width, int height)
{
- // Note: due to an issue with netcore 2.1 and default values and unpredictable behavior with those,
- // we define our own defaults as a workaround. See: https://github.com/dotnet/runtime/issues/55623
var color = default(TPixel);
- color.FromScaledVector4(TiffUtils.Vector4Default);
- byte[] buffer = new byte[4];
+ color.FromScaledVector4(Vector4.Zero);
+ Span buffer = stackalloc byte[4];
int bufferStartIdx = this.isBigEndian ? 1 : 0;
- Span bufferSpan = buffer.AsSpan(bufferStartIdx);
+ Span bufferSpan = buffer.Slice(bufferStartIdx);
int offset = 0;
for (int y = top; y < top + height; y++)
{
diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/BlackIsZero32FloatTiffColor{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/BlackIsZero32FloatTiffColor{TPixel}.cs
index c43b121caf..fc526a86f5 100644
--- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/BlackIsZero32FloatTiffColor{TPixel}.cs
+++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/BlackIsZero32FloatTiffColor{TPixel}.cs
@@ -3,7 +3,6 @@
using System;
using System.Numerics;
-using SixLabors.ImageSharp.Formats.Tiff.Utils;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
@@ -26,10 +25,8 @@ internal class BlackIsZero32FloatTiffColor : TiffBaseColorDecoder
public override void Decode(ReadOnlySpan data, Buffer2D pixels, int left, int top, int width, int height)
{
- // Note: due to an issue with netcore 2.1 and default values and unpredictable behavior with those,
- // we define our own defaults as a workaround. See: https://github.com/dotnet/runtime/issues/55623
var color = default(TPixel);
- color.FromScaledVector4(TiffUtils.Vector4Default);
+ color.FromScaledVector4(Vector4.Zero);
byte[] buffer = new byte[4];
int offset = 0;
diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/BlackIsZero32TiffColor{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/BlackIsZero32TiffColor{TPixel}.cs
index 00e4caef79..b2ab127003 100644
--- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/BlackIsZero32TiffColor{TPixel}.cs
+++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/BlackIsZero32TiffColor{TPixel}.cs
@@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0.
using System;
+using System.Numerics;
using SixLabors.ImageSharp.Formats.Tiff.Utils;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
@@ -25,10 +26,8 @@ internal class BlackIsZero32TiffColor : TiffBaseColorDecoder
///
public override void Decode(ReadOnlySpan data, Buffer2D pixels, int left, int top, int width, int height)
{
- // Note: due to an issue with netcore 2.1 and default values and unpredictable behavior with those,
- // we define our own defaults as a workaround. See: https://github.com/dotnet/runtime/issues/55623
var color = default(TPixel);
- color.FromScaledVector4(TiffUtils.Vector4Default);
+ color.FromScaledVector4(Vector4.Zero);
int offset = 0;
for (int y = top; y < top + height; y++)
diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/BlackIsZero4TiffColor{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/BlackIsZero4TiffColor{TPixel}.cs
index 2e66bb6d70..79247d8ed0 100644
--- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/BlackIsZero4TiffColor{TPixel}.cs
+++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/BlackIsZero4TiffColor{TPixel}.cs
@@ -24,6 +24,7 @@ public override void Decode(ReadOnlySpan data, Buffer2D pixels, in
var l8 = default(L8);
for (int y = top; y < top + height; y++)
{
+ Span pixelRowSpan = pixels.DangerousGetRowSpan(y);
for (int x = left; x < left + width - 1;)
{
byte byteData = data[offset++];
@@ -32,13 +33,13 @@ public override void Decode(ReadOnlySpan data, Buffer2D pixels, in
l8.PackedValue = intensity1;
color.FromL8(l8);
- pixels[x++, y] = color;
+ pixelRowSpan[x++] = color;
byte intensity2 = (byte)((byteData & 0x0F) * 17);
l8.PackedValue = intensity2;
color.FromL8(l8);
- pixels[x++, y] = color;
+ pixelRowSpan[x++] = color;
}
if (isOddWidth)
@@ -49,7 +50,7 @@ public override void Decode(ReadOnlySpan data, Buffer2D pixels, in
l8.PackedValue = intensity1;
color.FromL8(l8);
- pixels[left + width - 1, y] = color;
+ pixelRowSpan[left + width - 1] = color;
}
}
}
diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/PaletteTiffColor{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/PaletteTiffColor{TPixel}.cs
index ad5793084b..d0ab2383d7 100644
--- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/PaletteTiffColor{TPixel}.cs
+++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/PaletteTiffColor{TPixel}.cs
@@ -19,6 +19,8 @@ internal class PaletteTiffColor : TiffBaseColorDecoder
private readonly TPixel[] palette;
+ private const float InvMax = 1.0f / 65535F;
+
/// The number of bits per sample for each pixel.
/// The RGB color lookup table to use for decoding the image.
public PaletteTiffColor(TiffBitsPerSample bitsPerSample, ushort[] colorMap)
@@ -56,9 +58,9 @@ private static TPixel[] GeneratePalette(ushort[] colorMap, int colorCount)
for (int i = 0; i < palette.Length; i++)
{
- float r = colorMap[rOffset + i] / 65535F;
- float g = colorMap[gOffset + i] / 65535F;
- float b = colorMap[bOffset + i] / 65535F;
+ float r = colorMap[rOffset + i] * InvMax;
+ float g = colorMap[gOffset + i] * InvMax;
+ float b = colorMap[bOffset + i] * InvMax;
palette[i].FromScaledVector4(new Vector4(r, g, b, 1.0f));
}
diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgb161616TiffColor{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgb161616TiffColor{TPixel}.cs
index 6093690117..0527eaaf0f 100644
--- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgb161616TiffColor{TPixel}.cs
+++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgb161616TiffColor{TPixel}.cs
@@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0.
using System;
+using System.Numerics;
using SixLabors.ImageSharp.Formats.Tiff.Utils;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
@@ -32,11 +33,9 @@ public Rgb161616TiffColor(Configuration configuration, bool isBigEndian)
///
public override void Decode(ReadOnlySpan data, Buffer2D pixels, int left, int top, int width, int height)
{
- // Note: due to an issue with netcore 2.1 and default values and unpredictable behavior with those,
- // we define our own defaults as a workaround. See: https://github.com/dotnet/runtime/issues/55623
Rgba64 rgba = TiffUtils.Rgba64Default;
var color = default(TPixel);
- color.FromScaledVector4(TiffUtils.Vector4Default);
+ color.FromScaledVector4(Vector4.Zero);
int offset = 0;
diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgb16PlanarTiffColor{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgb16PlanarTiffColor{TPixel}.cs
index 76fed3c93e..fc5dc82aab 100644
--- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgb16PlanarTiffColor{TPixel}.cs
+++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgb16PlanarTiffColor{TPixel}.cs
@@ -3,6 +3,7 @@
using System;
using System.Buffers;
+using System.Numerics;
using SixLabors.ImageSharp.Formats.Tiff.Utils;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
@@ -26,11 +27,9 @@ internal class Rgb16PlanarTiffColor : TiffBasePlanarColorDecoder
///
public override void Decode(IMemoryOwner[] data, Buffer2D pixels, int left, int top, int width, int height)
{
- // Note: due to an issue with netcore 2.1 and default values and unpredictable behavior with those,
- // we define our own defaults as a workaround. See: https://github.com/dotnet/runtime/issues/55623
Rgba64 rgba = TiffUtils.Rgba64Default;
var color = default(TPixel);
- color.FromScaledVector4(TiffUtils.Vector4Default);
+ color.FromScaledVector4(Vector4.Zero);
Span redData = data[0].GetSpan();
Span greenData = data[1].GetSpan();
diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgb242424TiffColor{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgb242424TiffColor{TPixel}.cs
index addf576e95..4fc25f2dd0 100644
--- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgb242424TiffColor{TPixel}.cs
+++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgb242424TiffColor{TPixel}.cs
@@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0.
using System;
+using System.Numerics;
using SixLabors.ImageSharp.Formats.Tiff.Utils;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
@@ -25,10 +26,8 @@ internal class Rgb242424TiffColor : TiffBaseColorDecoder
///
public override void Decode(ReadOnlySpan data, Buffer2D pixels, int left, int top, int width, int height)
{
- // Note: due to an issue with netcore 2.1 and default values and unpredictable behavior with those,
- // we define our own defaults as a workaround. See: https://github.com/dotnet/runtime/issues/55623
var color = default(TPixel);
- color.FromScaledVector4(TiffUtils.Vector4Default);
+ color.FromScaledVector4(Vector4.Zero);
int offset = 0;
Span buffer = stackalloc byte[4];
int bufferStartIdx = this.isBigEndian ? 1 : 0;
diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgb24PlanarTiffColor{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgb24PlanarTiffColor{TPixel}.cs
index 2eda3b5af7..59bc94802f 100644
--- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgb24PlanarTiffColor{TPixel}.cs
+++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgb24PlanarTiffColor{TPixel}.cs
@@ -3,6 +3,7 @@
using System;
using System.Buffers;
+using System.Numerics;
using SixLabors.ImageSharp.Formats.Tiff.Utils;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
@@ -26,10 +27,8 @@ internal class Rgb24PlanarTiffColor : TiffBasePlanarColorDecoder
///
public override void Decode(IMemoryOwner[] data, Buffer2D pixels, int left, int top, int width, int height)
{
- // Note: due to an issue with netcore 2.1 and default values and unpredictable behavior with those,
- // we define our own defaults as a workaround. See: https://github.com/dotnet/runtime/issues/55623
var color = default(TPixel);
- color.FromScaledVector4(TiffUtils.Vector4Default);
+ color.FromScaledVector4(Vector4.Zero);
Span buffer = stackalloc byte[4];
int bufferStartIdx = this.isBigEndian ? 1 : 0;
diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgb323232TiffColor{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgb323232TiffColor{TPixel}.cs
index 02319bfa66..b8f9da72ff 100644
--- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgb323232TiffColor{TPixel}.cs
+++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgb323232TiffColor{TPixel}.cs
@@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0.
using System;
+using System.Numerics;
using SixLabors.ImageSharp.Formats.Tiff.Utils;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
@@ -25,10 +26,8 @@ internal class Rgb323232TiffColor : TiffBaseColorDecoder
///
public override void Decode(ReadOnlySpan data, Buffer2D pixels, int left, int top, int width, int height)
{
- // Note: due to an issue with netcore 2.1 and default values and unpredictable behavior with those,
- // we define our own defaults as a workaround. See: https://github.com/dotnet/runtime/issues/55623
var color = default(TPixel);
- color.FromScaledVector4(TiffUtils.Vector4Default);
+ color.FromScaledVector4(Vector4.Zero);
int offset = 0;
for (int y = top; y < top + height; y++)
diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgb32PlanarTiffColor{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgb32PlanarTiffColor{TPixel}.cs
index 26f75bfcf8..8903b8a40f 100644
--- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgb32PlanarTiffColor{TPixel}.cs
+++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgb32PlanarTiffColor{TPixel}.cs
@@ -3,6 +3,7 @@
using System;
using System.Buffers;
+using System.Numerics;
using SixLabors.ImageSharp.Formats.Tiff.Utils;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
@@ -26,10 +27,8 @@ internal class Rgb32PlanarTiffColor : TiffBasePlanarColorDecoder
///
public override void Decode(IMemoryOwner[] data, Buffer2D pixels, int left, int top, int width, int height)
{
- // Note: due to an issue with netcore 2.1 and default values and unpredictable behavior with those,
- // we define our own defaults as a workaround. See: https://github.com/dotnet/runtime/issues/55623
var color = default(TPixel);
- color.FromScaledVector4(TiffUtils.Vector4Default);
+ color.FromScaledVector4(Vector4.Zero);
Span redData = data[0].GetSpan();
Span greenData = data[1].GetSpan();
diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/RgbFloat323232TiffColor{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/RgbFloat323232TiffColor{TPixel}.cs
index 7fd98dd504..2aa810623e 100644
--- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/RgbFloat323232TiffColor{TPixel}.cs
+++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/RgbFloat323232TiffColor{TPixel}.cs
@@ -26,10 +26,8 @@ internal class RgbFloat323232TiffColor : TiffBaseColorDecoder
///
public override void Decode(ReadOnlySpan data, Buffer2D pixels, int left, int top, int width, int height)
{
- // Note: due to an issue with netcore 2.1 and default values and unpredictable behavior with those,
- // we define our own defaults as a workaround. See: https://github.com/dotnet/runtime/issues/55623
var color = default(TPixel);
- color.FromScaledVector4(TiffUtils.Vector4Default);
+ color.FromScaledVector4(Vector4.Zero);
int offset = 0;
byte[] buffer = new byte[4];
diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba16161616TiffColor{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba16161616TiffColor{TPixel}.cs
index 0340438cbf..d1164b67a3 100644
--- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba16161616TiffColor{TPixel}.cs
+++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba16161616TiffColor{TPixel}.cs
@@ -42,11 +42,9 @@ public Rgba16161616TiffColor(Configuration configuration, MemoryAllocator memory
///
public override void Decode(ReadOnlySpan data, Buffer2D pixels, int left, int top, int width, int height)
{
- // Note: due to an issue with netcore 2.1 and default values and unpredictable behavior with those,
- // we define our own defaults as a workaround. See: https://github.com/dotnet/runtime/issues/55623
Rgba64 rgba = TiffUtils.Rgba64Default;
var color = default(TPixel);
- color.FromScaledVector4(TiffUtils.Vector4Default);
+ color.FromScaledVector4(Vector4.Zero);
bool hasAssociatedAlpha = this.extraSamplesType.HasValue && this.extraSamplesType == TiffExtraSampleType.AssociatedAlphaData;
int offset = 0;
diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba16PlanarTiffColor{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba16PlanarTiffColor{TPixel}.cs
index 856d810d31..51e6e21dfa 100644
--- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba16PlanarTiffColor{TPixel}.cs
+++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba16PlanarTiffColor{TPixel}.cs
@@ -3,6 +3,7 @@
using System;
using System.Buffers;
+using System.Numerics;
using SixLabors.ImageSharp.Formats.Tiff.Utils;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
@@ -33,11 +34,9 @@ public Rgba16PlanarTiffColor(TiffExtraSampleType? extraSamplesType, bool isBigEn
///
public override void Decode(IMemoryOwner[] data, Buffer2D pixels, int left, int top, int width, int height)
{
- // Note: due to an issue with netcore 2.1 and default values and unpredictable behavior with those,
- // we define our own defaults as a workaround. See: https://github.com/dotnet/runtime/issues/55623
Rgba64 rgba = TiffUtils.Rgba64Default;
var color = default(TPixel);
- color.FromScaledVector4(TiffUtils.Vector4Default);
+ color.FromScaledVector4(Vector4.Zero);
Span redData = data[0].GetSpan();
Span greenData = data[1].GetSpan();
diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba24242424TiffColor{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba24242424TiffColor{TPixel}.cs
index 2ce30252f5..ff35a8d0dd 100644
--- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba24242424TiffColor{TPixel}.cs
+++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba24242424TiffColor{TPixel}.cs
@@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0.
using System;
+using System.Numerics;
using SixLabors.ImageSharp.Formats.Tiff.Utils;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
@@ -32,10 +33,8 @@ public Rgba24242424TiffColor(TiffExtraSampleType? extraSamplesType, bool isBigEn
///
public override void Decode(ReadOnlySpan data, Buffer2D pixels, int left, int top, int width, int height)
{
- // Note: due to an issue with netcore 2.1 and default values and unpredictable behavior with those,
- // we define our own defaults as a workaround. See: https://github.com/dotnet/runtime/issues/55623
var color = default(TPixel);
- color.FromScaledVector4(TiffUtils.Vector4Default);
+ color.FromScaledVector4(Vector4.Zero);
bool hasAssociatedAlpha = this.extraSamplesType.HasValue && this.extraSamplesType == TiffExtraSampleType.AssociatedAlphaData;
int offset = 0;
diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba24PlanarTiffColor{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba24PlanarTiffColor{TPixel}.cs
index 89172cfe72..1a3459fcb6 100644
--- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba24PlanarTiffColor{TPixel}.cs
+++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba24PlanarTiffColor{TPixel}.cs
@@ -3,6 +3,7 @@
using System;
using System.Buffers;
+using System.Numerics;
using SixLabors.ImageSharp.Formats.Tiff.Utils;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
@@ -33,10 +34,8 @@ public Rgba24PlanarTiffColor(TiffExtraSampleType? extraSamplesType, bool isBigEn
///
public override void Decode(IMemoryOwner[] data, Buffer2D pixels, int left, int top, int width, int height)
{
- // Note: due to an issue with netcore 2.1 and default values and unpredictable behavior with those,
- // we define our own defaults as a workaround. See: https://github.com/dotnet/runtime/issues/55623
var color = default(TPixel);
- color.FromScaledVector4(TiffUtils.Vector4Default);
+ color.FromScaledVector4(Vector4.Zero);
Span buffer = stackalloc byte[4];
int bufferStartIdx = this.isBigEndian ? 1 : 0;
diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba32323232TiffColor{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba32323232TiffColor{TPixel}.cs
index 8ee9eb0bf9..378338de6e 100644
--- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba32323232TiffColor{TPixel}.cs
+++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba32323232TiffColor{TPixel}.cs
@@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0.
using System;
+using System.Numerics;
using SixLabors.ImageSharp.Formats.Tiff.Utils;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
@@ -32,10 +33,8 @@ public Rgba32323232TiffColor(TiffExtraSampleType? extraSamplesType, bool isBigEn
///
public override void Decode(ReadOnlySpan data, Buffer2D pixels, int left, int top, int width, int height)
{
- // Note: due to an issue with netcore 2.1 and default values and unpredictable behavior with those,
- // we define our own defaults as a workaround. See: https://github.com/dotnet/runtime/issues/55623
var color = default(TPixel);
- color.FromScaledVector4(TiffUtils.Vector4Default);
+ color.FromScaledVector4(Vector4.Zero);
bool hasAssociatedAlpha = this.extraSamplesType.HasValue && this.extraSamplesType == TiffExtraSampleType.AssociatedAlphaData;
int offset = 0;
diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba32PlanarTiffColor{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba32PlanarTiffColor{TPixel}.cs
index c98ac1cf00..af3a888a79 100644
--- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba32PlanarTiffColor{TPixel}.cs
+++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba32PlanarTiffColor{TPixel}.cs
@@ -3,6 +3,7 @@
using System;
using System.Buffers;
+using System.Numerics;
using SixLabors.ImageSharp.Formats.Tiff.Utils;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
@@ -33,10 +34,8 @@ public Rgba32PlanarTiffColor(TiffExtraSampleType? extraSamplesType, bool isBigEn
///
public override void Decode(IMemoryOwner[] data, Buffer2D pixels, int left, int top, int width, int height)
{
- // Note: due to an issue with netcore 2.1 and default values and unpredictable behavior with those,
- // we define our own defaults as a workaround. See: https://github.com/dotnet/runtime/issues/55623
var color = default(TPixel);
- color.FromScaledVector4(TiffUtils.Vector4Default);
+ color.FromScaledVector4(Vector4.Zero);
Span redData = data[0].GetSpan();
Span greenData = data[1].GetSpan();
diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba8888TiffColor{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba8888TiffColor{TPixel}.cs
index 967a68ad0c..24cf8019ce 100644
--- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba8888TiffColor{TPixel}.cs
+++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba8888TiffColor{TPixel}.cs
@@ -36,7 +36,7 @@ public override void Decode(ReadOnlySpan data, Buffer2D pixels, in
bool hasAssociatedAlpha = this.extraSamplesType.HasValue && this.extraSamplesType == TiffExtraSampleType.AssociatedAlphaData;
var color = default(TPixel);
- color.FromScaledVector4(TiffUtils.Vector4Default);
+ color.FromScaledVector4(Vector4.Zero);
using IMemoryOwner vectors = hasAssociatedAlpha ? this.memoryAllocator.Allocate(width) : null;
Span vectorsSpan = hasAssociatedAlpha ? vectors.GetSpan() : Span.Empty;
for (int y = top; y < top + height; y++)
diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/RgbaFloat32323232TiffColor{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/RgbaFloat32323232TiffColor{TPixel}.cs
index f95045ec5a..317c2db3b3 100644
--- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/RgbaFloat32323232TiffColor{TPixel}.cs
+++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/RgbaFloat32323232TiffColor{TPixel}.cs
@@ -26,10 +26,8 @@ internal class RgbaFloat32323232TiffColor : TiffBaseColorDecoder
///
public override void Decode(ReadOnlySpan data, Buffer2D pixels, int left, int top, int width, int height)
{
- // Note: due to an issue with netcore 2.1 and default values and unpredictable behavior with those,
- // we define our own defaults as a workaround. See: https://github.com/dotnet/runtime/issues/55623
var color = default(TPixel);
- color.FromScaledVector4(TiffUtils.Vector4Default);
+ color.FromScaledVector4(Vector4.Zero);
int offset = 0;
byte[] buffer = new byte[4];
diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/WhiteIsZero16TiffColor{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/WhiteIsZero16TiffColor{TPixel}.cs
index d509776d7d..092ba68e2e 100644
--- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/WhiteIsZero16TiffColor{TPixel}.cs
+++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/WhiteIsZero16TiffColor{TPixel}.cs
@@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0.
using System;
+using System.Numerics;
using SixLabors.ImageSharp.Formats.Tiff.Utils;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
@@ -25,11 +26,9 @@ internal class WhiteIsZero16TiffColor : TiffBaseColorDecoder
///
public override void Decode(ReadOnlySpan data, Buffer2D pixels, int left, int top, int width, int height)
{
- // Note: due to an issue with netcore 2.1 and default values and unpredictable behavior with those,
- // we define our own defaults as a workaround. See: https://github.com/dotnet/runtime/issues/55623
L16 l16 = TiffUtils.L16Default;
var color = default(TPixel);
- color.FromScaledVector4(TiffUtils.Vector4Default);
+ color.FromScaledVector4(Vector4.Zero);
int offset = 0;
for (int y = top; y < top + height; y++)
diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/WhiteIsZero1TiffColor{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/WhiteIsZero1TiffColor{TPixel}.cs
index 5f1afe46ff..e3e95d9e12 100644
--- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/WhiteIsZero1TiffColor{TPixel}.cs
+++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/WhiteIsZero1TiffColor{TPixel}.cs
@@ -2,6 +2,8 @@
// Licensed under the Apache License, Version 2.0.
using System;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
@@ -16,26 +18,65 @@ internal class WhiteIsZero1TiffColor : TiffBaseColorDecoder
///
public override void Decode(ReadOnlySpan data, Buffer2D pixels, int left, int top, int width, int height)
{
- var color = default(TPixel);
+ nint offset = 0;
+ var colorBlack = default(TPixel);
+ var colorWhite = default(TPixel);
- int offset = 0;
-
- Color black = Color.Black;
- Color white = Color.White;
- for (int y = top; y < top + height; y++)
+ colorBlack.FromRgba32(Color.Black);
+ colorWhite.FromRgba32(Color.White);
+ ref byte dataRef = ref MemoryMarshal.GetReference(data);
+ for (nint y = top; y < top + height; y++)
{
- for (int x = left; x < left + width; x += 8)
+ Span pixelRowSpan = pixels.DangerousGetRowSpan((int)y);
+ ref TPixel pixelRowRef = ref MemoryMarshal.GetReference(pixelRowSpan);
+ for (nint x = left; x < left + width; x += 8)
{
- byte b = data[offset++];
- int maxShift = Math.Min(left + width - x, 8);
+ byte b = Unsafe.Add(ref dataRef, offset++);
+ nint maxShift = Math.Min(left + width - x, 8);
- for (int shift = 0; shift < maxShift; shift++)
+ if (maxShift == 8)
{
- int bit = (b >> (7 - shift)) & 1;
+ int bit = (b >> 7) & 1;
+ ref TPixel pixel0 = ref Unsafe.Add(ref pixelRowRef, x);
+ pixel0 = bit == 0 ? colorWhite : colorBlack;
+
+ bit = (b >> 6) & 1;
+ ref TPixel pixel1 = ref Unsafe.Add(ref pixelRowRef, x + 1);
+ pixel1 = bit == 0 ? colorWhite : colorBlack;
+
+ bit = (b >> 5) & 1;
+ ref TPixel pixel2 = ref Unsafe.Add(ref pixelRowRef, x + 2);
+ pixel2 = bit == 0 ? colorWhite : colorBlack;
+
+ bit = (b >> 4) & 1;
+ ref TPixel pixel3 = ref Unsafe.Add(ref pixelRowRef, x + 3);
+ pixel3 = bit == 0 ? colorWhite : colorBlack;
+
+ bit = (b >> 3) & 1;
+ ref TPixel pixel4 = ref Unsafe.Add(ref pixelRowRef, x + 4);
+ pixel4 = bit == 0 ? colorWhite : colorBlack;
- color.FromRgba32(bit == 0 ? white : black);
+ bit = (b >> 2) & 1;
+ ref TPixel pixel5 = ref Unsafe.Add(ref pixelRowRef, x + 5);
+ pixel5 = bit == 0 ? colorWhite : colorBlack;
+
+ bit = (b >> 1) & 1;
+ ref TPixel pixel6 = ref Unsafe.Add(ref pixelRowRef, x + 6);
+ pixel6 = bit == 0 ? colorWhite : colorBlack;
+
+ bit = b & 1;
+ ref TPixel pixel7 = ref Unsafe.Add(ref pixelRowRef, x + 7);
+ pixel7 = bit == 0 ? colorWhite : colorBlack;
+ }
+ else
+ {
+ for (int shift = 0; shift < maxShift; shift++)
+ {
+ int bit = (b >> (7 - shift)) & 1;
- pixels[x + shift, y] = color;
+ ref TPixel pixel = ref Unsafe.Add(ref pixelRowRef, x + shift);
+ pixel = bit == 0 ? colorWhite : colorBlack;
+ }
}
}
}
diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/WhiteIsZero24TiffColor{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/WhiteIsZero24TiffColor{TPixel}.cs
index fbf8130789..d483d7faf8 100644
--- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/WhiteIsZero24TiffColor{TPixel}.cs
+++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/WhiteIsZero24TiffColor{TPixel}.cs
@@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0.
using System;
+using System.Numerics;
using SixLabors.ImageSharp.Formats.Tiff.Utils;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
@@ -25,15 +26,13 @@ internal class WhiteIsZero24TiffColor : TiffBaseColorDecoder
///
public override void Decode(ReadOnlySpan data, Buffer2D pixels, int left, int top, int width, int height)
{
- // Note: due to an issue with netcore 2.1 and default values and unpredictable behavior with those,
- // we define our own defaults as a workaround. See: https://github.com/dotnet/runtime/issues/55623
var color = default(TPixel);
- color.FromScaledVector4(TiffUtils.Vector4Default);
- byte[] buffer = new byte[4];
+ color.FromScaledVector4(Vector4.Zero);
+ Span buffer = stackalloc byte[4];
int bufferStartIdx = this.isBigEndian ? 1 : 0;
const uint maxValue = 0xFFFFFF;
- Span bufferSpan = buffer.AsSpan(bufferStartIdx);
+ Span bufferSpan = buffer.Slice(bufferStartIdx);
int offset = 0;
for (int y = top; y < top + height; y++)
{
diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/WhiteIsZero32FloatTiffColor{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/WhiteIsZero32FloatTiffColor{TPixel}.cs
index 40d1541c51..f3b72edb5f 100644
--- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/WhiteIsZero32FloatTiffColor{TPixel}.cs
+++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/WhiteIsZero32FloatTiffColor{TPixel}.cs
@@ -26,10 +26,8 @@ internal class WhiteIsZero32FloatTiffColor : TiffBaseColorDecoder
public override void Decode(ReadOnlySpan data, Buffer2D pixels, int left, int top, int width, int height)
{
- // Note: due to an issue with netcore 2.1 and default values and unpredictable behavior with those,
- // we define our own defaults as a workaround. See: https://github.com/dotnet/runtime/issues/55623
var color = default(TPixel);
- color.FromScaledVector4(TiffUtils.Vector4Default);
+ color.FromScaledVector4(Vector4.Zero);
byte[] buffer = new byte[4];
int offset = 0;
diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/WhiteIsZero32TiffColor{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/WhiteIsZero32TiffColor{TPixel}.cs
index fd908c1e9f..48e24dedae 100644
--- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/WhiteIsZero32TiffColor{TPixel}.cs
+++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/WhiteIsZero32TiffColor{TPixel}.cs
@@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0.
using System;
+using System.Numerics;
using SixLabors.ImageSharp.Formats.Tiff.Utils;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
@@ -25,10 +26,8 @@ internal class WhiteIsZero32TiffColor : TiffBaseColorDecoder
///
public override void Decode(ReadOnlySpan data, Buffer2D pixels, int left, int top, int width, int height)
{
- // Note: due to an issue with netcore 2.1 and default values and unpredictable behavior with those,
- // we define our own defaults as a workaround. See: https://github.com/dotnet/runtime/issues/55623
var color = default(TPixel);
- color.FromScaledVector4(TiffUtils.Vector4Default);
+ color.FromScaledVector4(Vector4.Zero);
const uint maxValue = 0xFFFFFFFF;
int offset = 0;
diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/WhiteIsZero4TiffColor{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/WhiteIsZero4TiffColor{TPixel}.cs
index a4650af5ea..8b635043ec 100644
--- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/WhiteIsZero4TiffColor{TPixel}.cs
+++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/WhiteIsZero4TiffColor{TPixel}.cs
@@ -24,6 +24,7 @@ public override void Decode(ReadOnlySpan data, Buffer2D pixels, in
var l8 = default(L8);
for (int y = top; y < top + height; y++)
{
+ Span pixelRowSpan = pixels.DangerousGetRowSpan(y);
for (int x = left; x < left + width - 1;)
{
byte byteData = data[offset++];
@@ -32,13 +33,13 @@ public override void Decode(ReadOnlySpan data, Buffer2D pixels, in
l8.PackedValue = intensity1;
color.FromL8(l8);
- pixels[x++, y] = color;
+ pixelRowSpan[x++] = color;
byte intensity2 = (byte)((15 - (byteData & 0x0F)) * 17);
l8.PackedValue = intensity2;
color.FromL8(l8);
- pixels[x++, y] = color;
+ pixelRowSpan[x++] = color;
}
if (isOddWidth)
@@ -49,7 +50,7 @@ public override void Decode(ReadOnlySpan data, Buffer2D pixels, in
l8.PackedValue = intensity1;
color.FromL8(l8);
- pixels[left + width - 1, y] = color;
+ pixelRowSpan[left + width - 1] = color;
}
}
}
diff --git a/src/ImageSharp/Formats/Tiff/TiffEncoderCore.cs b/src/ImageSharp/Formats/Tiff/TiffEncoderCore.cs
index 3409b3dd8a..9a953a2695 100644
--- a/src/ImageSharp/Formats/Tiff/TiffEncoderCore.cs
+++ b/src/ImageSharp/Formats/Tiff/TiffEncoderCore.cs
@@ -343,7 +343,7 @@ private void SanitizeAndSetEncoderOptions(TiffBitsPerPixel? bitsPerPixel, int in
switch (bitsPerPixel)
{
case TiffBitsPerPixel.Bit1:
- if (compression == TiffCompression.Ccitt1D || compression == TiffCompression.CcittGroup3Fax || compression == TiffCompression.CcittGroup4Fax)
+ if (IsOneBitCompression(compression))
{
// The “normal” PhotometricInterpretation for bilevel CCITT compressed data is WhiteIsZero.
this.SetEncoderOptions(bitsPerPixel, TiffPhotometricInterpretation.WhiteIsZero, compression, TiffPredictor.None);
@@ -375,6 +375,13 @@ private void SanitizeAndSetEncoderOptions(TiffBitsPerPixel? bitsPerPixel, int in
break;
}
+ // Make sure 1 Bit compression is only used with 1 bit pixel type.
+ if (IsOneBitCompression(this.CompressionType) && this.BitsPerPixel != TiffBitsPerPixel.Bit1)
+ {
+ // Invalid compression / bits per pixel combination, fallback to no compression.
+ this.CompressionType = DefaultCompression;
+ }
+
return;
}
@@ -396,18 +403,14 @@ private void SanitizeAndSetEncoderOptions(TiffBitsPerPixel? bitsPerPixel, int in
{
case TiffPhotometricInterpretation.BlackIsZero:
case TiffPhotometricInterpretation.WhiteIsZero:
- if (this.CompressionType == TiffCompression.Ccitt1D ||
- this.CompressionType == TiffCompression.CcittGroup3Fax ||
- this.CompressionType == TiffCompression.CcittGroup4Fax)
+ if (IsOneBitCompression(this.CompressionType))
{
this.SetEncoderOptions(TiffBitsPerPixel.Bit1, photometricInterpretation, compression, TiffPredictor.None);
return;
}
- else
- {
- this.SetEncoderOptions(TiffBitsPerPixel.Bit8, photometricInterpretation, compression, predictor);
- return;
- }
+
+ this.SetEncoderOptions(TiffBitsPerPixel.Bit8, photometricInterpretation, compression, predictor);
+ return;
case TiffPhotometricInterpretation.PaletteColor:
this.SetEncoderOptions(TiffBitsPerPixel.Bit8, photometricInterpretation, compression, predictor);
@@ -428,5 +431,15 @@ private void SetEncoderOptions(TiffBitsPerPixel? bitsPerPixel, TiffPhotometricIn
this.CompressionType = compression;
this.HorizontalPredictor = predictor;
}
+
+ public static bool IsOneBitCompression(TiffCompression? compression)
+ {
+ if (compression is TiffCompression.Ccitt1D or TiffCompression.CcittGroup3Fax or TiffCompression.CcittGroup4Fax)
+ {
+ return true;
+ }
+
+ return false;
+ }
}
}
diff --git a/src/ImageSharp/Formats/Tiff/Utils/TiffUtils.cs b/src/ImageSharp/Formats/Tiff/Utils/TiffUtils.cs
index 532423c4f1..2f1ddcf21c 100644
--- a/src/ImageSharp/Formats/Tiff/Utils/TiffUtils.cs
+++ b/src/ImageSharp/Formats/Tiff/Utils/TiffUtils.cs
@@ -18,8 +18,6 @@ internal static class TiffUtils
private const float Scale32Bit = 1.0f / 0xFFFFFFFF;
- public static Vector4 Vector4Default { get; } = new(0.0f, 0.0f, 0.0f, 0.0f);
-
public static Rgba64 Rgba64Default { get; } = new(0, 0, 0, 0);
public static L16 L16Default { get; } = new(0);
diff --git a/tests/ImageSharp.Benchmarks/Codecs/Tiff/DecodeTiff.cs b/tests/ImageSharp.Benchmarks/Codecs/Tiff/DecodeTiff.cs
index db94fb1214..b34640bb14 100644
--- a/tests/ImageSharp.Benchmarks/Codecs/Tiff/DecodeTiff.cs
+++ b/tests/ImageSharp.Benchmarks/Codecs/Tiff/DecodeTiff.cs
@@ -46,6 +46,7 @@ public class DecodeTiff
[Params(
TestImages.Tiff.CcittFax3AllTermCodes,
+ TestImages.Tiff.Fax4Compressed2,
TestImages.Tiff.HuffmanRleAllMakeupCodes,
TestImages.Tiff.Calliphora_GrayscaleUncompressed,
TestImages.Tiff.Calliphora_RgbPaletteLzw_Predictor,
diff --git a/tests/ImageSharp.Benchmarks/Codecs/Tiff/EncodeTiff.cs b/tests/ImageSharp.Benchmarks/Codecs/Tiff/EncodeTiff.cs
index e9c61e729e..da2d94a2a2 100644
--- a/tests/ImageSharp.Benchmarks/Codecs/Tiff/EncodeTiff.cs
+++ b/tests/ImageSharp.Benchmarks/Codecs/Tiff/EncodeTiff.cs
@@ -1,6 +1,7 @@
// Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0.
+using System;
using System.Drawing.Imaging;
using System.IO;
using BenchmarkDotNet.Attributes;
@@ -9,6 +10,7 @@
using SixLabors.ImageSharp.Formats.Tiff.Constants;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Tests;
+using SDImage = System.Drawing.Image;
namespace SixLabors.ImageSharp.Benchmarks.Codecs
{
@@ -17,11 +19,10 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs
[Config(typeof(Config.ShortMultiFramework))]
public class EncodeTiff
{
- private System.Drawing.Image drawing;
+ private Stream stream;
+ private SDImage drawing;
private Image core;
- private Configuration configuration;
-
private string TestImageFullPath => Path.Combine(TestEnvironment.InputImagesDirectoryFullPath, this.TestImage);
[Params(TestImages.Tiff.Calliphora_RgbUncompressed)]
@@ -29,9 +30,11 @@ public class EncodeTiff
[Params(
TiffCompression.None,
- TiffCompression.Deflate,
+
+ // System.Drawing does not support Deflate or PackBits
+ // TiffCompression.Deflate,
+ // TiffCompression.PackBits,
TiffCompression.Lzw,
- TiffCompression.PackBits,
TiffCompression.CcittGroup3Fax,
TiffCompression.Ccitt1D)]
public TiffCompression Compression { get; set; }
@@ -39,11 +42,12 @@ public class EncodeTiff
[GlobalSetup]
public void ReadImages()
{
- if (this.core == null)
+ if (this.stream == null)
{
- this.configuration = new Configuration();
- this.core = Image.Load(this.configuration, this.TestImageFullPath);
- this.drawing = System.Drawing.Image.FromFile(this.TestImageFullPath);
+ this.stream = File.OpenRead(this.TestImageFullPath);
+ this.core = Image.Load(this.stream);
+ this.stream.Position = 0;
+ this.drawing = SDImage.FromStream(this.stream);
}
}
@@ -70,7 +74,10 @@ public void SystemDrawing()
[Benchmark(Description = "ImageSharp Tiff")]
public void TiffCore()
{
- TiffPhotometricInterpretation photometricInterpretation = TiffPhotometricInterpretation.Rgb;
+ TiffPhotometricInterpretation photometricInterpretation =
+ IsOneBitCompression(this.Compression) ?
+ TiffPhotometricInterpretation.WhiteIsZero :
+ TiffPhotometricInterpretation.Rgb;
var encoder = new TiffEncoder() { Compression = this.Compression, PhotometricInterpretation = photometricInterpretation };
using var memoryStream = new MemoryStream();
@@ -109,8 +116,18 @@ private static EncoderValue Cast(TiffCompression compression)
return EncoderValue.CompressionLZW;
default:
- throw new System.NotSupportedException(compression.ToString());
+ throw new NotSupportedException(compression.ToString());
+ }
+ }
+
+ public static bool IsOneBitCompression(TiffCompression compression)
+ {
+ if (compression is TiffCompression.Ccitt1D or TiffCompression.CcittGroup3Fax or TiffCompression.CcittGroup4Fax)
+ {
+ return true;
}
+
+ return false;
}
}
}
diff --git a/tests/ImageSharp.Benchmarks/Config.cs b/tests/ImageSharp.Benchmarks/Config.cs
index 60d0e76613..34978b594a 100644
--- a/tests/ImageSharp.Benchmarks/Config.cs
+++ b/tests/ImageSharp.Benchmarks/Config.cs
@@ -32,17 +32,13 @@ public Config()
public class MultiFramework : Config
{
public MultiFramework() => this.AddJob(
- Job.Default.WithRuntime(ClrRuntime.Net472),
- Job.Default.WithRuntime(CoreRuntime.Core31),
- Job.Default.WithRuntime(CoreRuntime.Core50).WithArguments(new Argument[] { new MsBuildArgument("/p:DebugType=portable") }));
+ Job.Default.WithRuntime(CoreRuntime.Core60).WithArguments(new Argument[] { new MsBuildArgument("/p:DebugType=portable") }));
}
public class ShortMultiFramework : Config
{
public ShortMultiFramework() => this.AddJob(
- Job.Default.WithRuntime(ClrRuntime.Net472).WithLaunchCount(1).WithWarmupCount(3).WithIterationCount(3),
- Job.Default.WithRuntime(CoreRuntime.Core31).WithLaunchCount(1).WithWarmupCount(3).WithIterationCount(3),
- Job.Default.WithRuntime(CoreRuntime.Core50).WithLaunchCount(1).WithWarmupCount(3).WithIterationCount(3).WithArguments(new Argument[] { new MsBuildArgument("/p:DebugType=portable") }));
+ Job.Default.WithRuntime(CoreRuntime.Core60).WithLaunchCount(1).WithWarmupCount(3).WithIterationCount(3).WithArguments(new Argument[] { new MsBuildArgument("/p:DebugType=portable") }));
}
public class ShortCore31 : Config
diff --git a/tests/ImageSharp.Tests/Formats/Tiff/PhotometricInterpretation/BlackIsZeroTiffColorTests.cs b/tests/ImageSharp.Tests/Formats/Tiff/PhotometricInterpretation/BlackIsZeroTiffColorTests.cs
index 38611c6f37..d4964cf778 100644
--- a/tests/ImageSharp.Tests/Formats/Tiff/PhotometricInterpretation/BlackIsZeroTiffColorTests.cs
+++ b/tests/ImageSharp.Tests/Formats/Tiff/PhotometricInterpretation/BlackIsZeroTiffColorTests.cs
@@ -13,14 +13,14 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff.PhotometricInterpretation
[Trait("Format", "Tiff")]
public class BlackIsZeroTiffColorTests : PhotometricInterpretationTestBase
{
- private static readonly Rgba32 Gray000 = new Rgba32(0, 0, 0, 255);
- private static readonly Rgba32 Gray128 = new Rgba32(128, 128, 128, 255);
- private static readonly Rgba32 Gray255 = new Rgba32(255, 255, 255, 255);
- private static readonly Rgba32 Gray0 = new Rgba32(0, 0, 0, 255);
- private static readonly Rgba32 Gray8 = new Rgba32(136, 136, 136, 255);
- private static readonly Rgba32 GrayF = new Rgba32(255, 255, 255, 255);
- private static readonly Rgba32 Bit0 = new Rgba32(0, 0, 0, 255);
- private static readonly Rgba32 Bit1 = new Rgba32(255, 255, 255, 255);
+ private static readonly Rgba32 Gray000 = new(0, 0, 0, 255);
+ private static readonly Rgba32 Gray128 = new(128, 128, 128, 255);
+ private static readonly Rgba32 Gray255 = new(255, 255, 255, 255);
+ private static readonly Rgba32 Gray0 = new(0, 0, 0, 255);
+ private static readonly Rgba32 Gray8 = new(136, 136, 136, 255);
+ private static readonly Rgba32 GrayF = new(255, 255, 255, 255);
+ private static readonly Rgba32 Bit0 = new(0, 0, 0, 255);
+ private static readonly Rgba32 Bit1 = new(255, 255, 255, 255);
private static readonly byte[] BilevelBytes4X4 =
{
@@ -30,8 +30,7 @@ public class BlackIsZeroTiffColorTests : PhotometricInterpretationTestBase
0b10010000
};
- private static readonly Rgba32[][] BilevelResult4X4 = new[]
- {
+ private static readonly Rgba32[][] BilevelResult4X4 = {
new[] { Bit0, Bit1, Bit0, Bit1 },
new[] { Bit1, Bit1, Bit1, Bit1 },
new[] { Bit0, Bit1, Bit1, Bit1 },
diff --git a/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs
index b9569c7a46..7987d76a3f 100644
--- a/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs
+++ b/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs
@@ -611,6 +611,8 @@ public void TiffDecoder_CanDecode_Fax3Compressed(TestImageProvider(TestImageProvider provider)
diff --git a/tests/ImageSharp.Tests/Formats/Tiff/TiffEncoderTests.cs b/tests/ImageSharp.Tests/Formats/Tiff/TiffEncoderTests.cs
index 93ca611c9e..d5f6df4a5f 100644
--- a/tests/ImageSharp.Tests/Formats/Tiff/TiffEncoderTests.cs
+++ b/tests/ImageSharp.Tests/Formats/Tiff/TiffEncoderTests.cs
@@ -95,6 +95,28 @@ public void EncoderOptions_UnsupportedBitPerPixel_DefaultTo24Bits(TiffBitsPerPix
Assert.Equal(TiffBitsPerPixel.Bit24, frameMetaData.BitsPerPixel);
}
+ [Theory]
+ [InlineData(TiffPhotometricInterpretation.Rgb, TiffCompression.Ccitt1D)]
+ [InlineData(TiffPhotometricInterpretation.Rgb, TiffCompression.CcittGroup3Fax)]
+ [InlineData(TiffPhotometricInterpretation.Rgb, TiffCompression.CcittGroup4Fax)]
+ public void EncoderOptions_WithInvalidCompressionAndPixelTypeCombination_DefaultsToRgb(TiffPhotometricInterpretation photometricInterpretation, TiffCompression compression)
+ {
+ // arrange
+ var tiffEncoder = new TiffEncoder { PhotometricInterpretation = photometricInterpretation, Compression = compression };
+ using Image input = new Image(10, 10);
+ using var memStream = new MemoryStream();
+
+ // act
+ input.Save(memStream, tiffEncoder);
+
+ // assert
+ memStream.Position = 0;
+ using var output = Image.Load(memStream);
+
+ TiffFrameMetadata frameMetaData = output.Frames.RootFrame.Metadata.GetTiffMetadata();
+ Assert.Equal(TiffBitsPerPixel.Bit24, frameMetaData.BitsPerPixel);
+ }
+
[Theory]
[InlineData(null, TiffCompression.Deflate, TiffBitsPerPixel.Bit24, TiffCompression.Deflate)]
[InlineData(TiffPhotometricInterpretation.Rgb, TiffCompression.Deflate, TiffBitsPerPixel.Bit24, TiffCompression.Deflate)]
diff --git a/tests/ImageSharp.Tests/TestImages.cs b/tests/ImageSharp.Tests/TestImages.cs
index ec65e2c65b..9c8fdd8d05 100644
--- a/tests/ImageSharp.Tests/TestImages.cs
+++ b/tests/ImageSharp.Tests/TestImages.cs
@@ -761,7 +761,9 @@ public static class Tiff
public const string Calliphora_HuffmanCompressed = "Tiff/Calliphora_huffman_rle.tiff";
public const string Calliphora_BiColorUncompressed = "Tiff/Calliphora_bicolor_uncompressed.tiff";
public const string Fax4Compressed = "Tiff/basi3p02_fax4.tiff";
+ public const string Fax4Compressed2 = "Tiff/CCITTGroup4.tiff";
public const string Fax4CompressedLowerOrderBitsFirst = "Tiff/basi3p02_fax4_lowerOrderBitsFirst.tiff";
+ public const string Fax4CompressedMinIsBlack = "Tiff/CCITTGroup4_minisblack.tiff";
public const string CcittFax3AllTermCodes = "Tiff/ccitt_fax3_all_terminating_codes.tiff";
public const string CcittFax3AllMakeupCodes = "Tiff/ccitt_fax3_all_makeup_codes.tiff";
diff --git a/tests/Images/Input/Tiff/CCITTGroup4.tiff b/tests/Images/Input/Tiff/CCITTGroup4.tiff
new file mode 100644
index 0000000000..20ffcd5d60
--- /dev/null
+++ b/tests/Images/Input/Tiff/CCITTGroup4.tiff
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:120ad0814f207c45d968b05f7435034ecfee8ac1a0958cd984a070dad31f66f3
+size 11082
diff --git a/tests/Images/Input/Tiff/CCITTGroup4_minisblack.tiff b/tests/Images/Input/Tiff/CCITTGroup4_minisblack.tiff
new file mode 100644
index 0000000000..8ae4647537
--- /dev/null
+++ b/tests/Images/Input/Tiff/CCITTGroup4_minisblack.tiff
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:6c12c96059a6214739fe836572bce6912dcf4a0d2ff389c840f0d2daa4465f55
+size 11637