diff --git a/src/ImageSharp/Common/Helpers/Numerics.cs b/src/ImageSharp/Common/Helpers/Numerics.cs
index bfbaa1b31c..301bef297f 100644
--- a/src/ImageSharp/Common/Helpers/Numerics.cs
+++ b/src/ImageSharp/Common/Helpers/Numerics.cs
@@ -75,6 +75,12 @@ 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/Jpeg/Components/Block8x8F.Intrinsic.cs b/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.Intrinsic.cs
index 0971ccdca0..879d64458d 100644
--- a/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.Intrinsic.cs
+++ b/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.Intrinsic.cs
@@ -35,8 +35,6 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components
[FieldOffset(224)]
public Vector256 V7;
- private static readonly Vector256 MultiplyIntoInt16ShuffleMask = Vector256.Create(0, 1, 4, 5, 2, 3, 6, 7);
-
private static unsafe void MultiplyIntoInt16_Avx2(ref Block8x8F a, ref Block8x8F b, ref Block8x8 dest)
{
DebugGuard.IsTrue(Avx2.IsSupported, "Avx2 support is required to run this operation!");
@@ -45,6 +43,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components
ref Vector256 bBase = ref b.V0;
ref Vector256 destRef = ref dest.V01;
+ Vector256 multiplyIntoInt16ShuffleMask = Vector256.Create(0, 1, 4, 5, 2, 3, 6, 7);
for (nint i = 0; i < 8; i += 2)
{
@@ -52,7 +51,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components
Vector256 row1 = Avx.ConvertToVector256Int32(Avx.Multiply(Unsafe.Add(ref aBase, i + 1), Unsafe.Add(ref bBase, i + 1)));
Vector256 row = Avx2.PackSignedSaturate(row0, row1);
- row = Avx2.PermuteVar8x32(row.AsInt32(), MultiplyIntoInt16ShuffleMask).AsInt16();
+ row = Avx2.PermuteVar8x32(row.AsInt32(), multiplyIntoInt16ShuffleMask).AsInt16();
Unsafe.Add(ref destRef, (IntPtr)((uint)i / 2)) = row;
}
diff --git a/src/ImageSharp/Formats/Jpeg/Components/FastFloatingPointDCT.Intrinsic.cs b/src/ImageSharp/Formats/Jpeg/Components/FastFloatingPointDCT.Intrinsic.cs
index 8acc4b6269..86640842e1 100644
--- a/src/ImageSharp/Formats/Jpeg/Components/FastFloatingPointDCT.Intrinsic.cs
+++ b/src/ImageSharp/Formats/Jpeg/Components/FastFloatingPointDCT.Intrinsic.cs
@@ -9,18 +9,6 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components
{
internal static partial class FastFloatingPointDCT
{
-#pragma warning disable SA1310, SA1311, IDE1006 // naming rule violation warnings
- private static readonly Vector256 mm256_F_0_7071 = Vector256.Create(0.707106781f);
- private static readonly Vector256 mm256_F_0_3826 = Vector256.Create(0.382683433f);
- private static readonly Vector256 mm256_F_0_5411 = Vector256.Create(0.541196100f);
- private static readonly Vector256 mm256_F_1_3065 = Vector256.Create(1.306562965f);
-
- private static readonly Vector256 mm256_F_1_4142 = Vector256.Create(1.414213562f);
- private static readonly Vector256 mm256_F_1_8477 = Vector256.Create(1.847759065f);
- private static readonly Vector256 mm256_F_n1_0823 = Vector256.Create(-1.082392200f);
- private static readonly Vector256 mm256_F_n2_6131 = Vector256.Create(-2.613125930f);
-#pragma warning restore SA1310, SA1311, IDE1006
-
///
/// Apply floating point FDCT inplace using simd operations.
///
@@ -57,6 +45,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components
block.V0 = Avx.Add(tmp10, tmp11);
block.V4 = Avx.Subtract(tmp10, tmp11);
+ Vector256 mm256_F_0_7071 = Vector256.Create(0.707106781f);
Vector256 z1 = Avx.Multiply(Avx.Add(tmp12, tmp13), mm256_F_0_7071);
block.V2 = Avx.Add(tmp13, z1);
block.V6 = Avx.Subtract(tmp13, z1);
@@ -66,9 +55,9 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components
tmp11 = Avx.Add(tmp5, tmp6);
tmp12 = Avx.Add(tmp6, tmp7);
- Vector256 z5 = Avx.Multiply(Avx.Subtract(tmp10, tmp12), mm256_F_0_3826);
- Vector256 z2 = SimdUtils.HwIntrinsics.MultiplyAdd(z5, mm256_F_0_5411, tmp10);
- Vector256 z4 = SimdUtils.HwIntrinsics.MultiplyAdd(z5, mm256_F_1_3065, tmp12);
+ Vector256 z5 = Avx.Multiply(Avx.Subtract(tmp10, tmp12), Vector256.Create(0.382683433f)); // mm256_F_0_3826
+ Vector256 z2 = SimdUtils.HwIntrinsics.MultiplyAdd(z5, Vector256.Create(0.541196100f), tmp10); // mm256_F_0_5411
+ Vector256 z4 = SimdUtils.HwIntrinsics.MultiplyAdd(z5, Vector256.Create(1.306562965f), tmp12); // mm256_F_1_3065
Vector256 z3 = Avx.Multiply(tmp11, mm256_F_0_7071);
Vector256 z11 = Avx.Add(tmp7, z3);
@@ -109,6 +98,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components
Vector256 tmp10 = Avx.Add(z5, tmp2);
Vector256 tmp11 = Avx.Subtract(z5, tmp2);
+ Vector256 mm256_F_1_4142 = Vector256.Create(1.414213562f);
Vector256 tmp13 = Avx.Add(tmp1, tmp3);
Vector256 tmp12 = SimdUtils.HwIntrinsics.MultiplySubstract(tmp13, Avx.Subtract(tmp1, tmp3), mm256_F_1_4142);
@@ -131,10 +121,10 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components
tmp7 = Avx.Add(z11, z13);
tmp11 = Avx.Multiply(Avx.Subtract(z11, z13), mm256_F_1_4142);
- z5 = Avx.Multiply(Avx.Add(z10, z12), mm256_F_1_8477);
+ z5 = Avx.Multiply(Avx.Add(z10, z12), Vector256.Create(1.847759065f)); // mm256_F_1_8477
- tmp10 = SimdUtils.HwIntrinsics.MultiplyAdd(z5, z12, mm256_F_n1_0823);
- tmp12 = SimdUtils.HwIntrinsics.MultiplyAdd(z5, z10, mm256_F_n2_6131);
+ tmp10 = SimdUtils.HwIntrinsics.MultiplyAdd(z5, z12, Vector256.Create(-1.082392200f)); // mm256_F_n1_0823
+ tmp12 = SimdUtils.HwIntrinsics.MultiplyAdd(z5, z10, Vector256.Create(-2.613125930f)); // mm256_F_n2_6131
tmp6 = Avx.Subtract(tmp12, tmp7);
tmp5 = Avx.Subtract(tmp11, tmp6);
diff --git a/src/ImageSharp/Formats/Tiff/Compression/BitWriterUtils.cs b/src/ImageSharp/Formats/Tiff/Compression/BitWriterUtils.cs
index 08d1475268..37e2a6efcb 100644
--- a/src/ImageSharp/Formats/Tiff/Compression/BitWriterUtils.cs
+++ b/src/ImageSharp/Formats/Tiff/Compression/BitWriterUtils.cs
@@ -2,21 +2,23 @@
// Licensed under the Apache License, Version 2.0.
using System;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
namespace SixLabors.ImageSharp.Formats.Tiff.Compression
{
internal static class BitWriterUtils
{
- public static void WriteBits(Span buffer, int pos, uint count, byte value)
+ public static void WriteBits(Span buffer, nint pos, nint count, byte value)
{
- int bitPos = pos % 8;
- int bufferPos = pos / 8;
- int startIdx = bufferPos + bitPos;
- int endIdx = (int)(startIdx + count);
+ nint bitPos = Numerics.Modulo8(pos);
+ nint bufferPos = pos / 8;
+ nint startIdx = bufferPos + bitPos;
+ nint endIdx = startIdx + count;
if (value == 1)
{
- for (int i = startIdx; i < endIdx; i++)
+ for (nint i = startIdx; i < endIdx; i++)
{
WriteBit(buffer, bufferPos, bitPos);
@@ -30,7 +32,7 @@ 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 3166106216..f92cf1822a 100644
--- a/src/ImageSharp/Formats/Tiff/Compression/Compressors/TiffCcittCompressor.cs
+++ b/src/ImageSharp/Formats/Tiff/Compression/Compressors/TiffCcittCompressor.cs
@@ -23,28 +23,28 @@ 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 0aec2361c3..5b0c64cf18 100644
--- a/src/ImageSharp/Formats/Tiff/Compression/Decompressors/CcittReferenceScanline.cs
+++ b/src/ImageSharp/Formats/Tiff/Compression/Decompressors/CcittReferenceScanline.cs
@@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0.
using System;
+using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.Formats.Tiff.Compression.Decompressors
{
@@ -130,6 +131,7 @@ 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 74a17b9075..9543499d7f 100644
--- a/src/ImageSharp/Formats/Tiff/Compression/Decompressors/CcittTwoDimensionalCode.cs
+++ b/src/ImageSharp/Formats/Tiff/Compression/Decompressors/CcittTwoDimensionalCode.cs
@@ -13,15 +13,21 @@ 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 89cdf7ea2b..8306e91a34 100644
--- a/src/ImageSharp/Formats/Tiff/Compression/Decompressors/ModifiedHuffmanBitReader.cs
+++ b/src/ImageSharp/Formats/Tiff/Compression/Decompressors/ModifiedHuffmanBitReader.cs
@@ -1,9 +1,8 @@
// Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0.
-using System.IO;
using SixLabors.ImageSharp.Formats.Tiff.Constants;
-using SixLabors.ImageSharp.Memory;
+using SixLabors.ImageSharp.IO;
namespace SixLabors.ImageSharp.Formats.Tiff.Compression.Decompressors
{
@@ -19,14 +18,13 @@ 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 453f7d10dd..54c94525c5 100644
--- a/src/ImageSharp/Formats/Tiff/Compression/Decompressors/ModifiedHuffmanTiffCompression.cs
+++ b/src/ImageSharp/Formats/Tiff/Compression/Decompressors/ModifiedHuffmanTiffCompression.cs
@@ -42,11 +42,12 @@ 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 4093d89871..d7bba88fd9 100644
--- a/src/ImageSharp/Formats/Tiff/Compression/Decompressors/PackBitsTiffCompression.cs
+++ b/src/ImageSharp/Formats/Tiff/Compression/Decompressors/PackBitsTiffCompression.cs
@@ -73,7 +73,7 @@ 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 9925d5a194..226bfe5dad 100644
--- a/src/ImageSharp/Formats/Tiff/Compression/Decompressors/T4BitReader.cs
+++ b/src/ImageSharp/Formats/Tiff/Compression/Decompressors/T4BitReader.cs
@@ -1,20 +1,17 @@
// Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0.
-using System;
-using System.Buffers;
using System.Collections.Generic;
-using System.IO;
using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.Formats.Tiff.Constants;
-using SixLabors.ImageSharp.Memory;
+using SixLabors.ImageSharp.IO;
namespace SixLabors.ImageSharp.Formats.Tiff.Compression.Decompressors
{
///
/// Bitreader for reading compressed CCITT T4 1D data.
///
- internal class T4BitReader : IDisposable
+ internal class T4BitReader
{
///
/// The logical order of bits within a byte.
@@ -52,28 +49,28 @@ 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 158cac9471..7b59e71173 100644
--- a/src/ImageSharp/Formats/Tiff/Compression/Decompressors/T4TiffCompression.cs
+++ b/src/ImageSharp/Formats/Tiff/Compression/Decompressors/T4TiffCompression.cs
@@ -61,11 +61,12 @@ 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 6b9939b175..0d068bb6fd 100644
--- a/src/ImageSharp/Formats/Tiff/Compression/Decompressors/T6BitReader.cs
+++ b/src/ImageSharp/Formats/Tiff/Compression/Decompressors/T6BitReader.cs
@@ -1,10 +1,9 @@
// Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0.
-using System.Collections.Generic;
-using System.IO;
+using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.Formats.Tiff.Constants;
-using SixLabors.ImageSharp.Memory;
+using SixLabors.ImageSharp.IO;
namespace SixLabors.ImageSharp.Formats.Tiff.Compression.Decompressors
{
@@ -16,38 +15,23 @@ 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 972f4d8ff1..8a94ead1e6 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);
}
///
@@ -53,15 +52,16 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Compression.Decompressors
protected override void Decompress(BufferedReadStream stream, int byteCount, int stripHeight, Span buffer)
{
int height = stripHeight;
+ buffer.Clear();
using System.Buffers.IMemoryOwner scanLineBuffer = this.Allocator.Allocate(this.width * 2);
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 +74,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 +135,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 e605629122..6f3189e706 100644
--- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/BlackIsZero16TiffColor{TPixel}.cs
+++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/BlackIsZero16TiffColor{TPixel}.cs
@@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0.
using System;
+using System.Numerics;
using SixLabors.ImageSharp.Formats.Tiff.Utils;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
@@ -32,11 +33,9 @@ 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 eb749efe62..cf8f8fb734 100644
--- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/BlackIsZero1TiffColor{TPixel}.cs
+++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/BlackIsZero1TiffColor{TPixel}.cs
@@ -2,6 +2,8 @@
// Licensed under the Apache License, Version 2.0.
using System;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
@@ -17,26 +19,65 @@ 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 7d230dfd5e..9be8dd7741 100644
--- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/BlackIsZero24TiffColor{TPixel}.cs
+++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/BlackIsZero24TiffColor{TPixel}.cs
@@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0.
using System;
+using System.Numerics;
using SixLabors.ImageSharp.Formats.Tiff.Utils;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
@@ -25,14 +26,12 @@ 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 c43b121caf..fc526a86f5 100644
--- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/BlackIsZero32FloatTiffColor{TPixel}.cs
+++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/BlackIsZero32FloatTiffColor{TPixel}.cs
@@ -3,7 +3,6 @@
using System;
using System.Numerics;
-using SixLabors.ImageSharp.Formats.Tiff.Utils;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
@@ -26,10 +25,8 @@ 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 00e4caef79..b2ab127003 100644
--- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/BlackIsZero32TiffColor{TPixel}.cs
+++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/BlackIsZero32TiffColor{TPixel}.cs
@@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0.
using System;
+using System.Numerics;
using SixLabors.ImageSharp.Formats.Tiff.Utils;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
@@ -25,10 +26,8 @@ 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 2e66bb6d70..79247d8ed0 100644
--- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/BlackIsZero4TiffColor{TPixel}.cs
+++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/BlackIsZero4TiffColor{TPixel}.cs
@@ -24,6 +24,7 @@ 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 ad5793084b..d0ab2383d7 100644
--- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/PaletteTiffColor{TPixel}.cs
+++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/PaletteTiffColor{TPixel}.cs
@@ -19,6 +19,8 @@ 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 6093690117..0527eaaf0f 100644
--- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgb161616TiffColor{TPixel}.cs
+++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgb161616TiffColor{TPixel}.cs
@@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0.
using System;
+using System.Numerics;
using SixLabors.ImageSharp.Formats.Tiff.Utils;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
@@ -32,11 +33,9 @@ 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 76fed3c93e..fc5dc82aab 100644
--- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgb16PlanarTiffColor{TPixel}.cs
+++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgb16PlanarTiffColor{TPixel}.cs
@@ -3,6 +3,7 @@
using System;
using System.Buffers;
+using System.Numerics;
using SixLabors.ImageSharp.Formats.Tiff.Utils;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
@@ -26,11 +27,9 @@ 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 addf576e95..4fc25f2dd0 100644
--- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgb242424TiffColor{TPixel}.cs
+++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgb242424TiffColor{TPixel}.cs
@@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0.
using System;
+using System.Numerics;
using SixLabors.ImageSharp.Formats.Tiff.Utils;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
@@ -25,10 +26,8 @@ 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 2eda3b5af7..59bc94802f 100644
--- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgb24PlanarTiffColor{TPixel}.cs
+++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgb24PlanarTiffColor{TPixel}.cs
@@ -3,6 +3,7 @@
using System;
using System.Buffers;
+using System.Numerics;
using SixLabors.ImageSharp.Formats.Tiff.Utils;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
@@ -26,10 +27,8 @@ 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 02319bfa66..b8f9da72ff 100644
--- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgb323232TiffColor{TPixel}.cs
+++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgb323232TiffColor{TPixel}.cs
@@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0.
using System;
+using System.Numerics;
using SixLabors.ImageSharp.Formats.Tiff.Utils;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
@@ -25,10 +26,8 @@ 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 26f75bfcf8..8903b8a40f 100644
--- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgb32PlanarTiffColor{TPixel}.cs
+++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgb32PlanarTiffColor{TPixel}.cs
@@ -3,6 +3,7 @@
using System;
using System.Buffers;
+using System.Numerics;
using SixLabors.ImageSharp.Formats.Tiff.Utils;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
@@ -26,10 +27,8 @@ 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 7fd98dd504..2aa810623e 100644
--- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/RgbFloat323232TiffColor{TPixel}.cs
+++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/RgbFloat323232TiffColor{TPixel}.cs
@@ -26,10 +26,8 @@ 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 0340438cbf..d1164b67a3 100644
--- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba16161616TiffColor{TPixel}.cs
+++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba16161616TiffColor{TPixel}.cs
@@ -42,11 +42,9 @@ 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 856d810d31..51e6e21dfa 100644
--- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba16PlanarTiffColor{TPixel}.cs
+++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba16PlanarTiffColor{TPixel}.cs
@@ -3,6 +3,7 @@
using System;
using System.Buffers;
+using System.Numerics;
using SixLabors.ImageSharp.Formats.Tiff.Utils;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
@@ -33,11 +34,9 @@ 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 2ce30252f5..ff35a8d0dd 100644
--- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba24242424TiffColor{TPixel}.cs
+++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba24242424TiffColor{TPixel}.cs
@@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0.
using System;
+using System.Numerics;
using SixLabors.ImageSharp.Formats.Tiff.Utils;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
@@ -32,10 +33,8 @@ 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 89172cfe72..1a3459fcb6 100644
--- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba24PlanarTiffColor{TPixel}.cs
+++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba24PlanarTiffColor{TPixel}.cs
@@ -3,6 +3,7 @@
using System;
using System.Buffers;
+using System.Numerics;
using SixLabors.ImageSharp.Formats.Tiff.Utils;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
@@ -33,10 +34,8 @@ 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 8ee9eb0bf9..378338de6e 100644
--- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba32323232TiffColor{TPixel}.cs
+++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba32323232TiffColor{TPixel}.cs
@@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0.
using System;
+using System.Numerics;
using SixLabors.ImageSharp.Formats.Tiff.Utils;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
@@ -32,10 +33,8 @@ 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 c98ac1cf00..af3a888a79 100644
--- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba32PlanarTiffColor{TPixel}.cs
+++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba32PlanarTiffColor{TPixel}.cs
@@ -3,6 +3,7 @@
using System;
using System.Buffers;
+using System.Numerics;
using SixLabors.ImageSharp.Formats.Tiff.Utils;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
@@ -33,10 +34,8 @@ 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 967a68ad0c..24cf8019ce 100644
--- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba8888TiffColor{TPixel}.cs
+++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba8888TiffColor{TPixel}.cs
@@ -36,7 +36,7 @@ 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 f95045ec5a..317c2db3b3 100644
--- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/RgbaFloat32323232TiffColor{TPixel}.cs
+++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/RgbaFloat32323232TiffColor{TPixel}.cs
@@ -26,10 +26,8 @@ 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 d509776d7d..092ba68e2e 100644
--- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/WhiteIsZero16TiffColor{TPixel}.cs
+++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/WhiteIsZero16TiffColor{TPixel}.cs
@@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0.
using System;
+using System.Numerics;
using SixLabors.ImageSharp.Formats.Tiff.Utils;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
@@ -25,11 +26,9 @@ 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 5f1afe46ff..e3e95d9e12 100644
--- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/WhiteIsZero1TiffColor{TPixel}.cs
+++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/WhiteIsZero1TiffColor{TPixel}.cs
@@ -2,6 +2,8 @@
// Licensed under the Apache License, Version 2.0.
using System;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
@@ -16,26 +18,65 @@ 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 fbf8130789..d483d7faf8 100644
--- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/WhiteIsZero24TiffColor{TPixel}.cs
+++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/WhiteIsZero24TiffColor{TPixel}.cs
@@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0.
using System;
+using System.Numerics;
using SixLabors.ImageSharp.Formats.Tiff.Utils;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
@@ -25,15 +26,13 @@ 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 40d1541c51..f3b72edb5f 100644
--- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/WhiteIsZero32FloatTiffColor{TPixel}.cs
+++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/WhiteIsZero32FloatTiffColor{TPixel}.cs
@@ -26,10 +26,8 @@ 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 fd908c1e9f..48e24dedae 100644
--- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/WhiteIsZero32TiffColor{TPixel}.cs
+++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/WhiteIsZero32TiffColor{TPixel}.cs
@@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0.
using System;
+using System.Numerics;
using SixLabors.ImageSharp.Formats.Tiff.Utils;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
@@ -25,10 +26,8 @@ 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 a4650af5ea..8b635043ec 100644
--- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/WhiteIsZero4TiffColor{TPixel}.cs
+++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/WhiteIsZero4TiffColor{TPixel}.cs
@@ -24,6 +24,7 @@ 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 3409b3dd8a..9a953a2695 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 532423c4f1..2f1ddcf21c 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/src/ImageSharp/Formats/Webp/Lossless/ColorSpaceTransformUtils.cs b/src/ImageSharp/Formats/Webp/Lossless/ColorSpaceTransformUtils.cs
index 71f3c5ca9e..6a7f4c9b0e 100644
--- a/src/ImageSharp/Formats/Webp/Lossless/ColorSpaceTransformUtils.cs
+++ b/src/ImageSharp/Formats/Webp/Lossless/ColorSpaceTransformUtils.cs
@@ -13,36 +13,6 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
{
internal static class ColorSpaceTransformUtils
{
-#if SUPPORTS_RUNTIME_INTRINSICS
- private static readonly Vector128 CollectColorRedTransformsGreenMask = Vector128.Create(0x00ff00).AsByte();
-
- private static readonly Vector128 CollectColorRedTransformsAndMask = Vector128.Create((short)0xff).AsByte();
-
- private static readonly Vector256 CollectColorRedTransformsGreenMask256 = Vector256.Create(0x00ff00).AsByte();
-
- private static readonly Vector256 CollectColorRedTransformsAndMask256 = Vector256.Create((short)0xff).AsByte();
-
- private static readonly Vector128 CollectColorBlueTransformsGreenMask = Vector128.Create(0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255);
-
- private static readonly Vector128 CollectColorBlueTransformsGreenBlueMask = Vector128.Create(255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0);
-
- private static readonly Vector128 CollectColorBlueTransformsBlueMask = Vector128.Create(255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0);
-
- private static readonly Vector128 CollectColorBlueTransformsShuffleLowMask = Vector128.Create(255, 2, 255, 6, 255, 10, 255, 14, 255, 255, 255, 255, 255, 255, 255, 255);
-
- private static readonly Vector128 CollectColorBlueTransformsShuffleHighMask = Vector128.Create(255, 255, 255, 255, 255, 255, 255, 255, 255, 2, 255, 6, 255, 10, 255, 14);
-
- private static readonly Vector256 CollectColorBlueTransformsShuffleLowMask256 = Vector256.Create(255, 2, 255, 6, 255, 10, 255, 14, 255, 255, 255, 255, 255, 255, 255, 255, 255, 18, 255, 22, 255, 26, 255, 30, 255, 255, 255, 255, 255, 255, 255, 255);
-
- private static readonly Vector256 CollectColorBlueTransformsShuffleHighMask256 = Vector256.Create(255, 255, 255, 255, 255, 255, 255, 255, 255, 2, 255, 6, 255, 10, 255, 14, 255, 255, 255, 255, 255, 255, 255, 255, 255, 18, 255, 22, 255, 26, 255, 30);
-
- private static readonly Vector256 CollectColorBlueTransformsGreenBlueMask256 = Vector256.Create(255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0);
-
- private static readonly Vector256 CollectColorBlueTransformsBlueMask256 = Vector256.Create(255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0);
-
- private static readonly Vector256 CollectColorBlueTransformsGreenMask256 = Vector256.Create(0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255);
-#endif
-
public static void CollectColorBlueTransforms(Span bgra, int stride, int tileWidth, int tileHeight, int greenToBlue, int redToBlue, Span histo)
{
#if SUPPORTS_RUNTIME_INTRINSICS
@@ -50,8 +20,13 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
{
const int span = 16;
Span values = stackalloc ushort[span];
- var multsr = Vector256.Create(LosslessUtils.Cst5b(redToBlue));
- var multsg = Vector256.Create(LosslessUtils.Cst5b(greenToBlue));
+ Vector256 collectColorBlueTransformsShuffleLowMask256 = Vector256.Create(255, 2, 255, 6, 255, 10, 255, 14, 255, 255, 255, 255, 255, 255, 255, 255, 255, 18, 255, 22, 255, 26, 255, 30, 255, 255, 255, 255, 255, 255, 255, 255);
+ Vector256 collectColorBlueTransformsShuffleHighMask256 = Vector256.Create(255, 255, 255, 255, 255, 255, 255, 255, 255, 2, 255, 6, 255, 10, 255, 14, 255, 255, 255, 255, 255, 255, 255, 255, 255, 18, 255, 22, 255, 26, 255, 30);
+ Vector256 collectColorBlueTransformsGreenBlueMask256 = Vector256.Create(255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0);
+ Vector256 collectColorBlueTransformsGreenMask256 = Vector256.Create(0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255);
+ Vector256 collectColorBlueTransformsBlueMask256 = Vector256.Create(255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0);
+ Vector256 multsr = Vector256.Create(LosslessUtils.Cst5b(redToBlue));
+ Vector256 multsg = Vector256.Create(LosslessUtils.Cst5b(greenToBlue));
for (int y = 0; y < tileHeight; y++)
{
Span srcSpan = bgra.Slice(y * stride);
@@ -62,18 +37,18 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
nint input1Idx = x + (span / 2);
Vector256 input0 = Unsafe.As>(ref Unsafe.Add(ref inputRef, input0Idx)).AsByte();
Vector256 input1 = Unsafe.As>(ref Unsafe.Add(ref inputRef, input1Idx)).AsByte();
- Vector256 r0 = Avx2.Shuffle(input0, CollectColorBlueTransformsShuffleLowMask256);
- Vector256 r1 = Avx2.Shuffle(input1, CollectColorBlueTransformsShuffleHighMask256);
+ Vector256 r0 = Avx2.Shuffle(input0, collectColorBlueTransformsShuffleLowMask256);
+ Vector256 r1 = Avx2.Shuffle(input1, collectColorBlueTransformsShuffleHighMask256);
Vector256 r = Avx2.Or(r0, r1);
- Vector256 gb0 = Avx2.And(input0, CollectColorBlueTransformsGreenBlueMask256);
- Vector256 gb1 = Avx2.And(input1, CollectColorBlueTransformsGreenBlueMask256);
+ Vector256 gb0 = Avx2.And(input0, collectColorBlueTransformsGreenBlueMask256);
+ Vector256 gb1 = Avx2.And(input1, collectColorBlueTransformsGreenBlueMask256);
Vector256 gb = Avx2.PackUnsignedSaturate(gb0.AsInt32(), gb1.AsInt32());
- Vector256 g = Avx2.And(gb.AsByte(), CollectColorBlueTransformsGreenMask256);
+ Vector256 g = Avx2.And(gb.AsByte(), collectColorBlueTransformsGreenMask256);
Vector256 a = Avx2.MultiplyHigh(r.AsInt16(), multsr);
Vector256 b = Avx2.MultiplyHigh(g.AsInt16(), multsg);
Vector256 c = Avx2.Subtract(gb.AsByte(), b.AsByte());
Vector256 d = Avx2.Subtract(c, a.AsByte());
- Vector256 e = Avx2.And(d, CollectColorBlueTransformsBlueMask256);
+ Vector256 e = Avx2.And(d, collectColorBlueTransformsBlueMask256);
ref ushort outputRef = ref MemoryMarshal.GetReference(values);
Unsafe.As>(ref outputRef) = e.AsUInt16();
@@ -95,8 +70,13 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
{
const int span = 8;
Span values = stackalloc ushort[span];
- var multsr = Vector128.Create(LosslessUtils.Cst5b(redToBlue));
- var multsg = Vector128.Create(LosslessUtils.Cst5b(greenToBlue));
+ Vector128 collectColorBlueTransformsShuffleLowMask = Vector128.Create(255, 2, 255, 6, 255, 10, 255, 14, 255, 255, 255, 255, 255, 255, 255, 255);
+ Vector128 collectColorBlueTransformsShuffleHighMask = Vector128.Create(255, 255, 255, 255, 255, 255, 255, 255, 255, 2, 255, 6, 255, 10, 255, 14);
+ Vector128 collectColorBlueTransformsGreenBlueMask = Vector128.Create(255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0);
+ Vector128 collectColorBlueTransformsGreenMask = Vector128.Create(0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255);
+ Vector128 collectColorBlueTransformsBlueMask = Vector128.Create(255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0);
+ Vector128 multsr = Vector128.Create(LosslessUtils.Cst5b(redToBlue));
+ Vector128 multsg = Vector128.Create(LosslessUtils.Cst5b(greenToBlue));
for (int y = 0; y < tileHeight; y++)
{
Span srcSpan = bgra.Slice(y * stride);
@@ -107,18 +87,18 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
nint input1Idx = x + (span / 2);
Vector128 input0 = Unsafe.As>(ref Unsafe.Add(ref inputRef, input0Idx)).AsByte();
Vector128 input1 = Unsafe.As>(ref Unsafe.Add(ref inputRef, input1Idx)).AsByte();
- Vector128 r0 = Ssse3.Shuffle(input0, CollectColorBlueTransformsShuffleLowMask);
- Vector128 r1 = Ssse3.Shuffle(input1, CollectColorBlueTransformsShuffleHighMask);
+ Vector128 r0 = Ssse3.Shuffle(input0, collectColorBlueTransformsShuffleLowMask);
+ Vector128 r1 = Ssse3.Shuffle(input1, collectColorBlueTransformsShuffleHighMask);
Vector128 r = Sse2.Or(r0, r1);
- Vector128 gb0 = Sse2.And(input0, CollectColorBlueTransformsGreenBlueMask);
- Vector128 gb1 = Sse2.And(input1, CollectColorBlueTransformsGreenBlueMask);
+ Vector128 gb0 = Sse2.And(input0, collectColorBlueTransformsGreenBlueMask);
+ Vector128 gb1 = Sse2.And(input1, collectColorBlueTransformsGreenBlueMask);
Vector128 gb = Sse41.PackUnsignedSaturate(gb0.AsInt32(), gb1.AsInt32());
- Vector128 g = Sse2.And(gb.AsByte(), CollectColorBlueTransformsGreenMask);
+ Vector128 g = Sse2.And(gb.AsByte(), collectColorBlueTransformsGreenMask);
Vector128 a = Sse2.MultiplyHigh(r.AsInt16(), multsr);
Vector128 b = Sse2.MultiplyHigh(g.AsInt16(), multsg);
Vector128 c = Sse2.Subtract(gb.AsByte(), b.AsByte());
Vector128 d = Sse2.Subtract(c, a.AsByte());
- Vector128 e = Sse2.And(d, CollectColorBlueTransformsBlueMask);
+ Vector128 e = Sse2.And(d, collectColorBlueTransformsBlueMask);
ref ushort outputRef = ref MemoryMarshal.GetReference(values);
Unsafe.As>(ref outputRef) = e.AsUInt16();
@@ -163,7 +143,9 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
#if SUPPORTS_RUNTIME_INTRINSICS
if (Avx2.IsSupported && tileWidth >= 16)
{
- var multsg = Vector256.Create(LosslessUtils.Cst5b(greenToRed));
+ Vector256 collectColorRedTransformsGreenMask256 = Vector256.Create(0x00ff00).AsByte();
+ Vector256 collectColorRedTransformsAndMask256 = Vector256.Create((short)0xff).AsByte();
+ Vector256 multsg = Vector256.Create(LosslessUtils.Cst5b(greenToRed));
const int span = 16;
Span values = stackalloc ushort[span];
for (int y = 0; y < tileHeight; y++)
@@ -176,15 +158,15 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
nint input1Idx = x + (span / 2);
Vector256 input0 = Unsafe.As>(ref Unsafe.Add(ref inputRef, input0Idx)).AsByte();
Vector256 input1 = Unsafe.As>(ref Unsafe.Add(ref inputRef, input1Idx)).AsByte();
- Vector256 g0 = Avx2.And(input0, CollectColorRedTransformsGreenMask256); // 0 0 | g 0
- Vector256 g1 = Avx2.And(input1, CollectColorRedTransformsGreenMask256);
+ Vector256 g0 = Avx2.And(input0, collectColorRedTransformsGreenMask256); // 0 0 | g 0
+ Vector256 g1 = Avx2.And(input1, collectColorRedTransformsGreenMask256);
Vector256 g = Avx2.PackUnsignedSaturate(g0.AsInt32(), g1.AsInt32()); // g 0
Vector256 a0 = Avx2.ShiftRightLogical(input0.AsInt32(), 16); // 0 0 | x r
Vector256 a1 = Avx2.ShiftRightLogical(input1.AsInt32(), 16);
Vector256 a = Avx2.PackUnsignedSaturate(a0, a1); // x r
Vector256 b = Avx2.MultiplyHigh(g.AsInt16(), multsg); // x dr
Vector256 c = Avx2.Subtract(a.AsByte(), b.AsByte()); // x r'
- Vector256 d = Avx2.And(c, CollectColorRedTransformsAndMask256); // 0 r'
+ Vector256 d = Avx2.And(c, collectColorRedTransformsAndMask256); // 0 r'
ref ushort outputRef = ref MemoryMarshal.GetReference(values);
Unsafe.As>(ref outputRef) = d.AsUInt16();
@@ -204,7 +186,9 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
}
else if (Sse41.IsSupported)
{
- var multsg = Vector128.Create(LosslessUtils.Cst5b(greenToRed));
+ Vector128 collectColorRedTransformsGreenMask = Vector128.Create(0x00ff00).AsByte();
+ Vector128 collectColorRedTransformsAndMask = Vector128.Create((short)0xff).AsByte();
+ Vector128 multsg = Vector128.Create(LosslessUtils.Cst5b(greenToRed));
const int span = 8;
Span values = stackalloc ushort[span];
for (int y = 0; y < tileHeight; y++)
@@ -217,15 +201,15 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
nint input1Idx = x + (span / 2);
Vector128 input0 = Unsafe.As>(ref Unsafe.Add(ref inputRef, input0Idx)).AsByte();
Vector128 input1 = Unsafe.As>(ref Unsafe.Add(ref inputRef, input1Idx)).AsByte();
- Vector128 g0 = Sse2.And(input0, CollectColorRedTransformsGreenMask); // 0 0 | g 0
- Vector128 g1 = Sse2.And(input1, CollectColorRedTransformsGreenMask);
+ Vector128 g0 = Sse2.And(input0, collectColorRedTransformsGreenMask); // 0 0 | g 0
+ Vector128 g1 = Sse2.And(input1, collectColorRedTransformsGreenMask);
Vector128 g = Sse41.PackUnsignedSaturate(g0.AsInt32(), g1.AsInt32()); // g 0
Vector128 a0 = Sse2.ShiftRightLogical(input0.AsInt32(), 16); // 0 0 | x r
Vector128 a1 = Sse2.ShiftRightLogical(input1.AsInt32(), 16);
Vector128 a = Sse41.PackUnsignedSaturate(a0, a1); // x r
Vector128 b = Sse2.MultiplyHigh(g.AsInt16(), multsg); // x dr
Vector128 c = Sse2.Subtract(a.AsByte(), b.AsByte()); // x r'
- Vector128 d = Sse2.And(c, CollectColorRedTransformsAndMask); // 0 r'
+ Vector128 d = Sse2.And(c, collectColorRedTransformsAndMask); // 0 r'
ref ushort outputRef = ref MemoryMarshal.GetReference(values);
Unsafe.As>(ref outputRef) = d.AsUInt16();
diff --git a/src/ImageSharp/Formats/Webp/Lossless/LosslessUtils.cs b/src/ImageSharp/Formats/Webp/Lossless/LosslessUtils.cs
index e7782b0ef4..1405b390b6 100644
--- a/src/ImageSharp/Formats/Webp/Lossless/LosslessUtils.cs
+++ b/src/ImageSharp/Formats/Webp/Lossless/LosslessUtils.cs
@@ -27,36 +27,6 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
private const double Log2Reciprocal = 1.44269504088896338700465094007086;
-#if SUPPORTS_RUNTIME_INTRINSICS
- private static readonly Vector256 AddGreenToBlueAndRedMaskAvx2 = Vector256.Create(1, 255, 1, 255, 5, 255, 5, 255, 9, 255, 9, 255, 13, 255, 13, 255, 17, 255, 17, 255, 21, 255, 21, 255, 25, 255, 25, 255, 29, 255, 29, 255);
-
- private static readonly Vector128 AddGreenToBlueAndRedMaskSsse3 = Vector128.Create(1, 255, 1, 255, 5, 255, 5, 255, 9, 255, 9, 255, 13, 255, 13, 255);
-
- private static readonly byte AddGreenToBlueAndRedShuffleMask = SimdUtils.Shuffle.MmShuffle(2, 2, 0, 0);
-
- private static readonly Vector256 SubtractGreenFromBlueAndRedMaskAvx2 = Vector256.Create(1, 255, 1, 255, 5, 255, 5, 255, 9, 255, 9, 255, 13, 255, 13, 255, 17, 255, 17, 255, 21, 255, 21, 255, 25, 255, 25, 255, 29, 255, 29, 255);
-
- private static readonly Vector128 SubtractGreenFromBlueAndRedMaskSsse3 = Vector128.Create(1, 255, 1, 255, 5, 255, 5, 255, 9, 255, 9, 255, 13, 255, 13, 255);
-
- private static readonly byte SubtractGreenFromBlueAndRedShuffleMask = SimdUtils.Shuffle.MmShuffle(2, 2, 0, 0);
-
- private static readonly Vector128 TransformColorAlphaGreenMask = Vector128.Create(0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255);
-
- private static readonly Vector256 TransformColorAlphaGreenMask256 = Vector256.Create(0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255);
-
- private static readonly Vector128 TransformColorRedBlueMask = Vector128.Create(255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0);
-
- private static readonly Vector256 TransformColorRedBlueMask256 = Vector256.Create(255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0);
-
- private static readonly byte TransformColorShuffleMask = SimdUtils.Shuffle.MmShuffle(2, 2, 0, 0);
-
- private static readonly Vector128 TransformColorInverseAlphaGreenMask = Vector128.Create(0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255);
-
- private static readonly Vector256 TransformColorInverseAlphaGreenMask256 = Vector256.Create(0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255);
-
- private static readonly byte TransformColorInverseShuffleMask = SimdUtils.Shuffle.MmShuffle(2, 2, 0, 0);
-#endif
-
///
/// Returns the exact index where array1 and array2 are different. For an index
/// inferior or equal to bestLenMatch, the return value just has to be strictly
@@ -129,13 +99,14 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
#if SUPPORTS_RUNTIME_INTRINSICS
if (Avx2.IsSupported)
{
+ Vector256 addGreenToBlueAndRedMaskAvx2 = Vector256.Create(1, 255, 1, 255, 5, 255, 5, 255, 9, 255, 9, 255, 13, 255, 13, 255, 17, 255, 17, 255, 21, 255, 21, 255, 25, 255, 25, 255, 29, 255, 29, 255);
int numPixels = pixelData.Length;
nint i;
for (i = 0; i <= numPixels - 8; i += 8)
{
ref uint pos = ref Unsafe.Add(ref MemoryMarshal.GetReference(pixelData), i);
Vector256 input = Unsafe.As>(ref pos).AsByte();
- Vector256 in0g0g = Avx2.Shuffle(input, AddGreenToBlueAndRedMaskAvx2);
+ Vector256 in0g0g = Avx2.Shuffle(input, addGreenToBlueAndRedMaskAvx2);
Vector256 output = Avx2.Add(input, in0g0g);
Unsafe.As>(ref pos) = output.AsUInt32();
}
@@ -147,13 +118,14 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
}
else if (Ssse3.IsSupported)
{
+ Vector128 addGreenToBlueAndRedMaskSsse3 = Vector128.Create(1, 255, 1, 255, 5, 255, 5, 255, 9, 255, 9, 255, 13, 255, 13, 255);
int numPixels = pixelData.Length;
nint i;
for (i = 0; i <= numPixels - 4; i += 4)
{
ref uint pos = ref Unsafe.Add(ref MemoryMarshal.GetReference(pixelData), i);
Vector128 input = Unsafe.As>(ref pos).AsByte();
- Vector128 in0g0g = Ssse3.Shuffle(input, AddGreenToBlueAndRedMaskSsse3);
+ Vector128 in0g0g = Ssse3.Shuffle(input, addGreenToBlueAndRedMaskSsse3);
Vector128 output = Sse2.Add(input, in0g0g);
Unsafe.As>(ref pos) = output.AsUInt32();
}
@@ -169,11 +141,13 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
nint i;
for (i = 0; i <= numPixels - 4; i += 4)
{
+ const byte mmShuffle_2200 = 0b_10_10_00_00;
+
ref uint pos = ref Unsafe.Add(ref MemoryMarshal.GetReference(pixelData), i);
Vector128 input = Unsafe.As>(ref pos).AsByte();
Vector128 a = Sse2.ShiftRightLogical(input.AsUInt16(), 8); // 0 a 0 g
- Vector128 b = Sse2.ShuffleLow(a, AddGreenToBlueAndRedShuffleMask);
- Vector128 c = Sse2.ShuffleHigh(b, AddGreenToBlueAndRedShuffleMask); // 0g0g
+ Vector128 b = Sse2.ShuffleLow(a, mmShuffle_2200);
+ Vector128 c = Sse2.ShuffleHigh(b, mmShuffle_2200); // 0g0g
Vector128