diff --git a/.github/dependabot.yml b/.github/dependabot.yml
new file mode 100644
index 0000000000..5ace4600a1
--- /dev/null
+++ b/.github/dependabot.yml
@@ -0,0 +1,6 @@
+version: 2
+updates:
+ - package-ecosystem: "github-actions"
+ directory: "/"
+ schedule:
+ interval: "weekly"
diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml
index 16f8ebb065..4ffbbb5440 100644
--- a/.github/workflows/build-and-test.yml
+++ b/.github/workflows/build-and-test.yml
@@ -58,7 +58,7 @@ jobs:
git config --global core.longpaths true
- name: Git Checkout
- uses: actions/checkout@v2
+ uses: actions/checkout@v3
with:
fetch-depth: 0
submodules: recursive
@@ -68,7 +68,7 @@ jobs:
run: git lfs ls-files -l | cut -d' ' -f1 | sort > .lfs-assets-id
- name: Git Setup LFS Cache
- uses: actions/cache@v2
+ uses: actions/cache@v3
id: lfs-cache
with:
path: .git/lfs
@@ -81,7 +81,7 @@ jobs:
uses: NuGet/setup-nuget@v1
- name: NuGet Setup Cache
- uses: actions/cache@v2
+ uses: actions/cache@v3
id: nuget-cache
with:
path: ~/.nuget
@@ -89,7 +89,7 @@ jobs:
restore-keys: ${{ runner.os }}-nuget-
- name: DotNet Setup
- uses: actions/setup-dotnet@v1
+ uses: actions/setup-dotnet@v2
with:
include-prerelease: true
dotnet-version: |
@@ -127,7 +127,7 @@ jobs:
XUNIT_PATH: .\tests\ImageSharp.Tests # Required for xunit
- name: Export Failed Output
- uses: actions/upload-artifact@v2
+ uses: actions/upload-artifact@v3
if: failure()
with:
name: actual_output_${{ runner.os }}_${{ matrix.options.framework }}${{ matrix.options.runtime }}.zip
@@ -148,7 +148,7 @@ jobs:
git config --global core.longpaths true
- name: Git Checkout
- uses: actions/checkout@v2
+ uses: actions/checkout@v3
with:
fetch-depth: 0
submodules: recursive
@@ -157,7 +157,7 @@ jobs:
uses: NuGet/setup-nuget@v1
- name: NuGet Setup Cache
- uses: actions/cache@v2
+ uses: actions/cache@v3
id: nuget-cache
with:
path: ~/.nuget
diff --git a/.github/workflows/code-coverage.yml b/.github/workflows/code-coverage.yml
index 3f8a820313..85ff42b74b 100644
--- a/.github/workflows/code-coverage.yml
+++ b/.github/workflows/code-coverage.yml
@@ -24,7 +24,7 @@ jobs:
git config --global core.longpaths true
- name: Git Checkout
- uses: actions/checkout@v2
+ uses: actions/checkout@v3
with:
fetch-depth: 0
submodules: recursive
@@ -34,7 +34,7 @@ jobs:
run: git lfs ls-files -l | cut -d' ' -f1 | sort > .lfs-assets-id
- name: Git Setup LFS Cache
- uses: actions/cache@v2
+ uses: actions/cache@v3
id: lfs-cache
with:
path: .git/lfs
@@ -47,7 +47,7 @@ jobs:
uses: NuGet/setup-nuget@v1
- name: NuGet Setup Cache
- uses: actions/cache@v2
+ uses: actions/cache@v3
id: nuget-cache
with:
path: ~/.nuget
@@ -55,7 +55,7 @@ jobs:
restore-keys: ${{ runner.os }}-nuget-
- name: DotNet Setup
- uses: actions/setup-dotnet@v1
+ uses: actions/setup-dotnet@v2
with:
dotnet-version: |
6.0.x
@@ -74,14 +74,14 @@ jobs:
XUNIT_PATH: .\tests\ImageSharp.Tests # Required for xunit
- name: Export Failed Output
- uses: actions/upload-artifact@v2
+ uses: actions/upload-artifact@v3
if: failure()
with:
name: actual_output_${{ runner.os }}_${{ matrix.options.framework }}${{ matrix.options.runtime }}.zip
path: tests/Images/ActualOutput/
- name: Codecov Update
- uses: codecov/codecov-action@v1
+ uses: codecov/codecov-action@v3
if: matrix.options.codecov == true && startsWith(github.repository, 'SixLabors')
with:
flags: unittests
diff --git a/src/ImageSharp/Common/Helpers/Numerics.cs b/src/ImageSharp/Common/Helpers/Numerics.cs
index 7de838bc94..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.
@@ -968,7 +974,7 @@ namespace SixLabors.ImageSharp
/// Tells whether input value is outside of the given range.
///
/// Value.
- /// Mininum value, inclusive.
+ /// Minimum value, inclusive.
/// Maximum value, inclusive.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool IsOutOfRange(int value, int min, int max)
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/Decoder/JpegBitReader.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegBitReader.cs
index 84013319e1..70968d5194 100644
--- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegBitReader.cs
+++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegBitReader.cs
@@ -155,12 +155,14 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
c = this.ReadStream();
}
+ // Found a marker
// We accept multiple FF bytes followed by a 0 as meaning a single FF data byte.
- // This data pattern is not valid according to the standard.
+ // even though it's considered 'invalid' according to the specs.
if (c != 0)
{
- this.Marker = (byte)c;
+ // It's a trick so we won't read past actual marker
this.badData = true;
+ this.Marker = (byte)c;
this.MarkerPosition = this.stream.Position - 2;
}
}
@@ -199,7 +201,6 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
if (b != 0)
{
this.Marker = (byte)b;
- this.badData = true;
this.MarkerPosition = this.stream.Position - 2;
return true;
}
diff --git a/src/ImageSharp/Formats/Jpeg/Components/FloatingPointDCT.Intrinsic.cs b/src/ImageSharp/Formats/Jpeg/Components/FloatingPointDCT.Intrinsic.cs
index c4b803ca3a..17c504d7f5 100644
--- a/src/ImageSharp/Formats/Jpeg/Components/FloatingPointDCT.Intrinsic.cs
+++ b/src/ImageSharp/Formats/Jpeg/Components/FloatingPointDCT.Intrinsic.cs
@@ -9,18 +9,6 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components
{
internal static partial class FloatingPointDCT
{
-#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/Jpeg/JpegDecoderCore.cs b/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs
index 038c23a7e2..c331d35588 100644
--- a/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs
+++ b/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs
@@ -90,6 +90,11 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
///
private JFifMarker jFif;
+ ///
+ /// Whether the image has a JFIF marker. This is needed to determine, if the colorspace is YCbCr.
+ ///
+ private bool hasJFif;
+
///
/// Contains information about the Adobe marker.
///
@@ -159,38 +164,38 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
///
/// Finds the next file marker within the byte stream.
///
- /// The buffer to read file markers to.
/// The input stream.
- /// The
- public static JpegFileMarker FindNextFileMarker(byte[] marker, BufferedReadStream stream)
+ /// The .
+ public static JpegFileMarker FindNextFileMarker(BufferedReadStream stream)
{
- int value = stream.Read(marker, 0, 2);
-
- if (value == 0)
+ while (true)
{
- return new JpegFileMarker(JpegConstants.Markers.EOI, stream.Length - 2);
- }
+ int b = stream.ReadByte();
+ if (b == -1)
+ {
+ return new JpegFileMarker(JpegConstants.Markers.EOI, stream.Length - 2);
+ }
- if (marker[0] == JpegConstants.Markers.XFF)
- {
- // According to Section B.1.1.2:
- // "Any marker may optionally be preceded by any number of fill bytes, which are bytes assigned code 0xFF."
- int m = marker[1];
- while (m == JpegConstants.Markers.XFF)
+ // Found a marker.
+ if (b == JpegConstants.Markers.XFF)
{
- int suffix = stream.ReadByte();
- if (suffix == -1)
+ while (b == JpegConstants.Markers.XFF)
{
- return new JpegFileMarker(JpegConstants.Markers.EOI, stream.Length - 2);
+ // Loop here to discard any padding FF bytes on terminating marker.
+ b = stream.ReadByte();
+ if (b == -1)
+ {
+ return new JpegFileMarker(JpegConstants.Markers.EOI, stream.Length - 2);
+ }
}
- m = suffix;
+ // Found a valid marker. Exit loop
+ if (b is not 0 and (< JpegConstants.Markers.RST0 or > JpegConstants.Markers.RST7))
+ {
+ return new JpegFileMarker((byte)(uint)b, stream.Position - 2);
+ }
}
-
- return new JpegFileMarker((byte)m, stream.Position - 2);
}
-
- return new JpegFileMarker(marker[1], stream.Position - 2, true);
}
///
@@ -340,15 +345,12 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
JpegThrowHelper.ThrowInvalidImageContentException("Missing SOI marker.");
}
- stream.Read(this.markerBuffer, 0, 2);
- byte marker = this.markerBuffer[1];
- fileMarker = new JpegFileMarker(marker, (int)stream.Position - 2);
+ fileMarker = FindNextFileMarker(stream);
this.QuantizationTables ??= new Block8x8F[4];
// Break only when we discover a valid EOI marker.
// https://github.com/SixLabors/ImageSharp/issues/695
- while (fileMarker.Marker != JpegConstants.Markers.EOI
- || (fileMarker.Marker == JpegConstants.Markers.EOI && fileMarker.Invalid))
+ while (fileMarker.Marker != JpegConstants.Markers.EOI)
{
cancellationToken.ThrowIfCancellationRequested();
@@ -500,7 +502,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
}
// Read on.
- fileMarker = FindNextFileMarker(this.markerBuffer, stream);
+ fileMarker = FindNextFileMarker(stream);
}
}
@@ -528,17 +530,56 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
if (componentCount == 3)
{
- if (!this.adobe.Equals(default) && this.adobe.ColorTransform == JpegConstants.Adobe.ColorTransformUnknown)
+ // We prioritize adobe marker over jfif marker, if somebody really encoded this image with redundant adobe marker,
+ // then it's most likely an adobe jfif image.
+ if (!this.adobe.Equals(default))
{
- return JpegColorSpace.RGB;
+ if (this.adobe.ColorTransform == JpegConstants.Adobe.ColorTransformYCbCr)
+ {
+ return JpegColorSpace.YCbCr;
+ }
+
+ if (this.adobe.ColorTransform == JpegConstants.Adobe.ColorTransformUnknown)
+ {
+ return JpegColorSpace.RGB;
+ }
+
+ // Fallback to the id color deduction: If these values are 1-3 for a 3-channel image, then the image is assumed to be YCbCr.
+ if (this.Components[2].Id == 3 && this.Components[1].Id == 2 && this.Components[0].Id == 1)
+ {
+ return JpegColorSpace.YCbCr;
+ }
+
+ JpegThrowHelper.ThrowNotSupportedColorSpace();
+ }
+
+ if (this.hasJFif)
+ {
+ // JFIF implies YCbCr.
+ return JpegColorSpace.YCbCr;
}
+ // Fallback to the id color deduction.
// If the component Id's are R, G, B in ASCII the colorspace is RGB and not YCbCr.
+ // See: https://docs.oracle.com/javase/7/docs/api/javax/imageio/metadata/doc-files/jpeg_metadata.html#color
if (this.Components[2].Id == 66 && this.Components[1].Id == 71 && this.Components[0].Id == 82)
{
return JpegColorSpace.RGB;
}
+ // If these values are 1-3 for a 3-channel image, then the image is assumed to be YCbCr.
+ if (this.Components[2].Id == 3 && this.Components[1].Id == 2 && this.Components[0].Id == 1)
+ {
+ return JpegColorSpace.YCbCr;
+ }
+
+ // 3-channel non-subsampled images are assumed to be RGB.
+ if (this.Components[2].VerticalSamplingFactor == 1 && this.Components[1].VerticalSamplingFactor == 1 && this.Components[0].VerticalSamplingFactor == 1 &&
+ this.Components[2].HorizontalSamplingFactor == 1 && this.Components[1].HorizontalSamplingFactor == 1 && this.Components[0].HorizontalSamplingFactor == 1)
+ {
+ return JpegColorSpace.RGB;
+ }
+
// Some images are poorly encoded and contain incorrect colorspace transform metadata.
// We ignore that and always fall back to the default colorspace.
return JpegColorSpace.YCbCr;
@@ -546,9 +587,24 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
if (componentCount == 4)
{
- return this.adobe.ColorTransform == JpegConstants.Adobe.ColorTransformYcck
- ? JpegColorSpace.Ycck
- : JpegColorSpace.Cmyk;
+ // jfif images doesn't not support 4 component images, so we only check adobe.
+ if (!this.adobe.Equals(default))
+ {
+ if (this.adobe.ColorTransform == JpegConstants.Adobe.ColorTransformYcck)
+ {
+ return JpegColorSpace.Ycck;
+ }
+
+ if (this.adobe.ColorTransform == JpegConstants.Adobe.ColorTransformUnknown)
+ {
+ return JpegColorSpace.Cmyk;
+ }
+
+ JpegThrowHelper.ThrowNotSupportedColorSpace();
+ }
+
+ // Fallback to cmyk as neither of cmyk nor ycck have 'special' component ids.
+ return JpegColorSpace.Cmyk;
}
JpegThrowHelper.ThrowNotSupportedComponentCount(componentCount);
@@ -715,6 +771,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
/// The remaining bytes in the segment block.
private void ProcessApplicationHeaderMarker(BufferedReadStream stream, int remaining)
{
+ this.hasJFif = true;
+
// We can only decode JFif identifiers.
// Some images contain multiple JFIF markers (Issue 1932) so we check to see
// if it's already been read.
diff --git a/src/ImageSharp/Formats/Jpeg/JpegThrowHelper.cs b/src/ImageSharp/Formats/Jpeg/JpegThrowHelper.cs
index 1073ffff78..0dc412a6f9 100644
--- a/src/ImageSharp/Formats/Jpeg/JpegThrowHelper.cs
+++ b/src/ImageSharp/Formats/Jpeg/JpegThrowHelper.cs
@@ -51,5 +51,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
[MethodImpl(InliningOptions.ColdPath)]
public static void ThrowNotSupportedComponentCount(int componentCount) => throw new NotSupportedException($"Images with {componentCount} components are not supported.");
+
+ [MethodImpl(InliningOptions.ColdPath)]
+ public static void ThrowNotSupportedColorSpace() => throw new NotSupportedException("Image color space could not be deduced.");
}
}
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/JpegTiffCompression.cs b/src/ImageSharp/Formats/Tiff/Compression/Decompressors/JpegTiffCompression.cs
index 88dbcb8828..3b2c765b38 100644
--- a/src/ImageSharp/Formats/Tiff/Compression/Decompressors/JpegTiffCompression.cs
+++ b/src/ImageSharp/Formats/Tiff/Compression/Decompressors/JpegTiffCompression.cs
@@ -65,13 +65,11 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Compression.Decompressors
jpegDecoder.ParseStream(stream, spectralConverterGray, CancellationToken.None);
// TODO: Should we pass through the CancellationToken from the tiff decoder?
- using var decompressedBuffer = spectralConverterGray.GetPixelBuffer(CancellationToken.None);
+ using Buffer2D decompressedBuffer = spectralConverterGray.GetPixelBuffer(CancellationToken.None);
CopyImageBytesToBuffer(buffer, decompressedBuffer);
break;
}
- // If the PhotometricInterpretation is YCbCr we explicitly assume the JPEG data is in RGB color space.
- // There seems no other way to determine that the JPEG data is RGB colorspace (no APP14 marker, componentId's are not RGB).
case TiffPhotometricInterpretation.YCbCr:
case TiffPhotometricInterpretation.Rgb:
{
@@ -82,7 +80,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Compression.Decompressors
jpegDecoder.ParseStream(stream, spectralConverter, CancellationToken.None);
// TODO: Should we pass through the CancellationToken from the tiff decoder?
- using var decompressedBuffer = spectralConverter.GetPixelBuffer(CancellationToken.None);
+ using Buffer2D decompressedBuffer = spectralConverter.GetPixelBuffer(CancellationToken.None);
CopyImageBytesToBuffer(buffer, decompressedBuffer);
break;
}
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
///