diff --git a/.editorconfig b/.editorconfig
index 03036f8a53..33fd0577a8 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -75,7 +75,7 @@ indent_style = tab
[*.{cs,csx,cake,vb,vbx}]
# Default Severity for all .NET Code Style rules below
-dotnet_analyzer_diagnostic.severity = warning
+dotnet_analyzer_diagnostic.category-style.severity = warning
##########################################
# Language Rules
diff --git a/Directory.Build.props b/Directory.Build.props
index 3df93fcd40..d70fbc45ae 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -26,5 +26,5 @@
true
-
+
diff --git a/ImageSharp.sln b/ImageSharp.sln
index 5555764353..ef6a945f65 100644
--- a/ImageSharp.sln
+++ b/ImageSharp.sln
@@ -546,12 +546,12 @@ Global
{2BF743D8-2A06-412D-96D7-F448F00C5EA5}.Debug|x64.Build.0 = Debug|Any CPU
{2BF743D8-2A06-412D-96D7-F448F00C5EA5}.Debug|x86.ActiveCfg = Debug|Any CPU
{2BF743D8-2A06-412D-96D7-F448F00C5EA5}.Debug|x86.Build.0 = Debug|Any CPU
- {2BF743D8-2A06-412D-96D7-F448F00C5EA5}.Debug-InnerLoop|Any CPU.ActiveCfg = Debug-InnerLoop|Any CPU
- {2BF743D8-2A06-412D-96D7-F448F00C5EA5}.Debug-InnerLoop|Any CPU.Build.0 = Debug-InnerLoop|Any CPU
- {2BF743D8-2A06-412D-96D7-F448F00C5EA5}.Debug-InnerLoop|x64.ActiveCfg = Debug-InnerLoop|Any CPU
- {2BF743D8-2A06-412D-96D7-F448F00C5EA5}.Debug-InnerLoop|x64.Build.0 = Debug-InnerLoop|Any CPU
- {2BF743D8-2A06-412D-96D7-F448F00C5EA5}.Debug-InnerLoop|x86.ActiveCfg = Debug-InnerLoop|Any CPU
- {2BF743D8-2A06-412D-96D7-F448F00C5EA5}.Debug-InnerLoop|x86.Build.0 = Debug-InnerLoop|Any CPU
+ {2BF743D8-2A06-412D-96D7-F448F00C5EA5}.Debug-InnerLoop|Any CPU.ActiveCfg = Debug|Any CPU
+ {2BF743D8-2A06-412D-96D7-F448F00C5EA5}.Debug-InnerLoop|Any CPU.Build.0 = Debug|Any CPU
+ {2BF743D8-2A06-412D-96D7-F448F00C5EA5}.Debug-InnerLoop|x64.ActiveCfg = Debug|Any CPU
+ {2BF743D8-2A06-412D-96D7-F448F00C5EA5}.Debug-InnerLoop|x64.Build.0 = Debug|Any CPU
+ {2BF743D8-2A06-412D-96D7-F448F00C5EA5}.Debug-InnerLoop|x86.ActiveCfg = Debug|Any CPU
+ {2BF743D8-2A06-412D-96D7-F448F00C5EA5}.Debug-InnerLoop|x86.Build.0 = Debug|Any CPU
{2BF743D8-2A06-412D-96D7-F448F00C5EA5}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2BF743D8-2A06-412D-96D7-F448F00C5EA5}.Release|Any CPU.Build.0 = Release|Any CPU
{2BF743D8-2A06-412D-96D7-F448F00C5EA5}.Release|x64.ActiveCfg = Release|Any CPU
@@ -570,12 +570,12 @@ Global
{FC527290-2F22-432C-B77B-6E815726B02C}.Debug|x64.Build.0 = Debug|Any CPU
{FC527290-2F22-432C-B77B-6E815726B02C}.Debug|x86.ActiveCfg = Debug|Any CPU
{FC527290-2F22-432C-B77B-6E815726B02C}.Debug|x86.Build.0 = Debug|Any CPU
- {FC527290-2F22-432C-B77B-6E815726B02C}.Debug-InnerLoop|Any CPU.ActiveCfg = Debug-InnerLoop|Any CPU
- {FC527290-2F22-432C-B77B-6E815726B02C}.Debug-InnerLoop|Any CPU.Build.0 = Debug-InnerLoop|Any CPU
- {FC527290-2F22-432C-B77B-6E815726B02C}.Debug-InnerLoop|x64.ActiveCfg = Debug-InnerLoop|Any CPU
- {FC527290-2F22-432C-B77B-6E815726B02C}.Debug-InnerLoop|x64.Build.0 = Debug-InnerLoop|Any CPU
- {FC527290-2F22-432C-B77B-6E815726B02C}.Debug-InnerLoop|x86.ActiveCfg = Debug-InnerLoop|Any CPU
- {FC527290-2F22-432C-B77B-6E815726B02C}.Debug-InnerLoop|x86.Build.0 = Debug-InnerLoop|Any CPU
+ {FC527290-2F22-432C-B77B-6E815726B02C}.Debug-InnerLoop|Any CPU.ActiveCfg = Debug|Any CPU
+ {FC527290-2F22-432C-B77B-6E815726B02C}.Debug-InnerLoop|Any CPU.Build.0 = Debug|Any CPU
+ {FC527290-2F22-432C-B77B-6E815726B02C}.Debug-InnerLoop|x64.ActiveCfg = Debug|Any CPU
+ {FC527290-2F22-432C-B77B-6E815726B02C}.Debug-InnerLoop|x64.Build.0 = Debug|Any CPU
+ {FC527290-2F22-432C-B77B-6E815726B02C}.Debug-InnerLoop|x86.ActiveCfg = Debug|Any CPU
+ {FC527290-2F22-432C-B77B-6E815726B02C}.Debug-InnerLoop|x86.Build.0 = Debug|Any CPU
{FC527290-2F22-432C-B77B-6E815726B02C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{FC527290-2F22-432C-B77B-6E815726B02C}.Release|Any CPU.Build.0 = Release|Any CPU
{FC527290-2F22-432C-B77B-6E815726B02C}.Release|x64.ActiveCfg = Release|Any CPU
diff --git a/shared-infrastructure b/shared-infrastructure
index 1f7ee70281..9b94ebc4be 160000
--- a/shared-infrastructure
+++ b/shared-infrastructure
@@ -1 +1 @@
-Subproject commit 1f7ee702812f3a1713ab7f749c0faae0ef139ed7
+Subproject commit 9b94ebc4be9b7a8d7620c257e6ee485455973332
diff --git a/src/ImageSharp/Common/Helpers/Numerics.cs b/src/ImageSharp/Common/Helpers/Numerics.cs
index ef457f7ceb..db65b84cca 100644
--- a/src/ImageSharp/Common/Helpers/Numerics.cs
+++ b/src/ImageSharp/Common/Helpers/Numerics.cs
@@ -24,24 +24,12 @@ namespace SixLabors.ImageSharp
#endif
#if !SUPPORTS_BITOPERATIONS
- ///
- /// Gets the counts the number of bits needed to hold an integer.
- ///
- private static ReadOnlySpan BitCountLut => new byte[]
+ private static ReadOnlySpan Log2DeBruijn => new byte[32]
{
- 0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5,
- 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
- 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
- 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
- 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
- 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
- 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
- 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
- 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
- 8, 8, 8,
+ 00, 09, 01, 10, 13, 21, 02, 29,
+ 11, 14, 16, 18, 22, 25, 03, 30,
+ 08, 12, 20, 28, 15, 17, 24, 07,
+ 19, 27, 23, 06, 26, 05, 04, 31
};
#endif
@@ -849,24 +837,47 @@ namespace SixLabors.ImageSharp
#endif
///
- /// Calculates how many minimum bits needed to store given value.
+ /// Calculates floored log of the specified value, base 2.
+ /// Note that by convention, input value 0 returns 0 since Log(0) is undefined.
///
- /// Unsigned integer to store
- /// Minimum number of bits needed to store given value
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static int MinimumBitsToStore16(uint number)
+ /// The value.
+ public static int Log2(uint value)
{
-#if !SUPPORTS_BITOPERATIONS
- if (number < 0x100)
- {
- return BitCountLut[(int)number];
- }
-
- return 8 + BitCountLut[(int)number >> 8];
+#if SUPPORTS_BITOPERATIONS
+ return BitOperations.Log2(value);
#else
- const int bitInUnsignedInteger = sizeof(uint) * 8;
- return bitInUnsignedInteger - BitOperations.LeadingZeroCount(number);
+ return Log2SoftwareFallback(value);
#endif
}
+
+#if !SUPPORTS_BITOPERATIONS
+ ///
+ /// Calculates floored log of the specified value, base 2.
+ /// Note that by convention, input value 0 returns 0 since Log(0) is undefined.
+ /// Bit hacking with deBruijn sequence, extremely fast yet does not use any intrinsics so will work on every platform/runtime.
+ ///
+ ///
+ /// Description of this bit hacking can be found here:
+ /// https://cstheory.stackexchange.com/questions/19524/using-the-de-bruijn-sequence-to-find-the-lceil-log-2-v-rceil-of-an-integer
+ ///
+ /// The value.
+ private static int Log2SoftwareFallback(uint value)
+ {
+ // No AggressiveInlining due to large method size
+ // Has conventional contract 0->0 (Log(0) is undefined) by default, no need for if checking
+
+ // Fill trailing zeros with ones, eg 00010010 becomes 00011111
+ value |= value >> 01;
+ value |= value >> 02;
+ value |= value >> 04;
+ value |= value >> 08;
+ value |= value >> 16;
+
+ // uint.MaxValue >> 27 is always in range [0 - 31] so we use Unsafe.AddByteOffset to avoid bounds check
+ return Unsafe.AddByteOffset(
+ ref MemoryMarshal.GetReference(Log2DeBruijn),
+ (IntPtr)(int)((value * 0x07C4ACDDu) >> 27)); // uint|long -> IntPtr cast on 32-bit platforms does expensive overflow checks not needed here
+ }
+#endif
}
}
diff --git a/src/ImageSharp/Formats/Jpeg/Components/Encoder/HuffmanScanEncoder.cs b/src/ImageSharp/Formats/Jpeg/Components/Encoder/HuffmanScanEncoder.cs
index ca352397b8..860a9c3236 100644
--- a/src/ImageSharp/Formats/Jpeg/Components/Encoder/HuffmanScanEncoder.cs
+++ b/src/ImageSharp/Formats/Jpeg/Components/Encoder/HuffmanScanEncoder.cs
@@ -360,7 +360,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Encoder
b = value - 1;
}
- int bt = Numerics.MinimumBitsToStore16((uint)a);
+ int bt = GetHuffmanEncodingLength((uint)a);
this.EmitHuff(index, (runLength << 4) | bt);
if (bt > 0)
@@ -388,5 +388,40 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Encoder
this.target.Write(this.emitBuffer, 0, this.emitLen);
}
}
+
+ ///
+ /// Calculates how many minimum bits needed to store given value for Huffman jpeg encoding.
+ ///
+ ///
+ /// This method returns 0 for input value 0. This is done specificaly for huffman encoding
+ ///
+ /// The value.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private static int GetHuffmanEncodingLength(uint value)
+ {
+ DebugGuard.IsTrue(value <= (1 << 16), "Huffman encoder is supposed to encode a value of 16bit size max");
+#if SUPPORTS_BITOPERATIONS
+ // This should have been implemented as (BitOperations.Log2(value) + 1) as in non-intrinsic implementation
+ // But internal log2 is implementated like this: (31 - (int)Lzcnt.LeadingZeroCount(value))
+
+ // BitOperations.Log2 implementation also checks if input value is zero for the convention 0->0
+ // Lzcnt would return 32 for input value of 0 - no need to check that with branching
+ // Fallback code if Lzcnt is not supported still use if-check
+ // But most modern CPUs support this instruction so this should not be a problem
+ return 32 - System.Numerics.BitOperations.LeadingZeroCount(value);
+#else
+ // Ideally:
+ // if 0 - return 0 in this case
+ // else - return log2(value) + 1
+ //
+ // Hack based on input value constaint:
+ // We know that input values are guaranteed to be maximum 16 bit large for huffman encoding
+ // We can safely shift input value for one bit -> log2(value << 1)
+ // Because of the 16 bit value constraint it won't overflow
+ // With that input value change we no longer need to add 1 before returning
+ // And this eliminates need to check if input value is zero - it is a standard convention which Log2SoftwareFallback adheres to
+ return Numerics.Log2(value << 1);
+#endif
+ }
}
}
diff --git a/src/ImageSharp/Formats/Jpeg/Components/Encoder/RgbToYCbCrConverterVectorized.cs b/src/ImageSharp/Formats/Jpeg/Components/Encoder/RgbToYCbCrConverterVectorized.cs
index 926e7d5a4a..9566ee862a 100644
--- a/src/ImageSharp/Formats/Jpeg/Components/Encoder/RgbToYCbCrConverterVectorized.cs
+++ b/src/ImageSharp/Formats/Jpeg/Components/Encoder/RgbToYCbCrConverterVectorized.cs
@@ -175,7 +175,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Encoder
// left 8x8 column conversions
for (int j = 0; j < 4; j += 2)
{
- rgb = Avx2.PermuteVar8x32(Unsafe.AddByteOffset(ref rgbByteSpan, (IntPtr)(bytesPerRgbStride * (i * 4 + j))).AsUInt32(), extractToLanesMask).AsByte();
+ rgb = Avx2.PermuteVar8x32(Unsafe.AddByteOffset(ref rgbByteSpan, (IntPtr)(bytesPerRgbStride * ((i * 4) + j))).AsUInt32(), extractToLanesMask).AsByte();
rgb = Avx2.Shuffle(rgb, extractRgbMask);
@@ -200,7 +200,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Encoder
// right 8x8 column conversions
for (int j = 1; j < 4; j += 2)
{
- rgb = Avx2.PermuteVar8x32(Unsafe.AddByteOffset(ref rgbByteSpan, (IntPtr)(bytesPerRgbStride * (i * 4 + j))).AsUInt32(), extractToLanesMask).AsByte();
+ rgb = Avx2.PermuteVar8x32(Unsafe.AddByteOffset(ref rgbByteSpan, (IntPtr)(bytesPerRgbStride * ((i * 4) + j))).AsUInt32(), extractToLanesMask).AsByte();
rgb = Avx2.Shuffle(rgb, extractRgbMask);
diff --git a/src/ImageSharp/Formats/Jpeg/Components/FastFloatingPointDCT.cs b/src/ImageSharp/Formats/Jpeg/Components/FastFloatingPointDCT.cs
index f31d07efca..0f569b5da1 100644
--- a/src/ImageSharp/Formats/Jpeg/Components/FastFloatingPointDCT.cs
+++ b/src/ImageSharp/Formats/Jpeg/Components/FastFloatingPointDCT.cs
@@ -63,7 +63,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components
private static readonly Vector256 C_V_n1_8477 = Vector256.Create(-1.847759065f);
private static readonly Vector256 C_V_0_7653 = Vector256.Create(0.765366865f);
- private static Vector256 C_V_InvSqrt2 = Vector256.Create(0.707107f);
+ private static readonly Vector256 C_V_InvSqrt2 = Vector256.Create(0.707107f);
#endif
#pragma warning restore SA1310 // FieldNamesMustNotContainUnderscore
private static readonly Vector4 InvSqrt2 = new Vector4(0.707107f);
diff --git a/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs b/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs
index 6020e6196c..135048aa4e 100644
--- a/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs
+++ b/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs
@@ -28,44 +28,6 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
///
private const int QuantizationTableCount = 2;
- ///
- /// Gets the unscaled quantization tables in zig-zag order. Each
- /// encoder copies and scales the tables according to its quality parameter.
- /// The values are derived from section K.1 after converting from natural to
- /// zig-zag order.
- ///
- // The C# compiler emits this as a compile-time constant embedded in the PE file.
- // This is effectively compiled down to: return new ReadOnlySpan(&data, length)
- // More details can be found: https://github.com/dotnet/roslyn/pull/24621
- private static ReadOnlySpan UnscaledQuant_Luminance => new byte[]
- {
- // Luminance.
- 16, 11, 12, 14, 12, 10, 16, 14, 13, 14, 18, 17, 16, 19, 24,
- 40, 26, 24, 22, 22, 24, 49, 35, 37, 29, 40, 58, 51, 61, 60,
- 57, 51, 56, 55, 64, 72, 92, 78, 64, 68, 87, 69, 55, 56, 80,
- 109, 81, 87, 95, 98, 103, 104, 103, 62, 77, 113, 121, 112,
- 100, 120, 92, 101, 103, 99,
- };
-
- ///
- /// Gets the unscaled quantization tables in zig-zag order. Each
- /// encoder copies and scales the tables according to its quality parameter.
- /// The values are derived from section K.1 after converting from natural to
- /// zig-zag order.
- ///
- // The C# compiler emits this as a compile-time constant embedded in the PE file.
- // This is effectively compiled down to: return new ReadOnlySpan(&data, length)
- // More details can be found: https://github.com/dotnet/roslyn/pull/24621
- private static ReadOnlySpan UnscaledQuant_Chrominance => new byte[]
- {
- // Chrominance.
- 17, 18, 18, 24, 21, 24, 47, 26, 26, 47, 99, 66, 56, 66,
- 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
- 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
- 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
- 99, 99, 99, 99, 99, 99, 99, 99,
- };
-
///
/// A scratch buffer to reduce allocations.
///
@@ -102,6 +64,44 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
this.colorType = options.ColorType;
}
+ ///
+ /// Gets the unscaled quantization tables in zig-zag order. Each
+ /// encoder copies and scales the tables according to its quality parameter.
+ /// The values are derived from section K.1 after converting from natural to
+ /// zig-zag order.
+ ///
+ // The C# compiler emits this as a compile-time constant embedded in the PE file.
+ // This is effectively compiled down to: return new ReadOnlySpan(&data, length)
+ // More details can be found: https://github.com/dotnet/roslyn/pull/24621
+ private static ReadOnlySpan UnscaledQuant_Luminance => new byte[]
+ {
+ // Luminance.
+ 16, 11, 12, 14, 12, 10, 16, 14, 13, 14, 18, 17, 16, 19, 24,
+ 40, 26, 24, 22, 22, 24, 49, 35, 37, 29, 40, 58, 51, 61, 60,
+ 57, 51, 56, 55, 64, 72, 92, 78, 64, 68, 87, 69, 55, 56, 80,
+ 109, 81, 87, 95, 98, 103, 104, 103, 62, 77, 113, 121, 112,
+ 100, 120, 92, 101, 103, 99,
+ };
+
+ ///
+ /// Gets the unscaled quantization tables in zig-zag order. Each
+ /// encoder copies and scales the tables according to its quality parameter.
+ /// The values are derived from section K.1 after converting from natural to
+ /// zig-zag order.
+ ///
+ // The C# compiler emits this as a compile-time constant embedded in the PE file.
+ // This is effectively compiled down to: return new ReadOnlySpan(&data, length)
+ // More details can be found: https://github.com/dotnet/roslyn/pull/24621
+ private static ReadOnlySpan UnscaledQuant_Chrominance => new byte[]
+ {
+ // Chrominance.
+ 17, 18, 18, 24, 21, 24, 47, 26, 26, 47, 99, 66, 56, 66,
+ 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99,
+ };
+
///
/// Encode writes the image to the jpeg baseline format with the given options.
///
@@ -180,7 +180,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
}
else
{
- switch (subsample)
+ switch (this.subsample)
{
case JpegSubsample.Ratio444:
scanEncoder.Encode444(image, ref luminanceQuantTable, ref chrominanceQuantTable, cancellationToken);
diff --git a/src/ImageSharp/Formats/Tiff/Compression/Compressors/T4BitCompressor.cs b/src/ImageSharp/Formats/Tiff/Compression/Compressors/T4BitCompressor.cs
index 3e9b7f4e63..30da537eb2 100644
--- a/src/ImageSharp/Formats/Tiff/Compression/Compressors/T4BitCompressor.cs
+++ b/src/ImageSharp/Formats/Tiff/Compression/Compressors/T4BitCompressor.cs
@@ -213,7 +213,9 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Compression.Compressors
this.compressedDataBuffer = this.Allocator.Allocate(maxNeededBytes);
}
- /// Writes a image compressed with CCITT T4 to the stream.
+ ///
+ /// Writes a image compressed with CCITT T4 to the stream.
+ ///
/// The pixels as 8-bit gray array.
/// The strip height.
public override void CompressStrip(Span pixelsAsGray, int height)
diff --git a/src/ImageSharp/Formats/Tiff/Constants/TiffConstants.cs b/src/ImageSharp/Formats/Tiff/Constants/TiffConstants.cs
index 6fe412b925..b545451412 100644
--- a/src/ImageSharp/Formats/Tiff/Constants/TiffConstants.cs
+++ b/src/ImageSharp/Formats/Tiff/Constants/TiffConstants.cs
@@ -40,41 +40,11 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Constants
///
public const int RowsPerStripInfinity = 2147483647;
- ///
- /// Size (in bytes) of the TIFF file header.
- ///
- public const int SizeOfTiffHeader = 8;
-
- ///
- /// Size (in bytes) of each individual TIFF IFD entry
- ///
- public const int SizeOfIfdEntry = 12;
-
- ///
- /// Size (in bytes) of the Short and SShort data types
- ///
- public const int SizeOfShort = 2;
-
- ///
- /// Size (in bytes) of the Long and SLong data types
- ///
- public const int SizeOfLong = 4;
-
///
/// Size (in bytes) of the Rational and SRational data types
///
public const int SizeOfRational = 8;
- ///
- /// Size (in bytes) of the Float data type
- ///
- public const int SizeOfFloat = 4;
-
- ///
- /// Size (in bytes) of the Double data type
- ///
- public const int SizeOfDouble = 8;
-
///
/// The default strip size is 8k.
///
@@ -83,42 +53,22 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Constants
///
/// The bits per sample for 1 bit bicolor images.
///
- public static readonly ushort[] BitsPerSample1Bit = { 1 };
+ public static readonly TiffBitsPerSample BitsPerSample1Bit = new TiffBitsPerSample(1, 0, 0);
///
/// The bits per sample for images with a 4 color palette.
///
- public static readonly ushort[] BitsPerSample4Bit = { 4 };
+ public static readonly TiffBitsPerSample BitsPerSample4Bit = new TiffBitsPerSample(4, 0, 0);
///
/// The bits per sample for 8 bit images.
///
- public static readonly ushort[] BitsPerSample8Bit = { 8 };
-
- ///
- /// The bits per sample for color images with 2 bits for each color channel.
- ///
- public static readonly ushort[] BitsPerSampleRgb2Bit = { 2, 2, 2 };
-
- ///
- /// The bits per sample for color images with 4 bits for each color channel.
- ///
- public static readonly ushort[] BitsPerSampleRgb4Bit = { 4, 4, 4 };
+ public static readonly TiffBitsPerSample BitsPerSample8Bit = new TiffBitsPerSample(8, 0, 0);
///
/// The bits per sample for color images with 8 bits for each color channel.
///
- public static readonly ushort[] BitsPerSampleRgb8Bit = { 8, 8, 8 };
-
- ///
- /// The bits per sample for color images with 10 bits for each color channel.
- ///
- public static readonly ushort[] BitsPerSampleRgb10Bit = { 10, 10, 10 };
-
- ///
- /// The bits per sample for color images with 14 bits for each color channel.
- ///
- public static readonly ushort[] BitsPerSampleRgb14Bit = { 14, 14, 14 };
+ public static readonly TiffBitsPerSample BitsPerSampleRgb8Bit = new TiffBitsPerSample(8, 8, 8);
///
/// The list of mimetypes that equate to a tiff.
diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/BlackIsZeroTiffColor{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/BlackIsZeroTiffColor{TPixel}.cs
index 83cef8e758..a4e5e45dfb 100644
--- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/BlackIsZeroTiffColor{TPixel}.cs
+++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/BlackIsZeroTiffColor{TPixel}.cs
@@ -19,9 +19,9 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
private readonly float factor;
- public BlackIsZeroTiffColor(ushort[] bitsPerSample)
+ public BlackIsZeroTiffColor(TiffBitsPerSample bitsPerSample)
{
- this.bitsPerSample0 = bitsPerSample[0];
+ this.bitsPerSample0 = bitsPerSample.Channel0;
this.factor = (1 << this.bitsPerSample0) - 1.0f;
}
diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/PaletteTiffColor{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/PaletteTiffColor{TPixel}.cs
index 7ed25f8221..796227953e 100644
--- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/PaletteTiffColor{TPixel}.cs
+++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/PaletteTiffColor{TPixel}.cs
@@ -21,9 +21,9 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
/// The number of bits per sample for each pixel.
/// The RGB color lookup table to use for decoding the image.
- public PaletteTiffColor(ushort[] bitsPerSample, ushort[] colorMap)
+ public PaletteTiffColor(TiffBitsPerSample bitsPerSample, ushort[] colorMap)
{
- this.bitsPerSample0 = bitsPerSample[0];
+ this.bitsPerSample0 = bitsPerSample.Channel0;
int colorCount = 1 << this.bitsPerSample0;
this.palette = GeneratePalette(colorMap, colorCount);
}
diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/RgbPlanarTiffColor{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/RgbPlanarTiffColor{TPixel}.cs
index b40158fcee..8dda0cf38f 100644
--- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/RgbPlanarTiffColor{TPixel}.cs
+++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/RgbPlanarTiffColor{TPixel}.cs
@@ -26,11 +26,11 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
private readonly ushort bitsPerSampleB;
- public RgbPlanarTiffColor(ushort[] bitsPerSample)
+ public RgbPlanarTiffColor(TiffBitsPerSample bitsPerSample)
{
- this.bitsPerSampleR = bitsPerSample[0];
- this.bitsPerSampleG = bitsPerSample[1];
- this.bitsPerSampleB = bitsPerSample[2];
+ this.bitsPerSampleR = bitsPerSample.Channel0;
+ this.bitsPerSampleG = bitsPerSample.Channel1;
+ this.bitsPerSampleB = bitsPerSample.Channel2;
this.rFactor = (1 << this.bitsPerSampleR) - 1.0f;
this.gFactor = (1 << this.bitsPerSampleG) - 1.0f;
diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/RgbTiffColor{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/RgbTiffColor{TPixel}.cs
index 816ba67b76..259bb8efa7 100644
--- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/RgbTiffColor{TPixel}.cs
+++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/RgbTiffColor{TPixel}.cs
@@ -27,11 +27,11 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
private readonly ushort bitsPerSampleB;
- public RgbTiffColor(ushort[] bitsPerSample)
+ public RgbTiffColor(TiffBitsPerSample bitsPerSample)
{
- this.bitsPerSampleR = bitsPerSample[0];
- this.bitsPerSampleG = bitsPerSample[1];
- this.bitsPerSampleB = bitsPerSample[2];
+ this.bitsPerSampleR = bitsPerSample.Channel0;
+ this.bitsPerSampleG = bitsPerSample.Channel1;
+ this.bitsPerSampleB = bitsPerSample.Channel2;
this.rFactor = (1 << this.bitsPerSampleR) - 1.0f;
this.gFactor = (1 << this.bitsPerSampleG) - 1.0f;
diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/TiffColorDecoderFactory{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/TiffColorDecoderFactory{TPixel}.cs
index 5555eb537c..36d2ab746e 100644
--- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/TiffColorDecoderFactory{TPixel}.cs
+++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/TiffColorDecoderFactory{TPixel}.cs
@@ -8,107 +8,125 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
internal static class TiffColorDecoderFactory
where TPixel : unmanaged, IPixel
{
- public static TiffBaseColorDecoder Create(TiffColorType colorType, ushort[] bitsPerSample, ushort[] colorMap)
+ public static TiffBaseColorDecoder Create(TiffColorType colorType, TiffBitsPerSample bitsPerSample, ushort[] colorMap)
{
switch (colorType)
{
case TiffColorType.WhiteIsZero:
- DebugGuard.IsTrue(bitsPerSample.Length == 1, "bitsPerSample");
+ DebugGuard.IsTrue(bitsPerSample.Channels == 1, "bitsPerSample");
DebugGuard.IsTrue(colorMap == null, "colorMap");
return new WhiteIsZeroTiffColor(bitsPerSample);
case TiffColorType.WhiteIsZero1:
- DebugGuard.IsTrue(bitsPerSample.Length == 1 && bitsPerSample[0] == 1, "bitsPerSample");
+ DebugGuard.IsTrue(bitsPerSample.Channels == 1 && bitsPerSample.Channel0 == 1, "bitsPerSample");
DebugGuard.IsTrue(colorMap == null, "colorMap");
return new WhiteIsZero1TiffColor();
case TiffColorType.WhiteIsZero4:
- DebugGuard.IsTrue(bitsPerSample.Length == 1 && bitsPerSample[0] == 4, "bitsPerSample");
+ DebugGuard.IsTrue(bitsPerSample.Channels == 1 && bitsPerSample.Channel0 == 4, "bitsPerSample");
DebugGuard.IsTrue(colorMap == null, "colorMap");
return new WhiteIsZero4TiffColor();
case TiffColorType.WhiteIsZero8:
- DebugGuard.IsTrue(bitsPerSample.Length == 1 && bitsPerSample[0] == 8, "bitsPerSample");
+ DebugGuard.IsTrue(bitsPerSample.Channels == 1 && bitsPerSample.Channel0 == 8, "bitsPerSample");
DebugGuard.IsTrue(colorMap == null, "colorMap");
return new WhiteIsZero8TiffColor();
case TiffColorType.BlackIsZero:
- DebugGuard.IsTrue(bitsPerSample.Length == 1, "bitsPerSample");
+ DebugGuard.IsTrue(bitsPerSample.Channels == 1, "bitsPerSample");
DebugGuard.IsTrue(colorMap == null, "colorMap");
return new BlackIsZeroTiffColor(bitsPerSample);
case TiffColorType.BlackIsZero1:
- DebugGuard.IsTrue(bitsPerSample.Length == 1 && bitsPerSample[0] == 1, "bitsPerSample");
+ DebugGuard.IsTrue(bitsPerSample.Channels == 1 && bitsPerSample.Channel0 == 1, "bitsPerSample");
DebugGuard.IsTrue(colorMap == null, "colorMap");
return new BlackIsZero1TiffColor();
case TiffColorType.BlackIsZero4:
- DebugGuard.IsTrue(bitsPerSample.Length == 1 && bitsPerSample[0] == 4, "bitsPerSample");
+ DebugGuard.IsTrue(bitsPerSample.Channels == 1 && bitsPerSample.Channel0 == 4, "bitsPerSample");
DebugGuard.IsTrue(colorMap == null, "colorMap");
return new BlackIsZero4TiffColor();
case TiffColorType.BlackIsZero8:
- DebugGuard.IsTrue(bitsPerSample.Length == 1 && bitsPerSample[0] == 8, "bitsPerSample");
+ DebugGuard.IsTrue(bitsPerSample.Channels == 1 && bitsPerSample.Channel0 == 8, "bitsPerSample");
DebugGuard.IsTrue(colorMap == null, "colorMap");
return new BlackIsZero8TiffColor();
case TiffColorType.Rgb:
- DebugGuard.NotNull(bitsPerSample, "bitsPerSample");
DebugGuard.IsTrue(colorMap == null, "colorMap");
return new RgbTiffColor(bitsPerSample);
case TiffColorType.Rgb222:
DebugGuard.IsTrue(
- bitsPerSample.Length == 3
- && bitsPerSample[2] == 2
- && bitsPerSample[1] == 2
- && bitsPerSample[0] == 2,
+ bitsPerSample.Channels == 3
+ && bitsPerSample.Channel2 == 2
+ && bitsPerSample.Channel1 == 2
+ && bitsPerSample.Channel0 == 2,
"bitsPerSample");
DebugGuard.IsTrue(colorMap == null, "colorMap");
return new RgbTiffColor(bitsPerSample);
case TiffColorType.Rgb444:
DebugGuard.IsTrue(
- bitsPerSample.Length == 3
- && bitsPerSample[2] == 4
- && bitsPerSample[1] == 4
- && bitsPerSample[0] == 4,
+ bitsPerSample.Channels == 3
+ && bitsPerSample.Channel2 == 4
+ && bitsPerSample.Channel1 == 4
+ && bitsPerSample.Channel0 == 4,
"bitsPerSample");
DebugGuard.IsTrue(colorMap == null, "colorMap");
return new Rgb444TiffColor();
case TiffColorType.Rgb888:
DebugGuard.IsTrue(
- bitsPerSample.Length == 3
- && bitsPerSample[2] == 8
- && bitsPerSample[1] == 8
- && bitsPerSample[0] == 8,
+ bitsPerSample.Channels == 3
+ && bitsPerSample.Channel2 == 8
+ && bitsPerSample.Channel1 == 8
+ && bitsPerSample.Channel0 == 8,
"bitsPerSample");
DebugGuard.IsTrue(colorMap == null, "colorMap");
return new Rgb888TiffColor();
case TiffColorType.Rgb101010:
DebugGuard.IsTrue(
- bitsPerSample.Length == 3
- && bitsPerSample[2] == 10
- && bitsPerSample[1] == 10
- && bitsPerSample[0] == 10,
+ bitsPerSample.Channels == 3
+ && bitsPerSample.Channel2 == 10
+ && bitsPerSample.Channel1 == 10
+ && bitsPerSample.Channel0 == 10,
+ "bitsPerSample");
+ DebugGuard.IsTrue(colorMap == null, "colorMap");
+ return new RgbTiffColor(bitsPerSample);
+
+ case TiffColorType.Rgb121212:
+ DebugGuard.IsTrue(
+ bitsPerSample.Channels == 3
+ && bitsPerSample.Channel2 == 12
+ && bitsPerSample.Channel1 == 12
+ && bitsPerSample.Channel0 == 12,
"bitsPerSample");
DebugGuard.IsTrue(colorMap == null, "colorMap");
return new RgbTiffColor(bitsPerSample);
case TiffColorType.Rgb141414:
DebugGuard.IsTrue(
- bitsPerSample.Length == 3
- && bitsPerSample[2] == 14
- && bitsPerSample[1] == 14
- && bitsPerSample[0] == 14,
+ bitsPerSample.Channels == 3
+ && bitsPerSample.Channel2 == 14
+ && bitsPerSample.Channel1 == 14
+ && bitsPerSample.Channel0 == 14,
+ "bitsPerSample");
+ DebugGuard.IsTrue(colorMap == null, "colorMap");
+ return new RgbTiffColor(bitsPerSample);
+
+ case TiffColorType.Rgb161616:
+ DebugGuard.IsTrue(
+ bitsPerSample.Channels == 3
+ && bitsPerSample.Channel2 == 16
+ && bitsPerSample.Channel1 == 16
+ && bitsPerSample.Channel0 == 16,
"bitsPerSample");
DebugGuard.IsTrue(colorMap == null, "colorMap");
return new RgbTiffColor(bitsPerSample);
case TiffColorType.PaletteColor:
- DebugGuard.NotNull(bitsPerSample, "bitsPerSample");
DebugGuard.NotNull(colorMap, "colorMap");
return new PaletteTiffColor(bitsPerSample, colorMap);
@@ -117,12 +135,11 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
}
}
- public static RgbPlanarTiffColor CreatePlanar(TiffColorType colorType, ushort[] bitsPerSample, ushort[] colorMap)
+ public static RgbPlanarTiffColor CreatePlanar(TiffColorType colorType, TiffBitsPerSample bitsPerSample, ushort[] colorMap)
{
switch (colorType)
{
case TiffColorType.RgbPlanar:
- DebugGuard.NotNull(bitsPerSample, "bitsPerSample");
DebugGuard.IsTrue(colorMap == null, "colorMap");
return new RgbPlanarTiffColor(bitsPerSample);
diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/TiffColorType.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/TiffColorType.cs
index 22d8199533..517926c239 100644
--- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/TiffColorType.cs
+++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/TiffColorType.cs
@@ -78,11 +78,21 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
///
Rgb101010,
+ ///
+ /// RGB color image with 12 bits for each channel.
+ ///
+ Rgb121212,
+
///
/// RGB color image with 14 bits for each channel.
///
Rgb141414,
+ ///
+ /// RGB color image with 16 bits for each channel.
+ ///
+ Rgb161616,
+
///
/// RGB Full Color. Planar configuration of data.
///
diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/WhiteIsZeroTiffColor{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/WhiteIsZeroTiffColor{TPixel}.cs
index 697fe2f073..04b6f98e50 100644
--- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/WhiteIsZeroTiffColor{TPixel}.cs
+++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/WhiteIsZeroTiffColor{TPixel}.cs
@@ -19,9 +19,9 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
private readonly float factor;
- public WhiteIsZeroTiffColor(ushort[] bitsPerSample)
+ public WhiteIsZeroTiffColor(TiffBitsPerSample bitsPerSample)
{
- this.bitsPerSample0 = bitsPerSample[0];
+ this.bitsPerSample0 = bitsPerSample.Channel0;
this.factor = (float)Math.Pow(2, this.bitsPerSample0) - 1.0f;
}
diff --git a/src/ImageSharp/Formats/Tiff/TiffBitsPerPixel.cs b/src/ImageSharp/Formats/Tiff/TiffBitsPerPixel.cs
index ab9f3cbec0..73f3f4b77e 100644
--- a/src/ImageSharp/Formats/Tiff/TiffBitsPerPixel.cs
+++ b/src/ImageSharp/Formats/Tiff/TiffBitsPerPixel.cs
@@ -30,6 +30,13 @@ namespace SixLabors.ImageSharp.Formats.Tiff
///
Bit8 = 8,
+ ///
+ /// 10 bits per pixel, for gray images.
+ ///
+ /// Note: The TiffEncoder does not yet support 10 bits per pixel and will default to 24 bits per pixel instead.
+ ///
+ Bit10 = 10,
+
///
/// 12 bits per pixel. 4 bit for each color channel.
///
@@ -37,6 +44,20 @@ namespace SixLabors.ImageSharp.Formats.Tiff
///
Bit12 = 12,
+ ///
+ /// 14 bits per pixel, for gray images.
+ ///
+ /// Note: The TiffEncoder does not yet support 14 bits per pixel images and will default to 24 bits per pixel instead.
+ ///
+ Bit14 = 14,
+
+ ///
+ /// 16 bits per pixel, for gray images.
+ ///
+ /// Note: The TiffEncoder does not yet support 16 bits per color channel and will default to 24 bits per pixel instead.
+ ///
+ Bit16 = 16,
+
///
/// 24 bits per pixel. One byte for each color channel.
///
@@ -49,11 +70,25 @@ namespace SixLabors.ImageSharp.Formats.Tiff
///
Bit30 = 30,
+ ///
+ /// 36 bits per pixel. 12 bit for each color channel.
+ ///
+ /// Note: The TiffEncoder does not yet support 12 bits per color channel and will default to 24 bits per pixel instead.
+ ///
+ Bit36 = 36,
+
///
/// 42 bits per pixel. 14 bit for each color channel.
///
/// Note: The TiffEncoder does not yet support 14 bits per color channel and will default to 24 bits per pixel instead.
///
Bit42 = 42,
+
+ ///
+ /// 48 bits per pixel. 16 bit for each color channel.
+ ///
+ /// Note: The TiffEncoder does not yet support 16 bits per color channel and will default to 24 bits per pixel instead.
+ ///
+ Bit48 = 48,
}
}
diff --git a/src/ImageSharp/Formats/Tiff/TiffBitsPerSample.cs b/src/ImageSharp/Formats/Tiff/TiffBitsPerSample.cs
index 088ef5d6f8..8fd26ac13d 100644
--- a/src/ImageSharp/Formats/Tiff/TiffBitsPerSample.cs
+++ b/src/ImageSharp/Formats/Tiff/TiffBitsPerSample.cs
@@ -1,56 +1,138 @@
// Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0.
+using System;
+
namespace SixLabors.ImageSharp.Formats.Tiff
{
///
/// The number of bits per component.
///
- public enum TiffBitsPerSample
+ public readonly struct TiffBitsPerSample : IEquatable
{
///
- /// The Bits per samples is not known.
+ /// The bits for the channel 0.
///
- Unknown = 0,
+ public readonly ushort Channel0;
///
- /// One bit per sample for bicolor images.
+ /// The bits for the channel 1.
///
- Bit1 = 1,
+ public readonly ushort Channel1;
///
- /// Four bits per sample for grayscale images with 16 different levels of gray or paletted images with a palette of 16 colors.
+ /// The bits for the channel 2.
///
- Bit4 = 4,
+ public readonly ushort Channel2;
///
- /// Eight bits per sample for grayscale images with 256 different levels of gray or paletted images with a palette of 256 colors.
+ /// The number of channels.
///
- Bit8 = 8,
+ public readonly byte Channels;
///
- /// Six bits per sample, each channel has 2 bits.
+ /// Initializes a new instance of the struct.
///
- Bit6 = 6,
+ /// The bits for the channel 0.
+ /// The bits for the channel 1.
+ /// The bits for the channel 2.
+ public TiffBitsPerSample(ushort channel0, ushort channel1, ushort channel2)
+ {
+ this.Channel0 = (ushort)Numerics.Clamp(channel0, 0, 32);
+ this.Channel1 = (ushort)Numerics.Clamp(channel1, 0, 32);
+ this.Channel2 = (ushort)Numerics.Clamp(channel2, 0, 32);
- ///
- /// Twelve bits per sample, each channel has 4 bits.
- ///
- Bit12 = 12,
+ this.Channels = 0;
+ this.Channels += (byte)(this.Channel0 != 0 ? 1 : 0);
+ this.Channels += (byte)(this.Channel1 != 0 ? 1 : 0);
+ this.Channels += (byte)(this.Channel2 != 0 ? 1 : 0);
+ }
///
- /// 24 bits per sample, each color channel has 8 Bits.
+ /// Tries to parse a ushort array and convert it into a TiffBitsPerSample struct.
///
- Bit24 = 24,
+ /// The value to parse.
+ /// The tiff bits per sample.
+ /// True, if the value could be parsed.
+ public static bool TryParse(ushort[] value, out TiffBitsPerSample sample)
+ {
+ if (value is null || value.Length == 0)
+ {
+ sample = default;
+ return false;
+ }
+
+ ushort c2;
+ ushort c1;
+ ushort c0;
+ switch (value.Length)
+ {
+ case 3:
+ c2 = value[2];
+ c1 = value[1];
+ c0 = value[0];
+ break;
+ case 2:
+ c2 = 0;
+ c1 = value[1];
+ c0 = value[0];
+ break;
+ default:
+ c2 = 0;
+ c1 = 0;
+ c0 = value[0];
+ break;
+ }
+
+ sample = new TiffBitsPerSample(c0, c1, c2);
+ return true;
+ }
+
+ ///
+ public override bool Equals(object obj)
+ => obj is TiffBitsPerSample sample && this.Equals(sample);
+
+ ///
+ public bool Equals(TiffBitsPerSample other)
+ => this.Channel0 == other.Channel0
+ && this.Channel1 == other.Channel1
+ && this.Channel2 == other.Channel2;
+
+ ///
+ public override int GetHashCode()
+ => HashCode.Combine(this.Channel0, this.Channel1, this.Channel2);
///
- /// Thirty bits per sample, each channel has 10 bits.
+ /// Converts the bits per sample struct to an ushort array.
///
- Bit30 = 30,
+ /// Bits per sample as ushort array.
+ public ushort[] ToArray()
+ {
+ if (this.Channel1 == 0)
+ {
+ return new[] { this.Channel0 };
+ }
+
+ if (this.Channel2 == 0)
+ {
+ return new[] { this.Channel0, this.Channel1 };
+ }
+
+ return new[] { this.Channel0, this.Channel1, this.Channel2 };
+ }
///
- /// Forty two bits per sample, each channel has 14 bits.
+ /// Gets the bits per pixel for the given bits per sample.
///
- Bit42 = 42,
+ /// Bits per pixel.
+ public TiffBitsPerPixel BitsPerPixel()
+ {
+ int bitsPerPixel = this.Channel0 + this.Channel1 + this.Channel2;
+ return (TiffBitsPerPixel)bitsPerPixel;
+ }
+
+ ///
+ public override string ToString()
+ => $"TiffBitsPerSample({this.Channel0}, {this.Channel1}, {this.Channel2})";
}
}
diff --git a/src/ImageSharp/Formats/Tiff/TiffBitsPerSampleExtensions.cs b/src/ImageSharp/Formats/Tiff/TiffBitsPerSampleExtensions.cs
deleted file mode 100644
index ca0f0befcc..0000000000
--- a/src/ImageSharp/Formats/Tiff/TiffBitsPerSampleExtensions.cs
+++ /dev/null
@@ -1,111 +0,0 @@
-// Copyright (c) Six Labors.
-// Licensed under the Apache License, Version 2.0.
-
-using System;
-using SixLabors.ImageSharp.Formats.Tiff.Constants;
-
-namespace SixLabors.ImageSharp.Formats.Tiff
-{
- internal static class TiffBitsPerSampleExtensions
- {
- ///
- /// Gets the bits per channel array for a given BitsPerSample value, e,g, for RGB888: [8, 8, 8]
- ///
- /// The tiff bits per sample.
- /// Bits per sample array.
- public static ushort[] Bits(this TiffBitsPerSample tiffBitsPerSample)
- {
- switch (tiffBitsPerSample)
- {
- case TiffBitsPerSample.Bit1:
- return TiffConstants.BitsPerSample1Bit;
- case TiffBitsPerSample.Bit4:
- return TiffConstants.BitsPerSample4Bit;
- case TiffBitsPerSample.Bit6:
- return TiffConstants.BitsPerSampleRgb2Bit;
- case TiffBitsPerSample.Bit8:
- return TiffConstants.BitsPerSample8Bit;
- case TiffBitsPerSample.Bit12:
- return TiffConstants.BitsPerSampleRgb4Bit;
- case TiffBitsPerSample.Bit24:
- return TiffConstants.BitsPerSampleRgb8Bit;
- case TiffBitsPerSample.Bit30:
- return TiffConstants.BitsPerSampleRgb10Bit;
- case TiffBitsPerSample.Bit42:
- return TiffConstants.BitsPerSampleRgb14Bit;
-
- default:
- return Array.Empty();
- }
- }
-
- ///
- /// Maps an array of bits per sample to a concrete enum value.
- ///
- /// The bits per sample array.
- /// TiffBitsPerSample enum value.
- public static TiffBitsPerSample GetBitsPerSample(this ushort[] bitsPerSample)
- {
- switch (bitsPerSample.Length)
- {
- case 3:
- if (bitsPerSample[2] == TiffConstants.BitsPerSampleRgb14Bit[2] &&
- bitsPerSample[1] == TiffConstants.BitsPerSampleRgb14Bit[1] &&
- bitsPerSample[0] == TiffConstants.BitsPerSampleRgb14Bit[0])
- {
- return TiffBitsPerSample.Bit42;
- }
-
- if (bitsPerSample[2] == TiffConstants.BitsPerSampleRgb10Bit[2] &&
- bitsPerSample[1] == TiffConstants.BitsPerSampleRgb10Bit[1] &&
- bitsPerSample[0] == TiffConstants.BitsPerSampleRgb10Bit[0])
- {
- return TiffBitsPerSample.Bit30;
- }
-
- if (bitsPerSample[2] == TiffConstants.BitsPerSampleRgb8Bit[2] &&
- bitsPerSample[1] == TiffConstants.BitsPerSampleRgb8Bit[1] &&
- bitsPerSample[0] == TiffConstants.BitsPerSampleRgb8Bit[0])
- {
- return TiffBitsPerSample.Bit24;
- }
-
- if (bitsPerSample[2] == TiffConstants.BitsPerSampleRgb4Bit[2] &&
- bitsPerSample[1] == TiffConstants.BitsPerSampleRgb4Bit[1] &&
- bitsPerSample[0] == TiffConstants.BitsPerSampleRgb4Bit[0])
- {
- return TiffBitsPerSample.Bit12;
- }
-
- if (bitsPerSample[2] == TiffConstants.BitsPerSampleRgb2Bit[2] &&
- bitsPerSample[1] == TiffConstants.BitsPerSampleRgb2Bit[1] &&
- bitsPerSample[0] == TiffConstants.BitsPerSampleRgb2Bit[0])
- {
- return TiffBitsPerSample.Bit6;
- }
-
- break;
-
- case 1:
- if (bitsPerSample[0] == TiffConstants.BitsPerSample1Bit[0])
- {
- return TiffBitsPerSample.Bit1;
- }
-
- if (bitsPerSample[0] == TiffConstants.BitsPerSample4Bit[0])
- {
- return TiffBitsPerSample.Bit4;
- }
-
- if (bitsPerSample[0] == TiffConstants.BitsPerSample8Bit[0])
- {
- return TiffBitsPerSample.Bit8;
- }
-
- break;
- }
-
- return TiffBitsPerSample.Unknown;
- }
- }
-}
diff --git a/src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs b/src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs
index fadb4f7c2e..5ce696118d 100644
--- a/src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs
+++ b/src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs
@@ -50,7 +50,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff
}
///
- /// Gets or sets the number of bits per component of the pixel format used to decode the image.
+ /// Gets or sets the bits per sample.
///
public TiffBitsPerSample BitsPerSample { get; set; }
@@ -198,7 +198,9 @@ namespace SixLabors.ImageSharp.Formats.Tiff
/// The size (in bytes) of the required pixel buffer.
private int CalculateStripBufferSize(int width, int height, int plane = -1)
{
- int bitsPerPixel;
+ DebugGuard.MustBeLessThanOrEqualTo(plane, 3, nameof(plane));
+
+ int bitsPerPixel = 0;
if (this.PlanarConfiguration == TiffPlanarConfiguration.Chunky)
{
@@ -207,7 +209,21 @@ namespace SixLabors.ImageSharp.Formats.Tiff
}
else
{
- bitsPerPixel = this.BitsPerSample.Bits()[plane];
+ switch (plane)
+ {
+ case 0:
+ bitsPerPixel = this.BitsPerSample.Channel0;
+ break;
+ case 1:
+ bitsPerPixel = this.BitsPerSample.Channel1;
+ break;
+ case 2:
+ bitsPerPixel = this.BitsPerSample.Channel2;
+ break;
+ default:
+ TiffThrowHelper.ThrowNotSupported("More then 3 color channels are not supported");
+ break;
+ }
}
int bytesPerRow = ((width * bitsPerPixel) + 7) / 8;
@@ -225,7 +241,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff
private void DecodeStripsPlanar(ImageFrame frame, int rowsPerStrip, Number[] stripOffsets, Number[] stripByteCounts)
where TPixel : unmanaged, IPixel
{
- int stripsPerPixel = this.BitsPerSample.Bits().Length;
+ int stripsPerPixel = this.BitsPerSample.Channels;
int stripsPerPlane = stripOffsets.Length / stripsPerPixel;
int bitsPerPixel = this.BitsPerPixel;
@@ -243,7 +259,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff
using TiffBaseDecompressor decompressor = TiffDecompressorsFactory.Create(this.CompressionType, this.memoryAllocator, this.PhotometricInterpretation, frame.Width, bitsPerPixel, this.Predictor, this.FaxCompressionOptions);
- RgbPlanarTiffColor colorDecoder = TiffColorDecoderFactory.CreatePlanar(this.ColorType, this.BitsPerSample.Bits(), this.ColorMap);
+ RgbPlanarTiffColor colorDecoder = TiffColorDecoderFactory.CreatePlanar(this.ColorType, this.BitsPerSample, this.ColorMap);
for (int i = 0; i < stripsPerPlane; i++)
{
@@ -286,7 +302,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff
using TiffBaseDecompressor decompressor = TiffDecompressorsFactory.Create(this.CompressionType, this.memoryAllocator, this.PhotometricInterpretation, frame.Width, bitsPerPixel, this.Predictor, this.FaxCompressionOptions);
- TiffBaseColorDecoder colorDecoder = TiffColorDecoderFactory.Create(this.ColorType, this.BitsPerSample.Bits(), this.ColorMap);
+ TiffBaseColorDecoder colorDecoder = TiffColorDecoderFactory.Create(this.ColorType, this.BitsPerSample, this.ColorMap);
for (int stripIndex = 0; stripIndex < stripOffsets.Length; stripIndex++)
{
diff --git a/src/ImageSharp/Formats/Tiff/TiffDecoderOptionsParser.cs b/src/ImageSharp/Formats/Tiff/TiffDecoderOptionsParser.cs
index eeac6a33c2..288f01cd1c 100644
--- a/src/ImageSharp/Formats/Tiff/TiffDecoderOptionsParser.cs
+++ b/src/ImageSharp/Formats/Tiff/TiffDecoderOptionsParser.cs
@@ -1,7 +1,6 @@
// Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0.
-using System;
using System.Linq;
using SixLabors.ImageSharp.Formats.Tiff.Compression;
using SixLabors.ImageSharp.Formats.Tiff.Constants;
@@ -69,7 +68,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff
options.Predictor = frameMetadata.Predictor ?? TiffPredictor.None;
options.PhotometricInterpretation = frameMetadata.PhotometricInterpretation ?? TiffPhotometricInterpretation.Rgb;
options.BitsPerPixel = frameMetadata.BitsPerPixel != null ? (int)frameMetadata.BitsPerPixel.Value : (int)TiffBitsPerPixel.Bit24;
- options.BitsPerSample = GetBitsPerSample(frameMetadata.BitsPerPixel);
+ options.BitsPerSample = frameMetadata.BitsPerSample ?? new TiffBitsPerSample(0, 0, 0);
options.ParseColorType(exifProfile);
options.ParseCompression(frameMetadata.Compression, exifProfile);
@@ -99,26 +98,32 @@ namespace SixLabors.ImageSharp.Formats.Tiff
{
case TiffPhotometricInterpretation.WhiteIsZero:
{
- if (options.BitsPerSample.Bits().Length != 1)
+ if (options.BitsPerSample.Channels != 1)
{
TiffThrowHelper.ThrowNotSupported("The number of samples in the TIFF BitsPerSample entry is not supported.");
}
- switch (options.BitsPerSample)
+ ushort bitsPerChannel = options.BitsPerSample.Channel0;
+ if (bitsPerChannel > 16)
{
- case TiffBitsPerSample.Bit8:
+ TiffThrowHelper.ThrowNotSupported("Bits per sample is not supported.");
+ }
+
+ switch (bitsPerChannel)
+ {
+ case 8:
{
options.ColorType = TiffColorType.WhiteIsZero8;
break;
}
- case TiffBitsPerSample.Bit4:
+ case 4:
{
options.ColorType = TiffColorType.WhiteIsZero4;
break;
}
- case TiffBitsPerSample.Bit1:
+ case 1:
{
options.ColorType = TiffColorType.WhiteIsZero1;
break;
@@ -136,26 +141,32 @@ namespace SixLabors.ImageSharp.Formats.Tiff
case TiffPhotometricInterpretation.BlackIsZero:
{
- if (options.BitsPerSample.Bits().Length != 1)
+ if (options.BitsPerSample.Channels != 1)
{
TiffThrowHelper.ThrowNotSupported("The number of samples in the TIFF BitsPerSample entry is not supported.");
}
- switch (options.BitsPerSample)
+ ushort bitsPerChannel = options.BitsPerSample.Channel0;
+ if (bitsPerChannel > 16)
+ {
+ TiffThrowHelper.ThrowNotSupported("Bits per sample is not supported.");
+ }
+
+ switch (bitsPerChannel)
{
- case TiffBitsPerSample.Bit8:
+ case 8:
{
options.ColorType = TiffColorType.BlackIsZero8;
break;
}
- case TiffBitsPerSample.Bit4:
+ case 4:
{
options.ColorType = TiffColorType.BlackIsZero4;
break;
}
- case TiffBitsPerSample.Bit1:
+ case 1:
{
options.ColorType = TiffColorType.BlackIsZero1;
break;
@@ -173,30 +184,39 @@ namespace SixLabors.ImageSharp.Formats.Tiff
case TiffPhotometricInterpretation.Rgb:
{
- if (options.BitsPerSample.Bits().Length != 3)
+ if (options.BitsPerSample.Channels != 3)
{
TiffThrowHelper.ThrowNotSupported("The number of samples in the TIFF BitsPerSample entry is not supported.");
}
if (options.PlanarConfiguration == TiffPlanarConfiguration.Chunky)
{
- switch (options.BitsPerSample)
+ ushort bitsPerChannel = options.BitsPerSample.Channel0;
+ switch (bitsPerChannel)
{
- case TiffBitsPerSample.Bit42:
+ case 16:
+ options.ColorType = TiffColorType.Rgb161616;
+ break;
+
+ case 14:
options.ColorType = TiffColorType.Rgb141414;
break;
- case TiffBitsPerSample.Bit30:
+ case 12:
+ options.ColorType = TiffColorType.Rgb121212;
+ break;
+
+ case 10:
options.ColorType = TiffColorType.Rgb101010;
break;
- case TiffBitsPerSample.Bit24:
+ case 8:
options.ColorType = TiffColorType.Rgb888;
break;
- case TiffBitsPerSample.Bit12:
+ case 4:
options.ColorType = TiffColorType.Rgb444;
break;
- case TiffBitsPerSample.Bit6:
+ case 2:
options.ColorType = TiffColorType.Rgb222;
break;
default:
@@ -217,7 +237,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff
options.ColorMap = exifProfile.GetValue(ExifTag.ColorMap)?.Value;
if (options.ColorMap != null)
{
- if (options.BitsPerSample.Bits().Length != 1)
+ if (options.BitsPerSample.Channels != 1)
{
TiffThrowHelper.ThrowNotSupported("The number of samples in the TIFF BitsPerSample entry is not supported.");
}
@@ -291,18 +311,5 @@ namespace SixLabors.ImageSharp.Formats.Tiff
}
}
}
-
- private static TiffBitsPerSample GetBitsPerSample(TiffBitsPerPixel? bitsPerPixel) => bitsPerPixel switch
- {
- TiffBitsPerPixel.Bit1 => TiffBitsPerSample.Bit1,
- TiffBitsPerPixel.Bit4 => TiffBitsPerSample.Bit4,
- TiffBitsPerPixel.Bit6 => TiffBitsPerSample.Bit6,
- TiffBitsPerPixel.Bit8 => TiffBitsPerSample.Bit8,
- TiffBitsPerPixel.Bit12 => TiffBitsPerSample.Bit12,
- TiffBitsPerPixel.Bit24 => TiffBitsPerSample.Bit24,
- TiffBitsPerPixel.Bit30 => TiffBitsPerSample.Bit30,
- TiffBitsPerPixel.Bit42 => TiffBitsPerSample.Bit42,
- _ => throw new NotSupportedException("The bits per pixel are not supported"),
- };
}
}
diff --git a/src/ImageSharp/Formats/Tiff/TiffEncoderCore.cs b/src/ImageSharp/Formats/Tiff/TiffEncoderCore.cs
index d5137c4357..2273d759f0 100644
--- a/src/ImageSharp/Formats/Tiff/TiffEncoderCore.cs
+++ b/src/ImageSharp/Formats/Tiff/TiffEncoderCore.cs
@@ -320,10 +320,15 @@ namespace SixLabors.ImageSharp.Formats.Tiff
this.SetEncoderOptions(bitsPerPixel, photometricInterpretation ?? TiffPhotometricInterpretation.BlackIsZero, compression, predictor);
break;
case TiffBitsPerPixel.Bit6:
+ case TiffBitsPerPixel.Bit10:
case TiffBitsPerPixel.Bit12:
+ case TiffBitsPerPixel.Bit14:
+ case TiffBitsPerPixel.Bit16:
case TiffBitsPerPixel.Bit30:
+ case TiffBitsPerPixel.Bit36:
case TiffBitsPerPixel.Bit42:
- // Encoding 42, 30, 12 and 6 bits per pixel is not yet supported. Default to 24 bits.
+ case TiffBitsPerPixel.Bit48:
+ // Encoding not yet supported bits per pixel will default to 24 bits.
this.SetEncoderOptions(TiffBitsPerPixel.Bit24, TiffPhotometricInterpretation.Rgb, compression, TiffPredictor.None);
break;
default:
diff --git a/src/ImageSharp/Formats/Tiff/TiffEncoderEntriesCollector.cs b/src/ImageSharp/Formats/Tiff/TiffEncoderEntriesCollector.cs
index 9bc0792c40..43a0868496 100644
--- a/src/ImageSharp/Formats/Tiff/TiffEncoderEntriesCollector.cs
+++ b/src/ImageSharp/Formats/Tiff/TiffEncoderEntriesCollector.cs
@@ -318,34 +318,34 @@ namespace SixLabors.ImageSharp.Formats.Tiff
case TiffPhotometricInterpretation.PaletteColor:
if (encoder.BitsPerPixel == TiffBitsPerPixel.Bit4)
{
- return TiffConstants.BitsPerSample4Bit;
+ return TiffConstants.BitsPerSample4Bit.ToArray();
}
else
{
- return TiffConstants.BitsPerSample8Bit;
+ return TiffConstants.BitsPerSample8Bit.ToArray();
}
case TiffPhotometricInterpretation.Rgb:
- return TiffConstants.BitsPerSampleRgb8Bit;
+ return TiffConstants.BitsPerSampleRgb8Bit.ToArray();
case TiffPhotometricInterpretation.WhiteIsZero:
if (encoder.BitsPerPixel == TiffBitsPerPixel.Bit1)
{
- return TiffConstants.BitsPerSample1Bit;
+ return TiffConstants.BitsPerSample1Bit.ToArray();
}
- return TiffConstants.BitsPerSample8Bit;
+ return TiffConstants.BitsPerSample8Bit.ToArray();
case TiffPhotometricInterpretation.BlackIsZero:
if (encoder.BitsPerPixel == TiffBitsPerPixel.Bit1)
{
- return TiffConstants.BitsPerSample1Bit;
+ return TiffConstants.BitsPerSample1Bit.ToArray();
}
- return TiffConstants.BitsPerSample8Bit;
+ return TiffConstants.BitsPerSample8Bit.ToArray();
default:
- return TiffConstants.BitsPerSampleRgb8Bit;
+ return TiffConstants.BitsPerSampleRgb8Bit.ToArray();
}
}
diff --git a/src/ImageSharp/Formats/Tiff/TiffFrameMetadata.cs b/src/ImageSharp/Formats/Tiff/TiffFrameMetadata.cs
index 25a0578e91..002dbf039e 100644
--- a/src/ImageSharp/Formats/Tiff/TiffFrameMetadata.cs
+++ b/src/ImageSharp/Formats/Tiff/TiffFrameMetadata.cs
@@ -35,6 +35,11 @@ namespace SixLabors.ImageSharp.Formats.Tiff
///
public TiffBitsPerPixel? BitsPerPixel { get; set; }
+ ///
+ /// Gets or sets number of bits per component.
+ ///
+ public TiffBitsPerSample? BitsPerSample { get; set; }
+
///
/// Gets or sets the compression scheme used on the image data.
///
@@ -64,7 +69,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff
}
///
- /// Parses the given Exif profile to populate the properties of the tiff frame meta data..
+ /// Parses the given Exif profile to populate the properties of the tiff frame meta data.
///
/// The tiff frame meta data.
/// The Exif profile containing tiff frame directory tags.
@@ -72,11 +77,14 @@ namespace SixLabors.ImageSharp.Formats.Tiff
{
if (profile != null)
{
- ushort[] bitsPerSample = profile.GetValue(ExifTag.BitsPerSample)?.Value;
- meta.BitsPerPixel = BitsPerPixelFromBitsPerSample(bitsPerSample);
+ if (TiffBitsPerSample.TryParse(profile.GetValue(ExifTag.BitsPerSample)?.Value, out TiffBitsPerSample bitsPerSample))
+ {
+ meta.BitsPerSample = bitsPerSample;
+ }
+
+ meta.BitsPerPixel = meta.BitsPerSample?.BitsPerPixel();
meta.Compression = (TiffCompression?)profile.GetValue(ExifTag.Compression)?.Value;
- meta.PhotometricInterpretation =
- (TiffPhotometricInterpretation?)profile.GetValue(ExifTag.PhotometricInterpretation)?.Value;
+ meta.PhotometricInterpretation = (TiffPhotometricInterpretation?)profile.GetValue(ExifTag.PhotometricInterpretation)?.Value;
meta.Predictor = (TiffPredictor?)profile.GetValue(ExifTag.Predictor)?.Value;
profile.RemoveValue(ExifTag.BitsPerSample);
@@ -86,27 +94,6 @@ namespace SixLabors.ImageSharp.Formats.Tiff
}
}
- ///
- /// Gets the bits per pixel for the given bits per sample.
- ///
- /// The tiff bits per sample.
- /// Bits per pixel.
- private static TiffBitsPerPixel? BitsPerPixelFromBitsPerSample(ushort[] bitsPerSample)
- {
- if (bitsPerSample == null)
- {
- return null;
- }
-
- int bitsPerPixel = 0;
- foreach (ushort bits in bitsPerSample)
- {
- bitsPerPixel += bits;
- }
-
- return (TiffBitsPerPixel)bitsPerPixel;
- }
-
///
public IDeepCloneable DeepClone() => new TiffFrameMetadata(this);
}
diff --git a/src/ImageSharp/Formats/Tiff/Writers/TiffBaseColorWriter{TPixel}.cs b/src/ImageSharp/Formats/Tiff/Writers/TiffBaseColorWriter{TPixel}.cs
index 232daa18d6..7100fe9fc8 100644
--- a/src/ImageSharp/Formats/Tiff/Writers/TiffBaseColorWriter{TPixel}.cs
+++ b/src/ImageSharp/Formats/Tiff/Writers/TiffBaseColorWriter{TPixel}.cs
@@ -79,10 +79,6 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Writers
this.Dispose(true);
}
- protected static Span GetStripPixels(Buffer2D buffer2D, int y, int height)
- where T : struct
- => buffer2D.GetSingleSpan().Slice(y * buffer2D.Width, height * buffer2D.Width);
-
protected abstract void EncodeStrip(int y, int height, TiffBaseCompressor compressor);
///
diff --git a/src/ImageSharp/Formats/Tiff/Writers/TiffBiColorWriter{TPixel}.cs b/src/ImageSharp/Formats/Tiff/Writers/TiffBiColorWriter{TPixel}.cs
index be5c837eae..662e729ef9 100644
--- a/src/ImageSharp/Formats/Tiff/Writers/TiffBiColorWriter{TPixel}.cs
+++ b/src/ImageSharp/Formats/Tiff/Writers/TiffBiColorWriter{TPixel}.cs
@@ -36,38 +36,50 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Writers
///
protected override void EncodeStrip(int y, int height, TiffBaseCompressor compressor)
{
- this.pixelsAsGray ??= this.MemoryAllocator.Allocate(height * this.Image.Width);
-
- Span pixelAsGraySpan = this.pixelsAsGray.Slice(0, height * this.Image.Width);
-
- Span pixelsBlackWhite = GetStripPixels(this.imageBlackWhite.GetRootFramePixelBuffer(), y, height);
-
- PixelOperations.Instance.ToL8Bytes(this.Configuration, pixelsBlackWhite, pixelAsGraySpan, pixelsBlackWhite.Length);
+ int width = this.Image.Width;
if (compressor.Method == TiffCompression.CcittGroup3Fax || compressor.Method == TiffCompression.Ccitt1D)
{
// Special case for T4BitCompressor.
- compressor.CompressStrip(pixelAsGraySpan, height);
+ int stripPixels = width * height;
+ this.pixelsAsGray ??= this.MemoryAllocator.Allocate(stripPixels);
+ Span pixelAsGraySpan = this.pixelsAsGray.GetSpan();
+ int lastRow = y + height;
+ int grayRowIdx = 0;
+ for (int row = y; row < lastRow; row++)
+ {
+ Span pixelsBlackWhiteRow = this.imageBlackWhite.GetPixelRowSpan(row);
+ Span pixelAsGrayRow = pixelAsGraySpan.Slice(grayRowIdx * width, width);
+ PixelOperations.Instance.ToL8Bytes(this.Configuration, pixelsBlackWhiteRow, pixelAsGrayRow, width);
+ grayRowIdx++;
+ }
+
+ compressor.CompressStrip(pixelAsGraySpan.Slice(0, stripPixels), height);
}
else
{
// Write uncompressed image.
int bytesPerStrip = this.BytesPerRow * height;
this.bitStrip ??= this.MemoryAllocator.AllocateManagedByteBuffer(bytesPerStrip);
+ this.pixelsAsGray ??= this.MemoryAllocator.Allocate(width);
+ Span pixelAsGraySpan = this.pixelsAsGray.GetSpan();
Span rows = this.bitStrip.Slice(0, bytesPerStrip);
rows.Clear();
- int grayPixelIndex = 0;
- for (int s = 0; s < height; s++)
+ int outputRowIdx = 0;
+ int lastRow = y + height;
+ for (int row = y; row < lastRow; row++)
{
int bitIndex = 0;
int byteIndex = 0;
- Span outputRow = rows.Slice(s * this.BytesPerRow);
+ Span outputRow = rows.Slice(outputRowIdx * this.BytesPerRow);
+ Span pixelsBlackWhiteRow = this.imageBlackWhite.GetPixelRowSpan(row);
+ PixelOperations.Instance.ToL8Bytes(this.Configuration, pixelsBlackWhiteRow, pixelAsGraySpan, width);
for (int x = 0; x < this.Image.Width; x++)
{
int shift = 7 - bitIndex;
- if (pixelAsGraySpan[grayPixelIndex++] == 255)
+ if (pixelAsGraySpan[x] == 255)
{
outputRow[byteIndex] |= (byte)(1 << shift);
}
@@ -79,6 +91,8 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Writers
bitIndex = 0;
}
}
+
+ outputRowIdx++;
}
compressor.CompressStrip(rows, height);
diff --git a/src/ImageSharp/Formats/Tiff/Writers/TiffCompositeColorWriter{TPixel}.cs b/src/ImageSharp/Formats/Tiff/Writers/TiffCompositeColorWriter{TPixel}.cs
index 4df57f7e85..43cb666b6a 100644
--- a/src/ImageSharp/Formats/Tiff/Writers/TiffCompositeColorWriter{TPixel}.cs
+++ b/src/ImageSharp/Formats/Tiff/Writers/TiffCompositeColorWriter{TPixel}.cs
@@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0.
using System;
+using System.Buffers;
using SixLabors.ImageSharp.Formats.Tiff.Compression;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
@@ -30,12 +31,22 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Writers
this.rowBuffer.Clear();
- Span rowSpan = this.rowBuffer.GetSpan().Slice(0, this.BytesPerRow * height);
+ Span outputRowSpan = this.rowBuffer.GetSpan().Slice(0, this.BytesPerRow * height);
- Span pixels = GetStripPixels(this.Image.PixelBuffer, y, height);
+ int width = this.Image.Width;
+ using IMemoryOwner stripPixelBuffer = this.MemoryAllocator.Allocate(height * width);
+ Span stripPixels = stripPixelBuffer.GetSpan();
+ int lastRow = y + height;
+ int stripPixelsRowIdx = 0;
+ for (int row = y; row < lastRow; row++)
+ {
+ Span stripPixelsRow = this.Image.PixelBuffer.GetRowSpan(row);
+ stripPixelsRow.CopyTo(stripPixels.Slice(stripPixelsRowIdx * width, width));
+ stripPixelsRowIdx++;
+ }
- this.EncodePixels(pixels, rowSpan);
- compressor.CompressStrip(rowSpan, height);
+ this.EncodePixels(stripPixels, outputRowSpan);
+ compressor.CompressStrip(outputRowSpan, height);
}
protected abstract void EncodePixels(Span pixels, Span buffer);
diff --git a/src/ImageSharp/Formats/Tiff/Writers/TiffPaletteWriter{TPixel}.cs b/src/ImageSharp/Formats/Tiff/Writers/TiffPaletteWriter{TPixel}.cs
index d1a3dd1ea3..61e24d6529 100644
--- a/src/ImageSharp/Formats/Tiff/Writers/TiffPaletteWriter{TPixel}.cs
+++ b/src/ImageSharp/Formats/Tiff/Writers/TiffPaletteWriter{TPixel}.cs
@@ -5,7 +5,6 @@ using System;
using System.Buffers;
using System.Runtime.InteropServices;
-using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Formats.Tiff.Compression;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.Metadata.Profiles.Exif;
@@ -21,6 +20,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Writers
private readonly int colorPaletteSize;
private readonly int colorPaletteBytes;
private readonly IndexedImageFrame quantizedImage;
+ private IMemoryOwner indexedPixelsBuffer;
public TiffPaletteWriter(
ImageFrame image,
@@ -55,22 +55,24 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Writers
///
protected override void EncodeStrip(int y, int height, TiffBaseCompressor compressor)
{
- Span indexedPixels = GetStripPixels(((IPixelSource)this.quantizedImage).PixelBuffer, y, height);
+ int width = this.Image.Width;
+
if (this.BitsPerPixel == 4)
{
- int width = this.Image.Width;
int halfWidth = width >> 1;
int excess = (width & 1) * height; // (width % 2) * height
int rows4BitBufferLength = (halfWidth * height) + excess;
- using IMemoryOwner rows4bitBuffer = this.MemoryAllocator.Allocate(rows4BitBufferLength);
- Span rows4bit = rows4bitBuffer.GetSpan();
- int idxPixels = 0;
+ this.indexedPixelsBuffer ??= this.MemoryAllocator.Allocate(rows4BitBufferLength);
+ Span rows4bit = this.indexedPixelsBuffer.GetSpan();
int idx4bitRows = 0;
- for (int row = 0; row < height; row++)
+ int lastRow = y + height;
+ for (int row = y; row < lastRow; row++)
{
+ ReadOnlySpan indexedPixelRow = this.quantizedImage.GetPixelRowSpan(row);
+ int idxPixels = 0;
for (int x = 0; x < halfWidth; x++)
{
- rows4bit[idx4bitRows] = (byte)((indexedPixels[idxPixels] << 4) | (indexedPixels[idxPixels + 1] & 0xF));
+ rows4bit[idx4bitRows] = (byte)((indexedPixelRow[idxPixels] << 4) | (indexedPixelRow[idxPixels + 1] & 0xF));
idxPixels += 2;
idx4bitRows++;
}
@@ -78,7 +80,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Writers
// Make sure rows are byte-aligned.
if (width % 2 != 0)
{
- rows4bit[idx4bitRows++] = (byte)(indexedPixels[idxPixels++] << 4);
+ rows4bit[idx4bitRows++] = (byte)(indexedPixelRow[idxPixels] << 4);
}
}
@@ -86,12 +88,28 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Writers
}
else
{
- compressor.CompressStrip(indexedPixels, height);
+ int stripPixels = width * height;
+ this.indexedPixelsBuffer ??= this.MemoryAllocator.AllocateManagedByteBuffer(stripPixels);
+ Span indexedPixels = this.indexedPixelsBuffer.GetSpan();
+ int lastRow = y + height;
+ int indexedPixelsRowIdx = 0;
+ for (int row = y; row < lastRow; row++)
+ {
+ ReadOnlySpan indexedPixelRow = this.quantizedImage.GetPixelRowSpan(row);
+ indexedPixelRow.CopyTo(indexedPixels.Slice(indexedPixelsRowIdx * width, width));
+ indexedPixelsRowIdx++;
+ }
+
+ compressor.CompressStrip(indexedPixels.Slice(0, stripPixels), height);
}
}
///
- protected override void Dispose(bool disposing) => this.quantizedImage?.Dispose();
+ protected override void Dispose(bool disposing)
+ {
+ this.quantizedImage?.Dispose();
+ this.indexedPixelsBuffer?.Dispose();
+ }
private void AddColorMapTag()
{
diff --git a/src/ImageSharp/ImageSharp.csproj b/src/ImageSharp/ImageSharp.csproj
index 510f34dc7d..7719b12420 100644
--- a/src/ImageSharp/ImageSharp.csproj
+++ b/src/ImageSharp/ImageSharp.csproj
@@ -12,7 +12,7 @@
$(RepositoryUrl)
Image Resize Crop Gif Jpg Jpeg Bitmap Png Tga NetCore
A new, fully featured, fully managed, cross-platform, 2D graphics API for .NET
- Debug;Release;Release-InnerLoop;Debug-InnerLoop
+ Debug;Release;Debug-InnerLoop;Release-InnerLoop
diff --git a/tests/Directory.Build.targets b/tests/Directory.Build.targets
index af86f49b09..9c17881452 100644
--- a/tests/Directory.Build.targets
+++ b/tests/Directory.Build.targets
@@ -22,8 +22,8 @@
-
-
+
+
diff --git a/tests/ImageSharp.Benchmarks/Codecs/EncodeTiff.cs b/tests/ImageSharp.Benchmarks/Codecs/EncodeTiff.cs
index 39055faf50..025412adcd 100644
--- a/tests/ImageSharp.Benchmarks/Codecs/EncodeTiff.cs
+++ b/tests/ImageSharp.Benchmarks/Codecs/EncodeTiff.cs
@@ -61,7 +61,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs
ImageCodecInfo codec = FindCodecForType("image/tiff");
using var parameters = new EncoderParameters(1)
{
- Param = {[0] = new EncoderParameter(Encoder.Compression, (long)Cast(this.Compression))}
+ Param = { [0] = new EncoderParameter(Encoder.Compression, (long)Cast(this.Compression)) }
};
using var memoryStream = new MemoryStream();
diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/EncodeJpeg.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/EncodeJpeg.cs
index 47c6f2c7d4..d472791e43 100644
--- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/EncodeJpeg.cs
+++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/EncodeJpeg.cs
@@ -47,8 +47,11 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg
this.bmpDrawing = SDImage.FromStream(this.bmpStream);
this.jpegCodec = GetEncoder(ImageFormat.Jpeg);
this.encoderParameters = new EncoderParameters(1);
+
// Quality cast to long is necessary
+#pragma warning disable IDE0004 // Remove Unnecessary Cast
this.encoderParameters.Param[0] = new EncoderParameter(Encoder.Quality, (long)this.Quality);
+#pragma warning restore IDE0004 // Remove Unnecessary Cast
this.destinationStream = new MemoryStream();
}
@@ -101,6 +104,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg
return codec;
}
}
+
return null;
}
}
diff --git a/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj b/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj
index a146dc03ee..17f6068d40 100644
--- a/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj
+++ b/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj
@@ -8,7 +8,7 @@
false
false
- Debug;Release;Release-InnerLoop;Debug-InnerLoop
+ Debug;Release;Debug-InnerLoop;Release-InnerLoop
diff --git a/tests/ImageSharp.Tests.ProfilingSandbox/ImageSharp.Tests.ProfilingSandbox.csproj b/tests/ImageSharp.Tests.ProfilingSandbox/ImageSharp.Tests.ProfilingSandbox.csproj
index fe3b16450c..a60ac604f1 100644
--- a/tests/ImageSharp.Tests.ProfilingSandbox/ImageSharp.Tests.ProfilingSandbox.csproj
+++ b/tests/ImageSharp.Tests.ProfilingSandbox/ImageSharp.Tests.ProfilingSandbox.csproj
@@ -12,7 +12,7 @@
false
false
- Debug;Release;Release-InnerLoop;Debug-InnerLoop
+ Debug;Release;Debug-InnerLoop;Release-InnerLoop
false
diff --git a/tests/ImageSharp.Tests/Common/NumericsTests.cs b/tests/ImageSharp.Tests/Common/NumericsTests.cs
new file mode 100644
index 0000000000..29eae6d488
--- /dev/null
+++ b/tests/ImageSharp.Tests/Common/NumericsTests.cs
@@ -0,0 +1,73 @@
+// Copyright (c) Six Labors.
+// Licensed under the Apache License, Version 2.0.
+
+using System;
+using Xunit;
+using Xunit.Abstractions;
+
+namespace SixLabors.ImageSharp.Tests.Common
+{
+ public class NumericsTests
+ {
+ private ITestOutputHelper Output { get; }
+
+ public NumericsTests(ITestOutputHelper output)
+ {
+ this.Output = output;
+ }
+
+ private static int Log2_ReferenceImplementation(uint value)
+ {
+ int n = 0;
+ while ((value >>= 1) != 0)
+ {
+ ++n;
+ }
+
+ return n;
+ }
+
+ [Fact]
+ public void Log2_ZeroConvention()
+ {
+ uint value = 0;
+ int expected = 0;
+ int actual = Numerics.Log2(value);
+
+ Assert.True(expected == actual, $"Expected: {expected}, Actual: {actual}");
+ }
+
+ [Fact]
+ public void Log2_PowersOfTwo()
+ {
+ for (int i = 0; i < sizeof(int) * 8; i++)
+ {
+ // from 2^0 to 2^32
+ uint value = (uint)(1 << i);
+ int expected = i;
+ int actual = Numerics.Log2(value);
+
+ Assert.True(expected == actual, $"Expected: {expected}, Actual: {actual}");
+ }
+ }
+
+ [Theory]
+ [InlineData(1, 100)]
+ [InlineData(2, 100)]
+ public void Log2_RandomValues(int seed, int count)
+ {
+ var rng = new Random(seed);
+ byte[] bytes = new byte[4];
+
+ for (int i = 0; i < count; i++)
+ {
+ rng.NextBytes(bytes);
+ uint value = BitConverter.ToUInt32(bytes, 0);
+ int expected = Log2_ReferenceImplementation(value);
+ int actual = Numerics.Log2(value);
+
+ Assert.True(expected == actual, $"Expected: {expected}, Actual: {actual}");
+ }
+ }
+ }
+}
diff --git a/tests/ImageSharp.Tests/Formats/Tiff/PhotometricInterpretation/BlackIsZeroTiffColorTests.cs b/tests/ImageSharp.Tests/Formats/Tiff/PhotometricInterpretation/BlackIsZeroTiffColorTests.cs
index 579ee02901..769ab850e4 100644
--- a/tests/ImageSharp.Tests/Formats/Tiff/PhotometricInterpretation/BlackIsZeroTiffColorTests.cs
+++ b/tests/ImageSharp.Tests/Formats/Tiff/PhotometricInterpretation/BlackIsZeroTiffColorTests.cs
@@ -2,7 +2,7 @@
// Licensed under the Apache License, Version 2.0.
using System.Collections.Generic;
-
+using SixLabors.ImageSharp.Formats.Tiff;
using SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation;
using SixLabors.ImageSharp.PixelFormats;
@@ -154,11 +154,11 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff.PhotometricInterpretation
[MemberData(nameof(BilevelData))]
[MemberData(nameof(Grayscale4_Data))]
[MemberData(nameof(Grayscale8_Data))]
- public void Decode_WritesPixelData(byte[] inputData, int bitsPerSample, int left, int top, int width, int height, Rgba32[][] expectedResult)
+ public void Decode_WritesPixelData(byte[] inputData, ushort bitsPerSample, int left, int top, int width, int height, Rgba32[][] expectedResult)
{
AssertDecode(expectedResult, pixels =>
{
- new BlackIsZeroTiffColor(new[] { (ushort)bitsPerSample }).Decode(inputData, pixels, left, top, width, height);
+ new BlackIsZeroTiffColor(new TiffBitsPerSample(bitsPerSample, 0, 0)).Decode(inputData, pixels, left, top, width, height);
});
}
diff --git a/tests/ImageSharp.Tests/Formats/Tiff/PhotometricInterpretation/PaletteTiffColorTests.cs b/tests/ImageSharp.Tests/Formats/Tiff/PhotometricInterpretation/PaletteTiffColorTests.cs
index 0da1d8bbd4..e368cd5f1e 100644
--- a/tests/ImageSharp.Tests/Formats/Tiff/PhotometricInterpretation/PaletteTiffColorTests.cs
+++ b/tests/ImageSharp.Tests/Formats/Tiff/PhotometricInterpretation/PaletteTiffColorTests.cs
@@ -2,7 +2,7 @@
// Licensed under the Apache License, Version 2.0.
using System.Collections.Generic;
-
+using SixLabors.ImageSharp.Formats.Tiff;
using SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation;
using SixLabors.ImageSharp.PixelFormats;
@@ -83,10 +83,11 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff.PhotometricInterpretation
[Theory]
[MemberData(nameof(Palette4Data))]
[MemberData(nameof(Palette8Data))]
- public void Decode_WritesPixelData(byte[] inputData, ushort bitsPerSample, ushort[] colorMap, int left, int top, int width, int height, Rgba32[][] expectedResult) => AssertDecode(expectedResult, pixels =>
- {
- new PaletteTiffColor(new[] { bitsPerSample }, colorMap).Decode(inputData, pixels, left, top, width, height);
- });
+ public void Decode_WritesPixelData(byte[] inputData, ushort bitsPerSample, ushort[] colorMap, int left, int top, int width, int height, Rgba32[][] expectedResult)
+ => AssertDecode(expectedResult, pixels =>
+ {
+ new PaletteTiffColor(new TiffBitsPerSample(bitsPerSample, 0, 0), colorMap).Decode(inputData, pixels, left, top, width, height);
+ });
private static uint[][] GeneratePalette(int count)
{
diff --git a/tests/ImageSharp.Tests/Formats/Tiff/PhotometricInterpretation/RgbPlanarTiffColorTests.cs b/tests/ImageSharp.Tests/Formats/Tiff/PhotometricInterpretation/RgbPlanarTiffColorTests.cs
index abfae6ab40..e9c73a6683 100644
--- a/tests/ImageSharp.Tests/Formats/Tiff/PhotometricInterpretation/RgbPlanarTiffColorTests.cs
+++ b/tests/ImageSharp.Tests/Formats/Tiff/PhotometricInterpretation/RgbPlanarTiffColorTests.cs
@@ -3,7 +3,7 @@
using System;
using System.Collections.Generic;
-
+using SixLabors.ImageSharp.Formats.Tiff;
using SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
@@ -101,17 +101,17 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff.PhotometricInterpretation
{
get
{
- yield return new object[] { Rgb4Bytes4X4, new ushort[] { 4, 4, 4 }, 0, 0, 4, 4, Rgb4Result4X4 };
- yield return new object[] { Rgb4Bytes4X4, new ushort[] { 4, 4, 4 }, 0, 0, 4, 4, Offset(Rgb4Result4X4, 0, 0, 6, 6) };
- yield return new object[] { Rgb4Bytes4X4, new ushort[] { 4, 4, 4 }, 1, 0, 4, 4, Offset(Rgb4Result4X4, 1, 0, 6, 6) };
- yield return new object[] { Rgb4Bytes4X4, new ushort[] { 4, 4, 4 }, 0, 1, 4, 4, Offset(Rgb4Result4X4, 0, 1, 6, 6) };
- yield return new object[] { Rgb4Bytes4X4, new ushort[] { 4, 4, 4 }, 1, 1, 4, 4, Offset(Rgb4Result4X4, 1, 1, 6, 6) };
-
- yield return new object[] { Rgb4Bytes3X4, new ushort[] { 4, 4, 4 }, 0, 0, 3, 4, Rgb4Result3X4 };
- yield return new object[] { Rgb4Bytes3X4, new ushort[] { 4, 4, 4 }, 0, 0, 3, 4, Offset(Rgb4Result3X4, 0, 0, 6, 6) };
- yield return new object[] { Rgb4Bytes3X4, new ushort[] { 4, 4, 4 }, 1, 0, 3, 4, Offset(Rgb4Result3X4, 1, 0, 6, 6) };
- yield return new object[] { Rgb4Bytes3X4, new ushort[] { 4, 4, 4 }, 0, 1, 3, 4, Offset(Rgb4Result3X4, 0, 1, 6, 6) };
- yield return new object[] { Rgb4Bytes3X4, new ushort[] { 4, 4, 4 }, 1, 1, 3, 4, Offset(Rgb4Result3X4, 1, 1, 6, 6) };
+ yield return new object[] { Rgb4Bytes4X4, new TiffBitsPerSample(4, 4, 4), 0, 0, 4, 4, Rgb4Result4X4 };
+ yield return new object[] { Rgb4Bytes4X4, new TiffBitsPerSample(4, 4, 4), 0, 0, 4, 4, Offset(Rgb4Result4X4, 0, 0, 6, 6) };
+ yield return new object[] { Rgb4Bytes4X4, new TiffBitsPerSample(4, 4, 4), 1, 0, 4, 4, Offset(Rgb4Result4X4, 1, 0, 6, 6) };
+ yield return new object[] { Rgb4Bytes4X4, new TiffBitsPerSample(4, 4, 4), 0, 1, 4, 4, Offset(Rgb4Result4X4, 0, 1, 6, 6) };
+ yield return new object[] { Rgb4Bytes4X4, new TiffBitsPerSample(4, 4, 4), 1, 1, 4, 4, Offset(Rgb4Result4X4, 1, 1, 6, 6) };
+
+ yield return new object[] { Rgb4Bytes3X4, new TiffBitsPerSample(4, 4, 4), 0, 0, 3, 4, Rgb4Result3X4 };
+ yield return new object[] { Rgb4Bytes3X4, new TiffBitsPerSample(4, 4, 4), 0, 0, 3, 4, Offset(Rgb4Result3X4, 0, 0, 6, 6) };
+ yield return new object[] { Rgb4Bytes3X4, new TiffBitsPerSample(4, 4, 4), 1, 0, 3, 4, Offset(Rgb4Result3X4, 1, 0, 6, 6) };
+ yield return new object[] { Rgb4Bytes3X4, new TiffBitsPerSample(4, 4, 4), 0, 1, 3, 4, Offset(Rgb4Result3X4, 0, 1, 6, 6) };
+ yield return new object[] { Rgb4Bytes3X4, new TiffBitsPerSample(4, 4, 4), 1, 1, 3, 4, Offset(Rgb4Result3X4, 1, 1, 6, 6) };
}
}
@@ -170,11 +170,11 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff.PhotometricInterpretation
{
get
{
- yield return new object[] { Rgb8Bytes4X4, new ushort[] { 8, 8, 8 }, 0, 0, 4, 4, Rgb8Result4X4 };
- yield return new object[] { Rgb8Bytes4X4, new ushort[] { 8, 8, 8 }, 0, 0, 4, 4, Offset(Rgb8Result4X4, 0, 0, 6, 6) };
- yield return new object[] { Rgb8Bytes4X4, new ushort[] { 8, 8, 8 }, 1, 0, 4, 4, Offset(Rgb8Result4X4, 1, 0, 6, 6) };
- yield return new object[] { Rgb8Bytes4X4, new ushort[] { 8, 8, 8 }, 0, 1, 4, 4, Offset(Rgb8Result4X4, 0, 1, 6, 6) };
- yield return new object[] { Rgb8Bytes4X4, new ushort[] { 8, 8, 8 }, 1, 1, 4, 4, Offset(Rgb8Result4X4, 1, 1, 6, 6) };
+ yield return new object[] { Rgb8Bytes4X4, new TiffBitsPerSample(8, 8, 8), 0, 0, 4, 4, Rgb8Result4X4 };
+ yield return new object[] { Rgb8Bytes4X4, new TiffBitsPerSample(8, 8, 8), 0, 0, 4, 4, Offset(Rgb8Result4X4, 0, 0, 6, 6) };
+ yield return new object[] { Rgb8Bytes4X4, new TiffBitsPerSample(8, 8, 8), 1, 0, 4, 4, Offset(Rgb8Result4X4, 1, 0, 6, 6) };
+ yield return new object[] { Rgb8Bytes4X4, new TiffBitsPerSample(8, 8, 8), 0, 1, 4, 4, Offset(Rgb8Result4X4, 0, 1, 6, 6) };
+ yield return new object[] { Rgb8Bytes4X4, new TiffBitsPerSample(8, 8, 8), 1, 1, 4, 4, Offset(Rgb8Result4X4, 1, 1, 6, 6) };
}
}
@@ -230,11 +230,11 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff.PhotometricInterpretation
{
get
{
- yield return new object[] { Rgb484Bytes4X4, new ushort[] { 4, 8, 4 }, 0, 0, 4, 4, Rgb484Result4X4 };
- yield return new object[] { Rgb484Bytes4X4, new ushort[] { 4, 8, 4 }, 0, 0, 4, 4, Offset(Rgb484Result4X4, 0, 0, 6, 6) };
- yield return new object[] { Rgb484Bytes4X4, new ushort[] { 4, 8, 4 }, 1, 0, 4, 4, Offset(Rgb484Result4X4, 1, 0, 6, 6) };
- yield return new object[] { Rgb484Bytes4X4, new ushort[] { 4, 8, 4 }, 0, 1, 4, 4, Offset(Rgb484Result4X4, 0, 1, 6, 6) };
- yield return new object[] { Rgb484Bytes4X4, new ushort[] { 4, 8, 4 }, 1, 1, 4, 4, Offset(Rgb484Result4X4, 1, 1, 6, 6) };
+ yield return new object[] { Rgb484Bytes4X4, new TiffBitsPerSample(4, 8, 4), 0, 0, 4, 4, Rgb484Result4X4 };
+ yield return new object[] { Rgb484Bytes4X4, new TiffBitsPerSample(4, 8, 4), 0, 0, 4, 4, Offset(Rgb484Result4X4, 0, 0, 6, 6) };
+ yield return new object[] { Rgb484Bytes4X4, new TiffBitsPerSample(4, 8, 4), 1, 0, 4, 4, Offset(Rgb484Result4X4, 1, 0, 6, 6) };
+ yield return new object[] { Rgb484Bytes4X4, new TiffBitsPerSample(4, 8, 4), 0, 1, 4, 4, Offset(Rgb484Result4X4, 0, 1, 6, 6) };
+ yield return new object[] { Rgb484Bytes4X4, new TiffBitsPerSample(4, 8, 4), 1, 1, 4, 4, Offset(Rgb484Result4X4, 1, 1, 6, 6) };
}
}
@@ -242,7 +242,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff.PhotometricInterpretation
[MemberData(nameof(Rgb4Data))]
[MemberData(nameof(Rgb8Data))]
[MemberData(nameof(Rgb484_Data))]
- public void Decode_WritesPixelData(byte[][] inputData, ushort[] bitsPerSample, int left, int top, int width, int height, Rgba32[][] expectedResult)
+ public void Decode_WritesPixelData(byte[][] inputData, TiffBitsPerSample bitsPerSample, int left, int top, int width, int height, Rgba32[][] expectedResult)
{
AssertDecode(expectedResult, pixels =>
{
diff --git a/tests/ImageSharp.Tests/Formats/Tiff/PhotometricInterpretation/RgbTiffColorTests.cs b/tests/ImageSharp.Tests/Formats/Tiff/PhotometricInterpretation/RgbTiffColorTests.cs
index 4abde8f17e..9adf59e484 100644
--- a/tests/ImageSharp.Tests/Formats/Tiff/PhotometricInterpretation/RgbTiffColorTests.cs
+++ b/tests/ImageSharp.Tests/Formats/Tiff/PhotometricInterpretation/RgbTiffColorTests.cs
@@ -2,7 +2,7 @@
// Licensed under the Apache License, Version 2.0.
using System.Collections.Generic;
-
+using SixLabors.ImageSharp.Formats.Tiff;
using SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation;
using SixLabors.ImageSharp.PixelFormats;
@@ -63,17 +63,17 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff.PhotometricInterpretation
{
get
{
- yield return new object[] { Rgb4Bytes4X4, new ushort[] { 4, 4, 4 }, 0, 0, 4, 4, Rgb4Result4X4 };
- yield return new object[] { Rgb4Bytes4X4, new ushort[] { 4, 4, 4 }, 0, 0, 4, 4, Offset(Rgb4Result4X4, 0, 0, 6, 6) };
- yield return new object[] { Rgb4Bytes4X4, new ushort[] { 4, 4, 4 }, 1, 0, 4, 4, Offset(Rgb4Result4X4, 1, 0, 6, 6) };
- yield return new object[] { Rgb4Bytes4X4, new ushort[] { 4, 4, 4 }, 0, 1, 4, 4, Offset(Rgb4Result4X4, 0, 1, 6, 6) };
- yield return new object[] { Rgb4Bytes4X4, new ushort[] { 4, 4, 4 }, 1, 1, 4, 4, Offset(Rgb4Result4X4, 1, 1, 6, 6) };
-
- yield return new object[] { Rgb4Bytes3X4, new ushort[] { 4, 4, 4 }, 0, 0, 3, 4, Rgb4Result3X4 };
- yield return new object[] { Rgb4Bytes3X4, new ushort[] { 4, 4, 4 }, 0, 0, 3, 4, Offset(Rgb4Result3X4, 0, 0, 6, 6) };
- yield return new object[] { Rgb4Bytes3X4, new ushort[] { 4, 4, 4 }, 1, 0, 3, 4, Offset(Rgb4Result3X4, 1, 0, 6, 6) };
- yield return new object[] { Rgb4Bytes3X4, new ushort[] { 4, 4, 4 }, 0, 1, 3, 4, Offset(Rgb4Result3X4, 0, 1, 6, 6) };
- yield return new object[] { Rgb4Bytes3X4, new ushort[] { 4, 4, 4 }, 1, 1, 3, 4, Offset(Rgb4Result3X4, 1, 1, 6, 6) };
+ yield return new object[] { Rgb4Bytes4X4, new TiffBitsPerSample(4, 4, 4), 0, 0, 4, 4, Rgb4Result4X4 };
+ yield return new object[] { Rgb4Bytes4X4, new TiffBitsPerSample(4, 4, 4), 0, 0, 4, 4, Offset(Rgb4Result4X4, 0, 0, 6, 6) };
+ yield return new object[] { Rgb4Bytes4X4, new TiffBitsPerSample(4, 4, 4), 1, 0, 4, 4, Offset(Rgb4Result4X4, 1, 0, 6, 6) };
+ yield return new object[] { Rgb4Bytes4X4, new TiffBitsPerSample(4, 4, 4), 0, 1, 4, 4, Offset(Rgb4Result4X4, 0, 1, 6, 6) };
+ yield return new object[] { Rgb4Bytes4X4, new TiffBitsPerSample(4, 4, 4), 1, 1, 4, 4, Offset(Rgb4Result4X4, 1, 1, 6, 6) };
+
+ yield return new object[] { Rgb4Bytes3X4, new TiffBitsPerSample(4, 4, 4), 0, 0, 3, 4, Rgb4Result3X4 };
+ yield return new object[] { Rgb4Bytes3X4, new TiffBitsPerSample(4, 4, 4), 0, 0, 3, 4, Offset(Rgb4Result3X4, 0, 0, 6, 6) };
+ yield return new object[] { Rgb4Bytes3X4, new TiffBitsPerSample(4, 4, 4), 1, 0, 3, 4, Offset(Rgb4Result3X4, 1, 0, 6, 6) };
+ yield return new object[] { Rgb4Bytes3X4, new TiffBitsPerSample(4, 4, 4), 0, 1, 3, 4, Offset(Rgb4Result3X4, 0, 1, 6, 6) };
+ yield return new object[] { Rgb4Bytes3X4, new TiffBitsPerSample(4, 4, 4), 1, 1, 3, 4, Offset(Rgb4Result3X4, 1, 1, 6, 6) };
}
}
@@ -111,11 +111,11 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff.PhotometricInterpretation
{
get
{
- yield return new object[] { Rgb8Bytes4X4, new ushort[] { 8, 8, 8 }, 0, 0, 4, 4, Rgb8Result4X4 };
- yield return new object[] { Rgb8Bytes4X4, new ushort[] { 8, 8, 8 }, 0, 0, 4, 4, Offset(Rgb8Result4X4, 0, 0, 6, 6) };
- yield return new object[] { Rgb8Bytes4X4, new ushort[] { 8, 8, 8 }, 1, 0, 4, 4, Offset(Rgb8Result4X4, 1, 0, 6, 6) };
- yield return new object[] { Rgb8Bytes4X4, new ushort[] { 8, 8, 8 }, 0, 1, 4, 4, Offset(Rgb8Result4X4, 0, 1, 6, 6) };
- yield return new object[] { Rgb8Bytes4X4, new ushort[] { 8, 8, 8 }, 1, 1, 4, 4, Offset(Rgb8Result4X4, 1, 1, 6, 6) };
+ yield return new object[] { Rgb8Bytes4X4, new TiffBitsPerSample(8, 8, 8), 0, 0, 4, 4, Rgb8Result4X4 };
+ yield return new object[] { Rgb8Bytes4X4, new TiffBitsPerSample(8, 8, 8), 0, 0, 4, 4, Offset(Rgb8Result4X4, 0, 0, 6, 6) };
+ yield return new object[] { Rgb8Bytes4X4, new TiffBitsPerSample(8, 8, 8), 1, 0, 4, 4, Offset(Rgb8Result4X4, 1, 0, 6, 6) };
+ yield return new object[] { Rgb8Bytes4X4, new TiffBitsPerSample(8, 8, 8), 0, 1, 4, 4, Offset(Rgb8Result4X4, 0, 1, 6, 6) };
+ yield return new object[] { Rgb8Bytes4X4, new TiffBitsPerSample(8, 8, 8), 1, 1, 4, 4, Offset(Rgb8Result4X4, 1, 1, 6, 6) };
}
}
@@ -153,11 +153,11 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff.PhotometricInterpretation
{
get
{
- yield return new object[] { Rgb484Bytes4X4, new ushort[] { 4, 8, 4 }, 0, 0, 4, 4, Rgb484Result4X4 };
- yield return new object[] { Rgb484Bytes4X4, new ushort[] { 4, 8, 4 }, 0, 0, 4, 4, Offset(Rgb484Result4X4, 0, 0, 6, 6) };
- yield return new object[] { Rgb484Bytes4X4, new ushort[] { 4, 8, 4 }, 1, 0, 4, 4, Offset(Rgb484Result4X4, 1, 0, 6, 6) };
- yield return new object[] { Rgb484Bytes4X4, new ushort[] { 4, 8, 4 }, 0, 1, 4, 4, Offset(Rgb484Result4X4, 0, 1, 6, 6) };
- yield return new object[] { Rgb484Bytes4X4, new ushort[] { 4, 8, 4 }, 1, 1, 4, 4, Offset(Rgb484Result4X4, 1, 1, 6, 6) };
+ yield return new object[] { Rgb484Bytes4X4, new TiffBitsPerSample(4, 8, 4), 0, 0, 4, 4, Rgb484Result4X4 };
+ yield return new object[] { Rgb484Bytes4X4, new TiffBitsPerSample(4, 8, 4), 0, 0, 4, 4, Offset(Rgb484Result4X4, 0, 0, 6, 6) };
+ yield return new object[] { Rgb484Bytes4X4, new TiffBitsPerSample(4, 8, 4), 1, 0, 4, 4, Offset(Rgb484Result4X4, 1, 0, 6, 6) };
+ yield return new object[] { Rgb484Bytes4X4, new TiffBitsPerSample(4, 8, 4), 0, 1, 4, 4, Offset(Rgb484Result4X4, 0, 1, 6, 6) };
+ yield return new object[] { Rgb484Bytes4X4, new TiffBitsPerSample(4, 8, 4), 1, 1, 4, 4, Offset(Rgb484Result4X4, 1, 1, 6, 6) };
}
}
@@ -165,7 +165,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff.PhotometricInterpretation
[MemberData(nameof(Rgb4Data))]
[MemberData(nameof(Rgb8Data))]
[MemberData(nameof(Rgb484Data))]
- public void Decode_WritesPixelData(byte[] inputData, ushort[] bitsPerSample, int left, int top, int width, int height, Rgba32[][] expectedResult)
+ public void Decode_WritesPixelData(byte[] inputData, TiffBitsPerSample bitsPerSample, int left, int top, int width, int height, Rgba32[][] expectedResult)
{
AssertDecode(expectedResult, pixels =>
{
@@ -175,7 +175,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff.PhotometricInterpretation
[Theory]
[MemberData(nameof(Rgb8Data))]
- public void Decode_WritesPixelData_8Bit(byte[] inputData, ushort[] bitsPerSample, int left, int top, int width, int height, Rgba32[][] expectedResult)
+ public void Decode_WritesPixelData_8Bit(byte[] inputData, TiffBitsPerSample bitsPerSample, int left, int top, int width, int height, Rgba32[][] expectedResult)
{
AssertDecode(expectedResult, pixels =>
{
diff --git a/tests/ImageSharp.Tests/Formats/Tiff/PhotometricInterpretation/WhiteIsZeroTiffColorTests.cs b/tests/ImageSharp.Tests/Formats/Tiff/PhotometricInterpretation/WhiteIsZeroTiffColorTests.cs
index 620fddd7d0..1d3304e4c8 100644
--- a/tests/ImageSharp.Tests/Formats/Tiff/PhotometricInterpretation/WhiteIsZeroTiffColorTests.cs
+++ b/tests/ImageSharp.Tests/Formats/Tiff/PhotometricInterpretation/WhiteIsZeroTiffColorTests.cs
@@ -2,7 +2,7 @@
// Licensed under the Apache License, Version 2.0.
using System.Collections.Generic;
-
+using SixLabors.ImageSharp.Formats.Tiff;
using SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation;
using SixLabors.ImageSharp.PixelFormats;
@@ -154,11 +154,11 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff.PhotometricInterpretation
[MemberData(nameof(BilevelData))]
[MemberData(nameof(Grayscale4Data))]
[MemberData(nameof(Grayscale8Data))]
- public void Decode_WritesPixelData(byte[] inputData, int bitsPerSample, int left, int top, int width, int height, Rgba32[][] expectedResult)
+ public void Decode_WritesPixelData(byte[] inputData, ushort bitsPerSample, int left, int top, int width, int height, Rgba32[][] expectedResult)
{
AssertDecode(expectedResult, pixels =>
{
- new WhiteIsZeroTiffColor(new[] { (ushort)bitsPerSample }).Decode(inputData, pixels, left, top, width, height);
+ new WhiteIsZeroTiffColor(new TiffBitsPerSample(bitsPerSample, 0, 0)).Decode(inputData, pixels, left, top, width, height);
});
}
diff --git a/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs
index 02b7f97d94..6b82f4281c 100644
--- a/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs
+++ b/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs
@@ -99,30 +99,73 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff
public void TiffDecoder_CanDecode_4Bit_WithPalette(TestImageProvider provider)
where TPixel : unmanaged, IPixel => TestTiffDecoder(provider, ReferenceDecoder, useExactComparer: false, 0.01f);
+ [Theory]
+ [WithFile(Flower2BitPalette, PixelTypes.Rgba32)]
+ public void TiffDecoder_CanDecode_2Bit_WithPalette(TestImageProvider provider)
+ where TPixel : unmanaged, IPixel => TestTiffDecoder(provider, ReferenceDecoder, useExactComparer: false, 0.01f);
+
+ [Theory]
+ [WithFile(Flower2BitGray, PixelTypes.Rgba32)]
+ public void TiffDecoder_CanDecode_2Bit(TestImageProvider provider)
+ where TPixel : unmanaged, IPixel => TestTiffDecoder(provider);
+
[Theory]
[WithFile(FlowerRgb222Contiguous, PixelTypes.Rgba32)]
[WithFile(FlowerRgb222Planar, PixelTypes.Rgba32)]
+ [WithFile(Flower6BitGray, PixelTypes.Rgba32)]
public void TiffDecoder_CanDecode_6Bit(TestImageProvider provider)
where TPixel : unmanaged, IPixel => TestTiffDecoder(provider);
+ [Theory]
+ [WithFile(Flower8BitGray, PixelTypes.Rgba32)]
+ public void TiffDecoder_CanDecode_8Bit(TestImageProvider provider)
+ where TPixel : unmanaged, IPixel => TestTiffDecoder(provider);
+
+ [Theory]
+ [WithFile(Flower10BitGray, PixelTypes.Rgba32)]
+ public void TiffDecoder_CanDecode_10Bit(TestImageProvider provider)
+ where TPixel : unmanaged, IPixel => TestTiffDecoder(provider);
+
[Theory]
[WithFile(FlowerRgb444Contiguous, PixelTypes.Rgba32)]
[WithFile(FlowerRgb444Planar, PixelTypes.Rgba32)]
+ [WithFile(Flower12BitGray, PixelTypes.Rgba32)]
public void TiffDecoder_CanDecode_12Bit(TestImageProvider provider)
where TPixel : unmanaged, IPixel => TestTiffDecoder(provider);
+ [Theory]
+ [WithFile(Flower14BitGray, PixelTypes.Rgba32)]
+ public void TiffDecoder_CanDecode_14Bit(TestImageProvider provider)
+ where TPixel : unmanaged, IPixel => TestTiffDecoder(provider);
+
+ [Theory]
+ [WithFile(Flower16BitGray, PixelTypes.Rgba32)]
+ public void TiffDecoder_CanDecode_16Bit(TestImageProvider provider)
+ where TPixel : unmanaged, IPixel => TestTiffDecoder(provider);
+
[Theory]
[WithFile(FlowerRgb101010Contiguous, PixelTypes.Rgba32)]
[WithFile(FlowerRgb101010Planar, PixelTypes.Rgba32)]
public void TiffDecoder_CanDecode_30Bit(TestImageProvider provider)
where TPixel : unmanaged, IPixel => TestTiffDecoder(provider);
+ [Theory]
+ [WithFile(FlowerRgb121212Contiguous, PixelTypes.Rgba32)]
+ public void TiffDecoder_CanDecode_36Bit(TestImageProvider provider)
+ where TPixel : unmanaged, IPixel => TestTiffDecoder(provider);
+
[Theory]
[WithFile(FlowerRgb141414Contiguous, PixelTypes.Rgba32)]
[WithFile(FlowerRgb141414Planar, PixelTypes.Rgba32)]
public void TiffDecoder_CanDecode_42Bit(TestImageProvider provider)
where TPixel : unmanaged, IPixel => TestTiffDecoder(provider);
+ [Theory]
+ [WithFile(FlowerRgb161616Contiguous, PixelTypes.Rgba32)]
+ [WithFile(FlowerRgb161616Planar, PixelTypes.Rgba32)]
+ public void TiffDecoder_CanDecode_48Bit(TestImageProvider provider)
+ where TPixel : unmanaged, IPixel => TestTiffDecoder(provider);
+
[Theory]
[WithFile(GrayscaleDeflateMultistrip, PixelTypes.Rgba32)]
[WithFile(RgbDeflateMultistrip, PixelTypes.Rgba32)]
diff --git a/tests/ImageSharp.Tests/Formats/Tiff/TiffEncoderTests.cs b/tests/ImageSharp.Tests/Formats/Tiff/TiffEncoderTests.cs
index f2f1470f94..0bb9b95b9a 100644
--- a/tests/ImageSharp.Tests/Formats/Tiff/TiffEncoderTests.cs
+++ b/tests/ImageSharp.Tests/Formats/Tiff/TiffEncoderTests.cs
@@ -78,9 +78,12 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff
}
[Theory]
+ [InlineData(TiffBitsPerPixel.Bit48)]
[InlineData(TiffBitsPerPixel.Bit42)]
+ [InlineData(TiffBitsPerPixel.Bit36)]
[InlineData(TiffBitsPerPixel.Bit30)]
[InlineData(TiffBitsPerPixel.Bit12)]
+ [InlineData(TiffBitsPerPixel.Bit10)]
[InlineData(TiffBitsPerPixel.Bit6)]
public void EncoderOptions_UnsupportedBitPerPixel_DefaultTo24Bits(TiffBitsPerPixel bitsPerPixel)
{
diff --git a/tests/ImageSharp.Tests/Formats/Tiff/TiffMetadataTests.cs b/tests/ImageSharp.Tests/Formats/Tiff/TiffMetadataTests.cs
index ab350f720e..c80d9fc165 100644
--- a/tests/ImageSharp.Tests/Formats/Tiff/TiffMetadataTests.cs
+++ b/tests/ImageSharp.Tests/Formats/Tiff/TiffMetadataTests.cs
@@ -66,7 +66,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff
{
Assert.NotNull(frameMetaData);
Assert.NotNull(frameMetaData.BitsPerPixel);
- Assert.Equal(TiffBitsPerSample.Bit4, (TiffBitsPerSample)frameMetaData.BitsPerPixel);
+ Assert.Equal(TiffBitsPerPixel.Bit4, frameMetaData.BitsPerPixel);
Assert.Equal(TiffCompression.Lzw, frameMetaData.Compression);
Assert.Equal(TiffPhotometricInterpretation.PaletteColor, frameMetaData.PhotometricInterpretation);
Assert.Equal(TiffPredictor.None, frameMetaData.Predictor);
diff --git a/tests/ImageSharp.Tests/ImageSharp.Tests.csproj b/tests/ImageSharp.Tests/ImageSharp.Tests.csproj
index b6482455e0..b8d44d0d1e 100644
--- a/tests/ImageSharp.Tests/ImageSharp.Tests.csproj
+++ b/tests/ImageSharp.Tests/ImageSharp.Tests.csproj
@@ -6,7 +6,7 @@
SixLabors.ImageSharp.Tests
AnyCPU;x64;x86
SixLabors.ImageSharp.Tests
- Debug;Release;Release-InnerLoop;Debug-InnerLoop
+ Debug;Release;Debug-InnerLoop;Release-InnerLoop
diff --git a/tests/ImageSharp.Tests/Processing/Processors/Convolution/BokehBlurTest.cs b/tests/ImageSharp.Tests/Processing/Processors/Convolution/BokehBlurTest.cs
index 2351cbb917..4ab053a310 100644
--- a/tests/ImageSharp.Tests/Processing/Processors/Convolution/BokehBlurTest.cs
+++ b/tests/ImageSharp.Tests/Processing/Processors/Convolution/BokehBlurTest.cs
@@ -11,6 +11,7 @@ using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing;
using SixLabors.ImageSharp.Processing.Processors.Convolution;
using SixLabors.ImageSharp.Tests.TestUtilities;
+using SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison;
using Xunit;
using Xunit.Abstractions;
@@ -154,8 +155,9 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Convolution
appendSourceFileOrDescription: false);
[Theory]
- [WithFileCollection(nameof(TestFiles), nameof(BokehBlurValues), PixelTypes.Rgba32)]
- public void BokehBlurFilterProcessor_Bounded(TestImageProvider provider, BokehBlurInfo value)
+ [WithFileCollection(nameof(TestFiles), nameof(BokehBlurValues), PixelTypes.Rgba32, HwIntrinsics.AllowAll)]
+ [WithFileCollection(nameof(TestFiles), nameof(BokehBlurValues), PixelTypes.Rgba32, HwIntrinsics.DisableSSE41)]
+ public void BokehBlurFilterProcessor_Bounded(TestImageProvider provider, BokehBlurInfo value, HwIntrinsics intrinsicsFilter)
{
static void RunTest(string arg1, string arg2)
{
@@ -173,12 +175,13 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Convolution
x.BokehBlur(value.Radius, value.Components, value.Gamma, bounds);
},
testOutputDetails: value.ToString(),
+ ImageComparer.TolerantPercentage(0.05f),
appendPixelTypeToFileName: false);
}
FeatureTestRunner.RunWithHwIntrinsicsFeature(
RunTest,
- HwIntrinsics.DisableSSE41,
+ intrinsicsFilter,
provider,
value);
}
diff --git a/tests/ImageSharp.Tests/TestImages.cs b/tests/ImageSharp.Tests/TestImages.cs
index 9471a63937..7eca4795df 100644
--- a/tests/ImageSharp.Tests/TestImages.cs
+++ b/tests/ImageSharp.Tests/TestImages.cs
@@ -558,16 +558,27 @@ namespace SixLabors.ImageSharp.Tests
public const string RgbPalette = "Tiff/rgb_palette.tiff";
public const string Rgb4BitPalette = "Tiff/bike_colorpalette_4bit.tiff";
public const string RgbPaletteDeflate = "Tiff/rgb_palette_deflate.tiff";
- public const string Flower4BitPalette = "Tiff/flower-palette-04.tiff";
- public const string Flower4BitPaletteGray = "Tiff/flower-minisblack-04.tiff";
+ public const string FlowerRgb161616Contiguous = "Tiff/flower-rgb-contig-16.tiff";
+ public const string FlowerRgb161616Planar = "Tiff/flower-rgb-planar-16.tiff";
public const string FlowerRgb141414Contiguous = "Tiff/flower-rgb-contig-14.tiff";
public const string FlowerRgb141414Planar = "Tiff/flower-rgb-planar-14.tiff";
public const string FlowerRgb101010Contiguous = "Tiff/flower-rgb-contig-10.tiff";
public const string FlowerRgb101010Planar = "Tiff/flower-rgb-planar-10.tiff";
+ public const string FlowerRgb121212Contiguous = "Tiff/flower-rgb-contig-12.tiff";
public const string FlowerRgb444Contiguous = "Tiff/flower-rgb-contig-04.tiff";
public const string FlowerRgb444Planar = "Tiff/flower-rgb-planar-04.tiff";
public const string FlowerRgb222Contiguous = "Tiff/flower-rgb-contig-02.tiff";
public const string FlowerRgb222Planar = "Tiff/flower-rgb-planar-02.tiff";
+ public const string Flower2BitGray = "Tiff/flower-minisblack-02.tiff";
+ public const string Flower2BitPalette = "Tiff/flower-palette-02.tiff";
+ public const string Flower4BitPalette = "Tiff/flower-palette-04.tiff";
+ public const string Flower4BitPaletteGray = "Tiff/flower-minisblack-04.tiff";
+ public const string Flower6BitGray = "Tiff/flower-minisblack-06.tiff";
+ public const string Flower8BitGray = "Tiff/flower-minisblack-08.tiff";
+ public const string Flower10BitGray = "Tiff/flower-minisblack-10.tiff";
+ public const string Flower12BitGray = "Tiff/flower-minisblack-12.tiff";
+ public const string Flower14BitGray = "Tiff/flower-minisblack-14.tiff";
+ public const string Flower16BitGray = "Tiff/flower-minisblack-16.tiff";
public const string SmallRgbDeflate = "Tiff/rgb_small_deflate.tiff";
public const string SmallRgbLzw = "Tiff/rgb_small_lzw.tiff";
diff --git a/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/MagickReferenceDecoder.cs b/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/MagickReferenceDecoder.cs
index dffbeac497..294bd20fb5 100644
--- a/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/MagickReferenceDecoder.cs
+++ b/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/MagickReferenceDecoder.cs
@@ -84,7 +84,7 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ReferenceCodecs
MemoryGroup framePixels = frame.PixelBuffer.FastMemoryGroup;
using IUnsafePixelCollection pixels = magicFrame.GetPixelsUnsafe();
- if (magicFrame.Depth == 8 || magicFrame.Depth == 4 || magicFrame.Depth == 2 || magicFrame.Depth == 1 || magicFrame.Depth == 10)
+ if (magicFrame.Depth == 8 || magicFrame.Depth == 6 || magicFrame.Depth == 4 || magicFrame.Depth == 2 || magicFrame.Depth == 1 || magicFrame.Depth == 10 || magicFrame.Depth == 12)
{
byte[] data = pixels.ToByteArray(PixelMapping.RGBA);
diff --git a/tests/ImageSharp.Tests/TestUtilities/Tests/TestEnvironmentTests.cs b/tests/ImageSharp.Tests/TestUtilities/Tests/TestEnvironmentTests.cs
index 84b9297295..05f4f032bf 100644
--- a/tests/ImageSharp.Tests/TestUtilities/Tests/TestEnvironmentTests.cs
+++ b/tests/ImageSharp.Tests/TestUtilities/Tests/TestEnvironmentTests.cs
@@ -3,7 +3,7 @@
using System;
using System.IO;
-
+using Microsoft.DotNet.RemoteExecutor;
using SixLabors.ImageSharp.Formats;
using SixLabors.ImageSharp.Formats.Bmp;
using SixLabors.ImageSharp.Formats.Gif;
@@ -114,5 +114,20 @@ namespace SixLabors.ImageSharp.Tests
IImageDecoder decoder = TestEnvironment.GetReferenceDecoder(fileName);
Assert.IsType(expectedDecoderType, decoder);
}
+
+ // RemoteExecutor does not work with "dotnet xunit" used to run tests on 32 bit .NET Framework:
+ // https://github.com/SixLabors/ImageSharp/blob/381dff8640b721a34b1227c970fcf6ad6c5e3e72/ci-test.ps1#L30
+ public static bool IsNot32BitNetFramework = !TestEnvironment.IsFramework || TestEnvironment.Is64BitProcess;
+
+ [ConditionalFact(nameof(IsNot32BitNetFramework))]
+ public void RemoteExecutor_FailingRemoteTestShouldFailLocalTest()
+ {
+ static void FailingCode()
+ {
+ Assert.False(true);
+ }
+
+ Assert.ThrowsAny(() => RemoteExecutor.Invoke(FailingCode).Dispose());
+ }
}
}
diff --git a/tests/Images/Input/Tiff/flower-minisblack-02.tiff b/tests/Images/Input/Tiff/flower-minisblack-02.tiff
new file mode 100644
index 0000000000..d6ce305fe6
--- /dev/null
+++ b/tests/Images/Input/Tiff/flower-minisblack-02.tiff
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:3122afede012fa00b8cb379b2f9125a34a38188c3346ec5e18d3b4bddcbb451b
+size 1131
diff --git a/tests/Images/Input/Tiff/flower-minisblack-06.tiff b/tests/Images/Input/Tiff/flower-minisblack-06.tiff
new file mode 100644
index 0000000000..53db4e1126
--- /dev/null
+++ b/tests/Images/Input/Tiff/flower-minisblack-06.tiff
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:b0c13012d8d35215b01192eb38058db4543486c60b4918beec8719a94d1e208e
+size 2679
diff --git a/tests/Images/Input/Tiff/flower-minisblack-08.tiff b/tests/Images/Input/Tiff/flower-minisblack-08.tiff
new file mode 100644
index 0000000000..02acb15113
--- /dev/null
+++ b/tests/Images/Input/Tiff/flower-minisblack-08.tiff
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:1268d843a2338409ec3a9f5a5a62e23d38c3a898035619994a02f21eff7590bf
+size 3453
diff --git a/tests/Images/Input/Tiff/flower-minisblack-10.tiff b/tests/Images/Input/Tiff/flower-minisblack-10.tiff
new file mode 100644
index 0000000000..770197726f
--- /dev/null
+++ b/tests/Images/Input/Tiff/flower-minisblack-10.tiff
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:a91d6946730604dd65c63f1653fb33031682f26218de33ebf3d0b362cb6883af
+size 4269
diff --git a/tests/Images/Input/Tiff/flower-minisblack-12.tiff b/tests/Images/Input/Tiff/flower-minisblack-12.tiff
new file mode 100644
index 0000000000..320083c323
--- /dev/null
+++ b/tests/Images/Input/Tiff/flower-minisblack-12.tiff
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:86fc9309872f4e4668350b95fae315d878ec9658046d738050a2743f5fa44446
+size 5043
diff --git a/tests/Images/Input/Tiff/flower-minisblack-14.tiff b/tests/Images/Input/Tiff/flower-minisblack-14.tiff
new file mode 100644
index 0000000000..34fca95b56
--- /dev/null
+++ b/tests/Images/Input/Tiff/flower-minisblack-14.tiff
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:dcd07668c73f24c2a13133ac4910b59a568502a6d3762675eef61a7e3b090165
+size 5817
diff --git a/tests/Images/Input/Tiff/flower-minisblack-16.tiff b/tests/Images/Input/Tiff/flower-minisblack-16.tiff
new file mode 100644
index 0000000000..0791941f99
--- /dev/null
+++ b/tests/Images/Input/Tiff/flower-minisblack-16.tiff
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:79531a10710dee89b86e2467818b7c03a24ff28ebd98c7bdcc292559671e1887
+size 6591
diff --git a/tests/Images/Input/Tiff/flower-palette-02.tiff b/tests/Images/Input/Tiff/flower-palette-02.tiff
new file mode 100644
index 0000000000..eb80e4de85
--- /dev/null
+++ b/tests/Images/Input/Tiff/flower-palette-02.tiff
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:75e74d8816942ff6e9dfda411f9171f0f1dd1a5a88cb1410238b55a2b2aeeb71
+size 1164
diff --git a/tests/Images/Input/Tiff/flower-rgb-contig-12.tiff b/tests/Images/Input/Tiff/flower-rgb-contig-12.tiff
new file mode 100644
index 0000000000..c890c777a6
--- /dev/null
+++ b/tests/Images/Input/Tiff/flower-rgb-contig-12.tiff
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:5f7a63eb8636e2b1ee39dfda4d0bddfc98bdc9eb94bea2dd657619331fa38b5b
+size 14483
diff --git a/tests/Images/Input/Tiff/flower-rgb-contig-16.tiff b/tests/Images/Input/Tiff/flower-rgb-contig-16.tiff
new file mode 100644
index 0000000000..125de5b9fd
--- /dev/null
+++ b/tests/Images/Input/Tiff/flower-rgb-contig-16.tiff
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:ab3d6b619a198ff2e5fdd8f9752bf43c5b03a782625b1f0e3f2cfe0f20c4b24a
+size 19177
diff --git a/tests/Images/Input/Tiff/flower-rgb-planar-16.tiff b/tests/Images/Input/Tiff/flower-rgb-planar-16.tiff
new file mode 100644
index 0000000000..939fd9471b
--- /dev/null
+++ b/tests/Images/Input/Tiff/flower-rgb-planar-16.tiff
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:0a143fb6c5792fa7755e06feb757c745ad68944336985dc5be8a0c37247fe36d
+size 19177