diff --git a/src/ImageSharp/Common/Helpers/Numerics.cs b/src/ImageSharp/Common/Helpers/Numerics.cs
index bfbaa1b31..301bef297 100644
--- a/src/ImageSharp/Common/Helpers/Numerics.cs
+++ b/src/ImageSharp/Common/Helpers/Numerics.cs
@@ -75,6 +75,12 @@ namespace SixLabors.ImageSharp
[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 08d147526..37e2a6efc 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 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Compression
}
else
{
- for (int i = startIdx; i < endIdx; i++)
+ for (nint i = startIdx; i < endIdx; i++)
{
WriteZeroBit(buffer, bufferPos, bitPos);
@@ -44,8 +46,18 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Compression
}
}
- 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 316610621..f92cf1822 100644
--- a/src/ImageSharp/Formats/Tiff/Compression/Compressors/TiffCcittCompressor.cs
+++ b/src/ImageSharp/Formats/Tiff/Compression/Compressors/TiffCcittCompressor.cs
@@ -23,28 +23,28 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Compression.Compressors
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 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Compression.Compressors
{ 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 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Compression.Compressors
{ 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 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Compression.Compressors
}
///
- /// 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 0aec2361c..5b0c64cf1 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 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Compression.Decompressors
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 74a17b907..9543499d7 100644
--- a/src/ImageSharp/Formats/Tiff/Compression/Decompressors/CcittTwoDimensionalCode.cs
+++ b/src/ImageSharp/Formats/Tiff/Compression/Decompressors/CcittTwoDimensionalCode.cs
@@ -13,15 +13,21 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Compression.Decompressors
///
/// 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 89cdf7ea2..8306e91a3 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 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Compression.Decompressors
/// 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 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Compression.Decompressors
{
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 453f7d10d..54c94525c 100644
--- a/src/ImageSharp/Formats/Tiff/Compression/Decompressors/ModifiedHuffmanTiffCompression.cs
+++ b/src/ImageSharp/Formats/Tiff/Compression/Decompressors/ModifiedHuffmanTiffCompression.cs
@@ -42,11 +42,12 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Compression.Decompressors
///
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 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Compression.Decompressors
{
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 4093d8987..d7bba88fd 100644
--- a/src/ImageSharp/Formats/Tiff/Compression/Decompressors/PackBitsTiffCompression.cs
+++ b/src/ImageSharp/Formats/Tiff/Compression/Decompressors/PackBitsTiffCompression.cs
@@ -73,7 +73,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Compression.Decompressors
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 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Compression.Decompressors
}
}
- 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 9925d5a19..226bfe5da 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 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Compression.Decompressors
///
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 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Compression.Decompressors
{ 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 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Compression.Decompressors
{ 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 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Compression.Decompressors
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 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Compression.Decompressors
///
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 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Compression.Decompressors
this.terminationCodeFound = false;
}
- ///
- public void Dispose() => this.Data.Dispose();
-
///
/// An EOL is expected before the first data.
///
@@ -436,6 +434,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Compression.Decompressors
///
/// 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 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Compression.Decompressors
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 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Compression.Decompressors
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 158cac947..7b59e7117 100644
--- a/src/ImageSharp/Formats/Tiff/Compression/Decompressors/T4TiffCompression.cs
+++ b/src/ImageSharp/Formats/Tiff/Compression/Decompressors/T4TiffCompression.cs
@@ -61,11 +61,12 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Compression.Decompressors
}
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 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Compression.Decompressors
{
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 6b9939b17..0d068bb6f 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 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Compression.Decompressors
{
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 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Compression.Decompressors
/// 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 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Compression.Decompressors
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 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Compression.Decompressors
///
/// 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 972f4d8ff..7cfcfe12b 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 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Compression.Decompressors
{
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 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Compression.Decompressors
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 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Compression.Decompressors
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 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Compression.Decompressors
}
}
- 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 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Compression.Decompressors
}
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 e60562912..6f3189e70 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 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
///
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 eb749efe6..cf8f8fb73 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 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
///
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 7d230dfd5..9be8dd774 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 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
///
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 c43b121ca..fc526a86f 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 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
///
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 00e4caef7..b2ab12700 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 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
///
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 2e66bb6d7..79247d8ed 100644
--- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/BlackIsZero4TiffColor{TPixel}.cs
+++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/BlackIsZero4TiffColor{TPixel}.cs
@@ -24,6 +24,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
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 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
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 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
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 ad5793084..d0ab2383d 100644
--- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/PaletteTiffColor{TPixel}.cs
+++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/PaletteTiffColor{TPixel}.cs
@@ -19,6 +19,8 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
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 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
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 609369011..0527eaaf0 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 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
///
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 76fed3c93..fc5dc82aa 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 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
///
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 addf576e9..4fc25f2dd 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 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
///
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 2eda3b5af..59bc94802 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 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
///
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 02319bfa6..b8f9da72f 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 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
///
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 26f75bfcf..8903b8a40 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 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
///
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 7fd98dd50..2aa810623 100644
--- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/RgbFloat323232TiffColor{TPixel}.cs
+++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/RgbFloat323232TiffColor{TPixel}.cs
@@ -26,10 +26,8 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
///
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 0340438cb..d1164b67a 100644
--- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba16161616TiffColor{TPixel}.cs
+++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba16161616TiffColor{TPixel}.cs
@@ -42,11 +42,9 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
///
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 856d810d3..51e6e21df 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 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
///
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 2ce30252f..ff35a8d0d 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 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
///
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 89172cfe7..1a3459fcb 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 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
///
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 8ee9eb0bf..378338de6 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 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
///
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 c98ac1cf0..af3a888a7 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 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
///
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 967a68ad0..24cf8019c 100644
--- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba8888TiffColor{TPixel}.cs
+++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba8888TiffColor{TPixel}.cs
@@ -36,7 +36,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
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 f95045ec5..317c2db3b 100644
--- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/RgbaFloat32323232TiffColor{TPixel}.cs
+++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/RgbaFloat32323232TiffColor{TPixel}.cs
@@ -26,10 +26,8 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
///
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 d509776d7..092ba68e2 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 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
///
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 5f1afe46f..e3e95d9e1 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 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
///
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 fbf813078..d483d7faf 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 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
///
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 40d1541c5..f3b72edb5 100644
--- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/WhiteIsZero32FloatTiffColor{TPixel}.cs
+++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/WhiteIsZero32FloatTiffColor{TPixel}.cs
@@ -26,10 +26,8 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
///
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 fd908c1e9..48e24deda 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 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
///
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 a4650af5e..8b635043e 100644
--- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/WhiteIsZero4TiffColor{TPixel}.cs
+++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/WhiteIsZero4TiffColor{TPixel}.cs
@@ -24,6 +24,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
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 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
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 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
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 3409b3dd8..9a953a269 100644
--- a/src/ImageSharp/Formats/Tiff/TiffEncoderCore.cs
+++ b/src/ImageSharp/Formats/Tiff/TiffEncoderCore.cs
@@ -343,7 +343,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff
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 @@ namespace SixLabors.ImageSharp.Formats.Tiff
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 @@ namespace SixLabors.ImageSharp.Formats.Tiff
{
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 @@ namespace SixLabors.ImageSharp.Formats.Tiff
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 532423c4f..2f1ddcf21 100644
--- a/src/ImageSharp/Formats/Tiff/Utils/TiffUtils.cs
+++ b/src/ImageSharp/Formats/Tiff/Utils/TiffUtils.cs
@@ -18,8 +18,6 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Utils
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 db94fb121..b34640bb1 100644
--- a/tests/ImageSharp.Benchmarks/Codecs/Tiff/DecodeTiff.cs
+++ b/tests/ImageSharp.Benchmarks/Codecs/Tiff/DecodeTiff.cs
@@ -46,6 +46,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs
[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 e9c61e729..da2d94a2a 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;
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 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs
[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 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs
[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 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs
[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 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs
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 60d0e7661..34978b594 100644
--- a/tests/ImageSharp.Benchmarks/Config.cs
+++ b/tests/ImageSharp.Benchmarks/Config.cs
@@ -32,17 +32,13 @@ namespace SixLabors.ImageSharp.Benchmarks
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 38611c6f3..d4964cf77 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 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff.PhotometricInterpretation
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 b9569c7a4..7987d76a3 100644
--- a/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs
+++ b/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs
@@ -611,6 +611,8 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff
[Theory]
[WithFile(Fax4Compressed, PixelTypes.Rgba32)]
+ [WithFile(Fax4Compressed2, PixelTypes.Rgba32)]
+ [WithFile(Fax4CompressedMinIsBlack, PixelTypes.Rgba32)]
[WithFile(Fax4CompressedLowerOrderBitsFirst, PixelTypes.Rgba32)]
[WithFile(Calliphora_Fax4Compressed, PixelTypes.Rgba32)]
public void TiffDecoder_CanDecode_Fax4Compressed(TestImageProvider provider)
diff --git a/tests/ImageSharp.Tests/Formats/Tiff/TiffEncoderTests.cs b/tests/ImageSharp.Tests/Formats/Tiff/TiffEncoderTests.cs
index 93ca611c9..d5f6df4a5 100644
--- a/tests/ImageSharp.Tests/Formats/Tiff/TiffEncoderTests.cs
+++ b/tests/ImageSharp.Tests/Formats/Tiff/TiffEncoderTests.cs
@@ -95,6 +95,28 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff
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 ec65e2c65..9c8fdd8d0 100644
--- a/tests/ImageSharp.Tests/TestImages.cs
+++ b/tests/ImageSharp.Tests/TestImages.cs
@@ -761,7 +761,9 @@ namespace SixLabors.ImageSharp.Tests
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 000000000..20ffcd5d6
--- /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 000000000..8ae464753
--- /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