diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba16161616TiffColor{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba16161616TiffColor{TPixel}.cs
new file mode 100644
index 0000000000..7fd8d9879b
--- /dev/null
+++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba16161616TiffColor{TPixel}.cs
@@ -0,0 +1,77 @@
+// Copyright (c) Six Labors.
+// Licensed under the Apache License, Version 2.0.
+
+using System;
+using SixLabors.ImageSharp.Formats.Tiff.Utils;
+using SixLabors.ImageSharp.Memory;
+using SixLabors.ImageSharp.PixelFormats;
+
+namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
+{
+ ///
+ /// Implements the 'RGB' photometric interpretation with an alpha channel and with 16 bits for each channel.
+ ///
+ internal class Rgba16161616TiffColor : TiffBaseColorDecoder
+ where TPixel : unmanaged, IPixel
+ {
+ private readonly bool isBigEndian;
+
+ private readonly Configuration configuration;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The configuration.
+ /// if set to true decodes the pixel data as big endian, otherwise as little endian.
+ public Rgba16161616TiffColor(Configuration configuration, bool isBigEndian)
+ {
+ this.configuration = configuration;
+ this.isBigEndian = isBigEndian;
+ }
+
+ ///
+ public override void Decode(ReadOnlySpan data, Buffer2D pixels, int left, int top, int width, int height)
+ {
+ // Note: due to an issue with netcore 2.1 and default values and unpredictable behavior with those,
+ // we define our own defaults as a workaround. See: https://github.com/dotnet/runtime/issues/55623
+ Rgba64 rgba = TiffUtils.Rgba64Default;
+ var color = default(TPixel);
+ color.FromVector4(TiffUtils.Vector4Default);
+
+ int offset = 0;
+
+ for (int y = top; y < top + height; y++)
+ {
+ Span pixelRow = pixels.DangerousGetRowSpan(y).Slice(left, width);
+
+ if (this.isBigEndian)
+ {
+ for (int x = 0; x < pixelRow.Length; x++)
+ {
+ ulong r = TiffUtils.ConvertToUShortBigEndian(data.Slice(offset, 2));
+ offset += 2;
+ ulong g = TiffUtils.ConvertToUShortBigEndian(data.Slice(offset, 2));
+ offset += 2;
+ ulong b = TiffUtils.ConvertToUShortBigEndian(data.Slice(offset, 2));
+ offset += 2;
+ ulong a = TiffUtils.ConvertToUShortBigEndian(data.Slice(offset, 2));
+ offset += 2;
+
+ pixelRow[x] = TiffUtils.ColorFromRgba64(rgba, r, g, b, a, color);
+ }
+ }
+ else
+ {
+ int byteCount = pixelRow.Length * 8;
+ PixelOperations.Instance.FromRgba64Bytes(
+ this.configuration,
+ data.Slice(offset, byteCount),
+ pixelRow,
+ pixelRow.Length);
+
+ offset += byteCount;
+ }
+ }
+ }
+ }
+}
diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba24242424TiffColor{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba24242424TiffColor{TPixel}.cs
new file mode 100644
index 0000000000..3d88d9fb5a
--- /dev/null
+++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba24242424TiffColor{TPixel}.cs
@@ -0,0 +1,90 @@
+// Copyright (c) Six Labors.
+// Licensed under the Apache License, Version 2.0.
+
+using System;
+using SixLabors.ImageSharp.Formats.Tiff.Utils;
+using SixLabors.ImageSharp.Memory;
+using SixLabors.ImageSharp.PixelFormats;
+
+namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
+{
+ ///
+ /// Implements the 'RGB' photometric interpretation with an alpha channel and with 24 bits for each channel.
+ ///
+ internal class Rgba24242424TiffColor : TiffBaseColorDecoder
+ where TPixel : unmanaged, IPixel
+ {
+ private readonly bool isBigEndian;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// if set to true decodes the pixel data as big endian, otherwise as little endian.
+ public Rgba24242424TiffColor(bool isBigEndian) => this.isBigEndian = isBigEndian;
+
+ ///
+ public override void Decode(ReadOnlySpan data, Buffer2D pixels, int left, int top, int width, int height)
+ {
+ // Note: due to an issue with netcore 2.1 and default values and unpredictable behavior with those,
+ // we define our own defaults as a workaround. See: https://github.com/dotnet/runtime/issues/55623
+ var color = default(TPixel);
+ color.FromVector4(TiffUtils.Vector4Default);
+ int offset = 0;
+ byte[] buffer = new byte[4];
+ int bufferStartIdx = this.isBigEndian ? 1 : 0;
+
+ Span bufferSpan = buffer.AsSpan(bufferStartIdx);
+ for (int y = top; y < top + height; y++)
+ {
+ Span pixelRow = pixels.DangerousGetRowSpan(y).Slice(left, width);
+
+ if (this.isBigEndian)
+ {
+ for (int x = 0; x < pixelRow.Length; x++)
+ {
+ data.Slice(offset, 3).CopyTo(bufferSpan);
+ ulong r = TiffUtils.ConvertToUIntBigEndian(buffer);
+ offset += 3;
+
+ data.Slice(offset, 3).CopyTo(bufferSpan);
+ ulong g = TiffUtils.ConvertToUIntBigEndian(buffer);
+ offset += 3;
+
+ data.Slice(offset, 3).CopyTo(bufferSpan);
+ ulong b = TiffUtils.ConvertToUIntBigEndian(buffer);
+ offset += 3;
+
+ data.Slice(offset, 3).CopyTo(bufferSpan);
+ ulong a = TiffUtils.ConvertToUIntBigEndian(buffer);
+ offset += 3;
+
+ pixelRow[x] = TiffUtils.ColorScaleTo32Bit(r, g, b, a, color);
+ }
+ }
+ else
+ {
+ for (int x = 0; x < pixelRow.Length; x++)
+ {
+ data.Slice(offset, 3).CopyTo(bufferSpan);
+ ulong r = TiffUtils.ConvertToUIntLittleEndian(buffer);
+ offset += 3;
+
+ data.Slice(offset, 3).CopyTo(bufferSpan);
+ ulong g = TiffUtils.ConvertToUIntLittleEndian(buffer);
+ offset += 3;
+
+ data.Slice(offset, 3).CopyTo(bufferSpan);
+ ulong b = TiffUtils.ConvertToUIntLittleEndian(buffer);
+ offset += 3;
+
+ data.Slice(offset, 3).CopyTo(bufferSpan);
+ ulong a = TiffUtils.ConvertToUIntLittleEndian(buffer);
+ offset += 3;
+
+ pixelRow[x] = TiffUtils.ColorScaleTo32Bit(r, g, b, a, color);
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba32323232TiffColor{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba32323232TiffColor{TPixel}.cs
new file mode 100644
index 0000000000..fbd18ca3e0
--- /dev/null
+++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba32323232TiffColor{TPixel}.cs
@@ -0,0 +1,79 @@
+// Copyright (c) Six Labors.
+// Licensed under the Apache License, Version 2.0.
+
+using System;
+using SixLabors.ImageSharp.Formats.Tiff.Utils;
+using SixLabors.ImageSharp.Memory;
+using SixLabors.ImageSharp.PixelFormats;
+
+namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
+{
+ ///
+ /// Implements the 'RGB' photometric interpretation with an alpha channel and with 32 bits for each channel.
+ ///
+ internal class Rgba32323232TiffColor : TiffBaseColorDecoder
+ where TPixel : unmanaged, IPixel
+ {
+ private readonly bool isBigEndian;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// if set to true decodes the pixel data as big endian, otherwise as little endian.
+ public Rgba32323232TiffColor(bool isBigEndian) => this.isBigEndian = isBigEndian;
+
+ ///
+ public override void Decode(ReadOnlySpan data, Buffer2D pixels, int left, int top, int width, int height)
+ {
+ // Note: due to an issue with netcore 2.1 and default values and unpredictable behavior with those,
+ // we define our own defaults as a workaround. See: https://github.com/dotnet/runtime/issues/55623
+ var color = default(TPixel);
+ color.FromVector4(TiffUtils.Vector4Default);
+ int offset = 0;
+
+ for (int y = top; y < top + height; y++)
+ {
+ Span pixelRow = pixels.DangerousGetRowSpan(y).Slice(left, width);
+
+ if (this.isBigEndian)
+ {
+ for (int x = 0; x < pixelRow.Length; x++)
+ {
+ ulong r = TiffUtils.ConvertToUIntBigEndian(data.Slice(offset, 4));
+ offset += 4;
+
+ ulong g = TiffUtils.ConvertToUIntBigEndian(data.Slice(offset, 4));
+ offset += 4;
+
+ ulong b = TiffUtils.ConvertToUIntBigEndian(data.Slice(offset, 4));
+ offset += 4;
+
+ ulong a = TiffUtils.ConvertToUIntBigEndian(data.Slice(offset, 4));
+ offset += 4;
+
+ pixelRow[x] = TiffUtils.ColorScaleTo32Bit(r, g, b, a, color);
+ }
+ }
+ else
+ {
+ for (int x = 0; x < pixelRow.Length; x++)
+ {
+ ulong r = TiffUtils.ConvertToUIntLittleEndian(data.Slice(offset, 4));
+ offset += 4;
+
+ ulong g = TiffUtils.ConvertToUIntLittleEndian(data.Slice(offset, 4));
+ offset += 4;
+
+ ulong b = TiffUtils.ConvertToUIntLittleEndian(data.Slice(offset, 4));
+ offset += 4;
+
+ ulong a = TiffUtils.ConvertToUIntLittleEndian(data.Slice(offset, 4));
+ offset += 4;
+
+ pixelRow[x] = TiffUtils.ColorScaleTo32Bit(r, g, b, a, color);
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba8888TiffColor{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba8888TiffColor{TPixel}.cs
new file mode 100644
index 0000000000..491a42fb75
--- /dev/null
+++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba8888TiffColor{TPixel}.cs
@@ -0,0 +1,39 @@
+// Copyright (c) Six Labors.
+// Licensed under the Apache License, Version 2.0.
+
+using System;
+using SixLabors.ImageSharp.Memory;
+using SixLabors.ImageSharp.PixelFormats;
+
+namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
+{
+ ///
+ /// Implements the 'RGB' photometric interpretation with an alpha channel and 8 bits per channel.
+ ///
+ internal class Rgba8888TiffColor : TiffBaseColorDecoder
+ where TPixel : unmanaged, IPixel
+ {
+ private readonly Configuration configuration;
+
+ public Rgba8888TiffColor(Configuration configuration) => this.configuration = configuration;
+
+ ///
+ public override void Decode(ReadOnlySpan data, Buffer2D pixels, int left, int top, int width, int height)
+ {
+ int offset = 0;
+
+ for (int y = top; y < top + height; y++)
+ {
+ Span pixelRow = pixels.DangerousGetRowSpan(y).Slice(left, width);
+ int byteCount = pixelRow.Length * 4;
+ PixelOperations.Instance.FromRgba32Bytes(
+ this.configuration,
+ data.Slice(offset, byteCount),
+ pixelRow,
+ pixelRow.Length);
+
+ offset += byteCount;
+ }
+ }
+ }
+}
diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/RgbaFloat32323232TiffColor{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/RgbaFloat32323232TiffColor{TPixel}.cs
new file mode 100644
index 0000000000..4fb0797dc5
--- /dev/null
+++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/RgbaFloat32323232TiffColor{TPixel}.cs
@@ -0,0 +1,97 @@
+// Copyright (c) Six Labors.
+// Licensed under the Apache License, Version 2.0.
+
+using System;
+using System.Numerics;
+using SixLabors.ImageSharp.Formats.Tiff.Utils;
+using SixLabors.ImageSharp.Memory;
+using SixLabors.ImageSharp.PixelFormats;
+
+namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
+{
+ ///
+ /// Implements the 'RGB' photometric interpretation with an alpha channel and with 32 bits for each channel.
+ ///
+ internal class RgbaFloat32323232TiffColor : TiffBaseColorDecoder
+ where TPixel : unmanaged, IPixel
+ {
+ private readonly bool isBigEndian;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// if set to true decodes the pixel data as big endian, otherwise as little endian.
+ public RgbaFloat32323232TiffColor(bool isBigEndian) => this.isBigEndian = isBigEndian;
+
+ ///
+ public override void Decode(ReadOnlySpan data, Buffer2D pixels, int left, int top, int width, int height)
+ {
+ // Note: due to an issue with netcore 2.1 and default values and unpredictable behavior with those,
+ // we define our own defaults as a workaround. See: https://github.com/dotnet/runtime/issues/55623
+ var color = default(TPixel);
+ color.FromVector4(TiffUtils.Vector4Default);
+ int offset = 0;
+ byte[] buffer = new byte[4];
+
+ for (int y = top; y < top + height; y++)
+ {
+ Span pixelRow = pixels.DangerousGetRowSpan(y).Slice(left, width);
+
+ if (this.isBigEndian)
+ {
+ for (int x = 0; x < pixelRow.Length; x++)
+ {
+ data.Slice(offset, 4).CopyTo(buffer);
+ Array.Reverse(buffer);
+ float r = BitConverter.ToSingle(buffer, 0);
+ offset += 4;
+
+ data.Slice(offset, 4).CopyTo(buffer);
+ Array.Reverse(buffer);
+ float g = BitConverter.ToSingle(buffer, 0);
+ offset += 4;
+
+ data.Slice(offset, 4).CopyTo(buffer);
+ Array.Reverse(buffer);
+ float b = BitConverter.ToSingle(buffer, 0);
+ offset += 4;
+
+ data.Slice(offset, 4).CopyTo(buffer);
+ Array.Reverse(buffer);
+ float a = BitConverter.ToSingle(buffer, 0);
+ offset += 4;
+
+ var colorVector = new Vector4(r, g, b, a);
+ color.FromVector4(colorVector);
+ pixelRow[x] = color;
+ }
+ }
+ else
+ {
+ for (int x = 0; x < pixelRow.Length; x++)
+ {
+ data.Slice(offset, 4).CopyTo(buffer);
+ float r = BitConverter.ToSingle(buffer, 0);
+ offset += 4;
+
+ data.Slice(offset, 4).CopyTo(buffer);
+ float g = BitConverter.ToSingle(buffer, 0);
+ offset += 4;
+
+ data.Slice(offset, 4).CopyTo(buffer);
+ float b = BitConverter.ToSingle(buffer, 0);
+ offset += 4;
+
+ data.Slice(offset, 4).CopyTo(buffer);
+ float a = BitConverter.ToSingle(buffer, 0);
+ offset += 4;
+
+ var colorVector = new Vector4(r, g, b, a);
+ color.FromVector4(colorVector);
+ pixelRow[x] = color;
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/RgbaTiffColor{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/RgbaTiffColor{TPixel}.cs
new file mode 100644
index 0000000000..8bec7da89d
--- /dev/null
+++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/RgbaTiffColor{TPixel}.cs
@@ -0,0 +1,72 @@
+// Copyright (c) Six Labors.
+// Licensed under the Apache License, Version 2.0.
+
+using System;
+using System.Numerics;
+using SixLabors.ImageSharp.Formats.Tiff.Utils;
+using SixLabors.ImageSharp.Memory;
+using SixLabors.ImageSharp.PixelFormats;
+
+namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
+{
+ ///
+ /// Implements the 'RGB' photometric interpretation with alpha channel (for all bit depths).
+ ///
+ internal class RgbaTiffColor : TiffBaseColorDecoder
+ where TPixel : unmanaged, IPixel
+ {
+ private readonly float rFactor;
+
+ private readonly float gFactor;
+
+ private readonly float bFactor;
+
+ private readonly float aFactor;
+
+ private readonly ushort bitsPerSampleR;
+
+ private readonly ushort bitsPerSampleG;
+
+ private readonly ushort bitsPerSampleB;
+
+ private readonly ushort bitsPerSampleA;
+
+ public RgbaTiffColor(TiffBitsPerSample bitsPerSample)
+ {
+ this.bitsPerSampleR = bitsPerSample.Channel0;
+ this.bitsPerSampleG = bitsPerSample.Channel1;
+ this.bitsPerSampleB = bitsPerSample.Channel2;
+ this.bitsPerSampleA = bitsPerSample.Channel3;
+
+ this.rFactor = (1 << this.bitsPerSampleR) - 1.0f;
+ this.gFactor = (1 << this.bitsPerSampleG) - 1.0f;
+ this.bFactor = (1 << this.bitsPerSampleB) - 1.0f;
+ this.aFactor = (1 << this.bitsPerSampleA) - 1.0f;
+ }
+
+ ///
+ public override void Decode(ReadOnlySpan data, Buffer2D pixels, int left, int top, int width, int height)
+ {
+ var color = default(TPixel);
+
+ var bitReader = new BitReader(data);
+
+ for (int y = top; y < top + height; y++)
+ {
+ Span pixelRow = pixels.DangerousGetRowSpan(y).Slice(left, width);
+ for (int x = 0; x < pixelRow.Length; x++)
+ {
+ float r = bitReader.ReadBits(this.bitsPerSampleR) / this.rFactor;
+ float g = bitReader.ReadBits(this.bitsPerSampleG) / this.gFactor;
+ float b = bitReader.ReadBits(this.bitsPerSampleB) / this.bFactor;
+ float a = bitReader.ReadBits(this.bitsPerSampleB) / this.aFactor;
+
+ color.FromVector4(new Vector4(r, g, b, a));
+ pixelRow[x] = color;
+ }
+
+ bitReader.NextRow();
+ }
+ }
+ }
+}
diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/TiffColorDecoderFactory{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/TiffColorDecoderFactory{TPixel}.cs
index a8c4cef4ed..25ca534315 100644
--- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/TiffColorDecoderFactory{TPixel}.cs
+++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/TiffColorDecoderFactory{TPixel}.cs
@@ -116,6 +116,38 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
DebugGuard.IsTrue(colorMap == null, "colorMap");
return new RgbTiffColor(bitsPerSample);
+ case TiffColorType.Rgba2222:
+ DebugGuard.IsTrue(
+ bitsPerSample.Channels == 4
+ && bitsPerSample.Channel3 == 2
+ && bitsPerSample.Channel2 == 2
+ && bitsPerSample.Channel1 == 2
+ && bitsPerSample.Channel0 == 2,
+ "bitsPerSample");
+ DebugGuard.IsTrue(colorMap == null, "colorMap");
+ return new RgbaTiffColor(bitsPerSample);
+
+ case TiffColorType.Rgb333:
+ DebugGuard.IsTrue(
+ bitsPerSample.Channels == 3
+ && bitsPerSample.Channel2 == 3
+ && bitsPerSample.Channel1 == 3
+ && bitsPerSample.Channel0 == 3,
+ "bitsPerSample");
+ DebugGuard.IsTrue(colorMap == null, "colorMap");
+ return new RgbTiffColor(bitsPerSample);
+
+ case TiffColorType.Rgba3333:
+ DebugGuard.IsTrue(
+ bitsPerSample.Channels == 4
+ && bitsPerSample.Channel3 == 3
+ && bitsPerSample.Channel2 == 3
+ && bitsPerSample.Channel1 == 3
+ && bitsPerSample.Channel0 == 3,
+ "bitsPerSample");
+ DebugGuard.IsTrue(colorMap == null, "colorMap");
+ return new RgbaTiffColor(bitsPerSample);
+
case TiffColorType.Rgb444:
DebugGuard.IsTrue(
bitsPerSample.Channels == 3
@@ -126,6 +158,59 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
DebugGuard.IsTrue(colorMap == null, "colorMap");
return new Rgb444TiffColor();
+ case TiffColorType.Rgba4444:
+ DebugGuard.IsTrue(
+ bitsPerSample.Channels == 4
+ && bitsPerSample.Channel3 == 4
+ && bitsPerSample.Channel2 == 4
+ && bitsPerSample.Channel1 == 4
+ && bitsPerSample.Channel0 == 4,
+ "bitsPerSample");
+ DebugGuard.IsTrue(colorMap == null, "colorMap");
+ return new RgbaTiffColor(bitsPerSample);
+
+ case TiffColorType.Rgb555:
+ DebugGuard.IsTrue(
+ bitsPerSample.Channels == 3
+ && bitsPerSample.Channel2 == 5
+ && bitsPerSample.Channel1 == 5
+ && bitsPerSample.Channel0 == 5,
+ "bitsPerSample");
+ DebugGuard.IsTrue(colorMap == null, "colorMap");
+ return new RgbTiffColor(bitsPerSample);
+
+ case TiffColorType.Rgba5555:
+ DebugGuard.IsTrue(
+ bitsPerSample.Channels == 4
+ && bitsPerSample.Channel3 == 5
+ && bitsPerSample.Channel2 == 5
+ && bitsPerSample.Channel1 == 5
+ && bitsPerSample.Channel0 == 5,
+ "bitsPerSample");
+ DebugGuard.IsTrue(colorMap == null, "colorMap");
+ return new RgbaTiffColor(bitsPerSample);
+
+ case TiffColorType.Rgb666:
+ DebugGuard.IsTrue(
+ bitsPerSample.Channels == 3
+ && bitsPerSample.Channel2 == 6
+ && bitsPerSample.Channel1 == 6
+ && bitsPerSample.Channel0 == 6,
+ "bitsPerSample");
+ DebugGuard.IsTrue(colorMap == null, "colorMap");
+ return new RgbTiffColor(bitsPerSample);
+
+ case TiffColorType.Rgba6666:
+ DebugGuard.IsTrue(
+ bitsPerSample.Channels == 4
+ && bitsPerSample.Channel3 == 6
+ && bitsPerSample.Channel2 == 6
+ && bitsPerSample.Channel1 == 6
+ && bitsPerSample.Channel0 == 6,
+ "bitsPerSample");
+ DebugGuard.IsTrue(colorMap == null, "colorMap");
+ return new RgbaTiffColor(bitsPerSample);
+
case TiffColorType.Rgb888:
DebugGuard.IsTrue(
bitsPerSample.Channels == 3
@@ -136,6 +221,17 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
DebugGuard.IsTrue(colorMap == null, "colorMap");
return new Rgb888TiffColor(configuration);
+ case TiffColorType.Rgba8888:
+ DebugGuard.IsTrue(
+ bitsPerSample.Channels == 4
+ && bitsPerSample.Channel3 == 8
+ && bitsPerSample.Channel2 == 8
+ && bitsPerSample.Channel1 == 8
+ && bitsPerSample.Channel0 == 8,
+ "bitsPerSample");
+ DebugGuard.IsTrue(colorMap == null, "colorMap");
+ return new Rgba8888TiffColor(configuration);
+
case TiffColorType.Rgb101010:
DebugGuard.IsTrue(
bitsPerSample.Channels == 3
@@ -146,6 +242,17 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
DebugGuard.IsTrue(colorMap == null, "colorMap");
return new RgbTiffColor(bitsPerSample);
+ case TiffColorType.Rgba10101010:
+ DebugGuard.IsTrue(
+ bitsPerSample.Channels == 4
+ && bitsPerSample.Channel3 == 10
+ && bitsPerSample.Channel2 == 10
+ && bitsPerSample.Channel1 == 10
+ && bitsPerSample.Channel0 == 10,
+ "bitsPerSample");
+ DebugGuard.IsTrue(colorMap == null, "colorMap");
+ return new RgbaTiffColor(bitsPerSample);
+
case TiffColorType.Rgb121212:
DebugGuard.IsTrue(
bitsPerSample.Channels == 3
@@ -156,6 +263,17 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
DebugGuard.IsTrue(colorMap == null, "colorMap");
return new RgbTiffColor(bitsPerSample);
+ case TiffColorType.Rgba12121212:
+ DebugGuard.IsTrue(
+ bitsPerSample.Channels == 4
+ && bitsPerSample.Channel3 == 12
+ && bitsPerSample.Channel2 == 12
+ && bitsPerSample.Channel1 == 12
+ && bitsPerSample.Channel0 == 12,
+ "bitsPerSample");
+ DebugGuard.IsTrue(colorMap == null, "colorMap");
+ return new RgbaTiffColor(bitsPerSample);
+
case TiffColorType.Rgb141414:
DebugGuard.IsTrue(
bitsPerSample.Channels == 3
@@ -166,6 +284,17 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
DebugGuard.IsTrue(colorMap == null, "colorMap");
return new RgbTiffColor(bitsPerSample);
+ case TiffColorType.Rgba14141414:
+ DebugGuard.IsTrue(
+ bitsPerSample.Channels == 4
+ && bitsPerSample.Channel3 == 14
+ && bitsPerSample.Channel2 == 14
+ && bitsPerSample.Channel1 == 14
+ && bitsPerSample.Channel0 == 14,
+ "bitsPerSample");
+ DebugGuard.IsTrue(colorMap == null, "colorMap");
+ return new RgbaTiffColor(bitsPerSample);
+
case TiffColorType.Rgb161616:
DebugGuard.IsTrue(
bitsPerSample.Channels == 3
@@ -176,6 +305,17 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
DebugGuard.IsTrue(colorMap == null, "colorMap");
return new Rgb161616TiffColor(configuration, isBigEndian: byteOrder == ByteOrder.BigEndian);
+ case TiffColorType.Rgba16161616:
+ DebugGuard.IsTrue(
+ bitsPerSample.Channels == 4
+ && bitsPerSample.Channel3 == 16
+ && bitsPerSample.Channel2 == 16
+ && bitsPerSample.Channel1 == 16
+ && bitsPerSample.Channel0 == 16,
+ "bitsPerSample");
+ DebugGuard.IsTrue(colorMap == null, "colorMap");
+ return new Rgba16161616TiffColor(configuration, isBigEndian: byteOrder == ByteOrder.BigEndian);
+
case TiffColorType.Rgb242424:
DebugGuard.IsTrue(
bitsPerSample.Channels == 3
@@ -186,6 +326,17 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
DebugGuard.IsTrue(colorMap == null, "colorMap");
return new Rgb242424TiffColor(isBigEndian: byteOrder == ByteOrder.BigEndian);
+ case TiffColorType.Rgba24242424:
+ DebugGuard.IsTrue(
+ bitsPerSample.Channels == 4
+ && bitsPerSample.Channel3 == 24
+ && bitsPerSample.Channel2 == 24
+ && bitsPerSample.Channel1 == 24
+ && bitsPerSample.Channel0 == 24,
+ "bitsPerSample");
+ DebugGuard.IsTrue(colorMap == null, "colorMap");
+ return new Rgba24242424TiffColor(isBigEndian: byteOrder == ByteOrder.BigEndian);
+
case TiffColorType.Rgb323232:
DebugGuard.IsTrue(
bitsPerSample.Channels == 3
@@ -196,6 +347,17 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
DebugGuard.IsTrue(colorMap == null, "colorMap");
return new Rgb323232TiffColor(isBigEndian: byteOrder == ByteOrder.BigEndian);
+ case TiffColorType.Rgba32323232:
+ DebugGuard.IsTrue(
+ bitsPerSample.Channels == 4
+ && bitsPerSample.Channel3 == 32
+ && bitsPerSample.Channel2 == 32
+ && bitsPerSample.Channel1 == 32
+ && bitsPerSample.Channel0 == 32,
+ "bitsPerSample");
+ DebugGuard.IsTrue(colorMap == null, "colorMap");
+ return new Rgba32323232TiffColor(isBigEndian: byteOrder == ByteOrder.BigEndian);
+
case TiffColorType.RgbFloat323232:
DebugGuard.IsTrue(
bitsPerSample.Channels == 3
@@ -206,6 +368,17 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
DebugGuard.IsTrue(colorMap == null, "colorMap");
return new RgbFloat323232TiffColor(isBigEndian: byteOrder == ByteOrder.BigEndian);
+ case TiffColorType.RgbaFloat32323232:
+ DebugGuard.IsTrue(
+ bitsPerSample.Channels == 4
+ && bitsPerSample.Channel3 == 32
+ && bitsPerSample.Channel2 == 32
+ && bitsPerSample.Channel1 == 32
+ && bitsPerSample.Channel0 == 32,
+ "bitsPerSample");
+ DebugGuard.IsTrue(colorMap == null, "colorMap");
+ return new RgbaFloat32323232TiffColor(isBigEndian: byteOrder == ByteOrder.BigEndian);
+
case TiffColorType.PaletteColor:
DebugGuard.NotNull(colorMap, "colorMap");
return new PaletteTiffColor(bitsPerSample, colorMap);
diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/TiffColorType.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/TiffColorType.cs
index 8caefaed56..a0a48c2b93 100644
--- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/TiffColorType.cs
+++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/TiffColorType.cs
@@ -103,51 +103,131 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
///
Rgb222,
+ ///
+ /// RGBA color image with 2 bits for each channel.
+ ///
+ Rgba2222,
+
+ ///
+ /// RGB color image with 3 bits for each channel.
+ ///
+ Rgb333,
+
+ ///
+ /// RGBA color image with 3 bits for each channel.
+ ///
+ Rgba3333,
+
///
/// RGB color image with 4 bits for each channel.
///
Rgb444,
+ ///
+ /// RGBA color image with 4 bits for each channel.
+ ///
+ Rgba4444,
+
+ ///
+ /// RGB color image with 5 bits for each channel.
+ ///
+ Rgb555,
+
+ ///
+ /// RGBA color image with 5 bits for each channel.
+ ///
+ Rgba5555,
+
+ ///
+ /// RGB color image with 6 bits for each channel.
+ ///
+ Rgb666,
+
+ ///
+ /// RGBA color image with 6 bits for each channel.
+ ///
+ Rgba6666,
+
///
/// RGB Full Color. Optimized implementation for 8-bit images.
///
Rgb888,
+ ///
+ /// RGBA Full Color with 8-bit for each channel.
+ ///
+ Rgba8888,
+
///
/// RGB color image with 10 bits for each channel.
///
Rgb101010,
+ ///
+ /// RGBA color image with 10 bits for each channel.
+ ///
+ Rgba10101010,
+
///
/// RGB color image with 12 bits for each channel.
///
Rgb121212,
+ ///
+ /// RGBA color image with 12 bits for each channel.
+ ///
+ Rgba12121212,
+
///
/// RGB color image with 14 bits for each channel.
///
Rgb141414,
+ ///
+ /// RGBA color image with 14 bits for each channel.
+ ///
+ Rgba14141414,
+
///
/// RGB color image with 16 bits for each channel.
///
Rgb161616,
+ ///
+ /// RGBA color image with 16 bits for each channel.
+ ///
+ Rgba16161616,
+
///
/// RGB color image with 24 bits for each channel.
///
Rgb242424,
+ ///
+ /// RGBA color image with 24 bits for each channel.
+ ///
+ Rgba24242424,
+
///
/// RGB color image with 32 bits for each channel.
///
Rgb323232,
+ ///
+ /// RGBA color image with 32 bits for each channel.
+ ///
+ Rgba32323232,
+
///
/// RGB color image with 32 bits floats for each channel.
///
RgbFloat323232,
+ ///
+ /// RGBA color image with 32 bits floats for each channel.
+ ///
+ RgbaFloat32323232,
+
///
/// RGB Full Color. Planar configuration of data. 8 Bit per color channel.
///
diff --git a/src/ImageSharp/Formats/Tiff/README.md b/src/ImageSharp/Formats/Tiff/README.md
index 51e84ef558..aa960b373c 100644
--- a/src/ImageSharp/Formats/Tiff/README.md
+++ b/src/ImageSharp/Formats/Tiff/README.md
@@ -105,7 +105,7 @@
|Artist | Y | Y | |
|HostComputer | Y | Y | |
|ColorMap | Y | Y | |
-|ExtraSamples | | - | |
+|ExtraSamples | | (Y) | Only UnassociatedAlphaData is supported so far |
|Copyright | Y | Y | |
### Extension TIFF Tags
diff --git a/src/ImageSharp/Formats/Tiff/TiffBitsPerSample.cs b/src/ImageSharp/Formats/Tiff/TiffBitsPerSample.cs
index 8fd26ac13d..9348a68839 100644
--- a/src/ImageSharp/Formats/Tiff/TiffBitsPerSample.cs
+++ b/src/ImageSharp/Formats/Tiff/TiffBitsPerSample.cs
@@ -25,6 +25,11 @@ namespace SixLabors.ImageSharp.Formats.Tiff
///
public readonly ushort Channel2;
+ ///
+ /// The bits for the alpha channel.
+ ///
+ public readonly ushort Channel3;
+
///
/// The number of channels.
///
@@ -36,16 +41,19 @@ namespace SixLabors.ImageSharp.Formats.Tiff
/// 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)
+ /// The bits for the channel 3.
+ public TiffBitsPerSample(ushort channel0, ushort channel1, ushort channel2, ushort channel3 = 0)
{
this.Channel0 = (ushort)Numerics.Clamp(channel0, 0, 32);
this.Channel1 = (ushort)Numerics.Clamp(channel1, 0, 32);
this.Channel2 = (ushort)Numerics.Clamp(channel2, 0, 32);
+ this.Channel3 = (ushort)Numerics.Clamp(channel3, 0, 32);
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);
+ this.Channels += (byte)(this.Channel3 != 0 ? 1 : 0);
}
///
@@ -62,11 +70,19 @@ namespace SixLabors.ImageSharp.Formats.Tiff
return false;
}
+ ushort c3 = 0;
ushort c2;
ushort c1;
ushort c0;
switch (value.Length)
{
+ case 4:
+ c3 = value[3];
+ c2 = value[2];
+ c1 = value[1];
+ c0 = value[0];
+ break;
+
case 3:
c2 = value[2];
c1 = value[1];
@@ -84,7 +100,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff
break;
}
- sample = new TiffBitsPerSample(c0, c1, c2);
+ sample = new TiffBitsPerSample(c0, c1, c2, c3);
return true;
}
@@ -96,11 +112,12 @@ namespace SixLabors.ImageSharp.Formats.Tiff
public bool Equals(TiffBitsPerSample other)
=> this.Channel0 == other.Channel0
&& this.Channel1 == other.Channel1
- && this.Channel2 == other.Channel2;
+ && this.Channel2 == other.Channel2
+ && this.Channel3 == other.Channel3;
///
public override int GetHashCode()
- => HashCode.Combine(this.Channel0, this.Channel1, this.Channel2);
+ => HashCode.Combine(this.Channel0, this.Channel1, this.Channel2, this.Channel3);
///
/// Converts the bits per sample struct to an ushort array.
@@ -118,7 +135,12 @@ namespace SixLabors.ImageSharp.Formats.Tiff
return new[] { this.Channel0, this.Channel1 };
}
- return new[] { this.Channel0, this.Channel1, this.Channel2 };
+ if (this.Channel3 == 0)
+ {
+ return new[] { this.Channel0, this.Channel1, this.Channel2 };
+ }
+
+ return new[] { this.Channel0, this.Channel1, this.Channel2, this.Channel3 };
}
///
@@ -127,12 +149,14 @@ namespace SixLabors.ImageSharp.Formats.Tiff
/// Bits per pixel.
public TiffBitsPerPixel BitsPerPixel()
{
- int bitsPerPixel = this.Channel0 + this.Channel1 + this.Channel2;
+ int bitsPerPixel = this.Channel0 + this.Channel1 + this.Channel2 + this.Channel3;
return (TiffBitsPerPixel)bitsPerPixel;
}
///
public override string ToString()
- => $"TiffBitsPerSample({this.Channel0}, {this.Channel1}, {this.Channel2})";
+ => this.Channel3 is 0 ?
+ $"TiffBitsPerSample({this.Channel0}, {this.Channel1}, {this.Channel2})"
+ : $"TiffBitsPerSample({this.Channel0}, {this.Channel1}, {this.Channel2}, {this.Channel3})";
}
}
diff --git a/src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs b/src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs
index cd06282f18..aaaef0b8a7 100644
--- a/src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs
+++ b/src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs
@@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff
///
/// Gets the decoding mode for multi-frame images
///
- private FrameDecodingMode decodingMode;
+ private readonly FrameDecodingMode decodingMode;
///
/// The stream to decode from.
@@ -117,6 +117,11 @@ namespace SixLabors.ImageSharp.Formats.Tiff
///
public TiffFillOrder FillOrder { get; set; }
+ ///
+ /// Gets or sets the extra samples, which can contain the alpha channel data.
+ ///
+ public TiffExtraSampleType? ExtraSamples { get; set; }
+
///
/// Gets or sets the JPEG tables when jpeg compression is used.
///
diff --git a/src/ImageSharp/Formats/Tiff/TiffDecoderOptionsParser.cs b/src/ImageSharp/Formats/Tiff/TiffDecoderOptionsParser.cs
index a187d444ac..0f1ffc79ff 100644
--- a/src/ImageSharp/Formats/Tiff/TiffDecoderOptionsParser.cs
+++ b/src/ImageSharp/Formats/Tiff/TiffDecoderOptionsParser.cs
@@ -29,9 +29,21 @@ namespace SixLabors.ImageSharp.Formats.Tiff
TiffThrowHelper.ThrowNotSupported("Tiled images are not supported.");
}
- if (exifProfile.GetValueInternal(ExifTag.ExtraSamples) is not null)
+ IExifValue extraSamplesExifValue = exifProfile.GetValueInternal(ExifTag.ExtraSamples);
+ if (extraSamplesExifValue is not null)
{
- TiffThrowHelper.ThrowNotSupported("ExtraSamples is not supported.");
+ short[] extraSamples = (short[])extraSamplesExifValue.GetValue();
+ if (extraSamples.Length != 1)
+ {
+ TiffThrowHelper.ThrowNotSupported("ExtraSamples is only supported with one extra sample for alpha data.");
+ }
+
+ var extraSamplesType = (TiffExtraSampleType)extraSamples[0];
+ options.ExtraSamples = extraSamplesType;
+ if (extraSamplesType is not TiffExtraSampleType.UnassociatedAlphaData)
+ {
+ TiffThrowHelper.ThrowNotSupported("Decoding Tiff images with ExtraSamples is only supported with UnassociatedAlphaData.");
+ }
}
TiffFillOrder fillOrder = (TiffFillOrder?)exifProfile.GetValue(ExifTag.FillOrder)?.Value ?? TiffFillOrder.MostSignificantBitFirst;
@@ -52,7 +64,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff
sampleFormat = sampleFormats[0];
foreach (TiffSampleFormat format in sampleFormats)
{
- if (format != TiffSampleFormat.UnsignedInteger && format != TiffSampleFormat.Float)
+ if (format is not TiffSampleFormat.UnsignedInteger and not TiffSampleFormat.Float)
{
TiffThrowHelper.ThrowNotSupported("ImageSharp only supports the UnsignedInteger and Float SampleFormat.");
}
@@ -252,12 +264,13 @@ namespace SixLabors.ImageSharp.Formats.Tiff
case TiffPhotometricInterpretation.Rgb:
{
TiffBitsPerSample bitsPerSample = options.BitsPerSample;
- if (bitsPerSample.Channels != 3)
+ if (bitsPerSample.Channels is not (3 or 4))
{
TiffThrowHelper.ThrowNotSupported("The number of samples in the TIFF BitsPerSample entry is not supported.");
}
- if (!(bitsPerSample.Channel0 == bitsPerSample.Channel1 && bitsPerSample.Channel1 == bitsPerSample.Channel2))
+ if ((bitsPerSample.Channels == 3 && !(bitsPerSample.Channel0 == bitsPerSample.Channel1 && bitsPerSample.Channel1 == bitsPerSample.Channel2)) ||
+ (bitsPerSample.Channels == 4 && !(bitsPerSample.Channel0 == bitsPerSample.Channel1 && bitsPerSample.Channel1 == bitsPerSample.Channel2 && bitsPerSample.Channel2 == bitsPerSample.Channel3)))
{
TiffThrowHelper.ThrowNotSupported("Only BitsPerSample with equal bits per channel are supported.");
}
@@ -270,41 +283,50 @@ namespace SixLabors.ImageSharp.Formats.Tiff
case 32:
if (options.SampleFormat == TiffSampleFormat.Float)
{
- options.ColorType = TiffColorType.RgbFloat323232;
+ options.ColorType = options.BitsPerSample.Channels is 3 ? TiffColorType.RgbFloat323232 : TiffColorType.RgbaFloat32323232;
return;
}
- options.ColorType = TiffColorType.Rgb323232;
+ options.ColorType = options.BitsPerSample.Channels is 3 ? TiffColorType.Rgb323232 : TiffColorType.Rgba32323232;
break;
case 24:
- options.ColorType = TiffColorType.Rgb242424;
+ options.ColorType = options.BitsPerSample.Channels is 3 ? TiffColorType.Rgb242424 : TiffColorType.Rgba24242424;
break;
case 16:
- options.ColorType = TiffColorType.Rgb161616;
+ options.ColorType = options.BitsPerSample.Channels is 3 ? TiffColorType.Rgb161616 : TiffColorType.Rgba16161616;
break;
case 14:
- options.ColorType = TiffColorType.Rgb141414;
+ options.ColorType = options.BitsPerSample.Channels is 3 ? TiffColorType.Rgb141414 : TiffColorType.Rgba14141414;
break;
case 12:
- options.ColorType = TiffColorType.Rgb121212;
+ options.ColorType = options.BitsPerSample.Channels is 3 ? TiffColorType.Rgb121212 : TiffColorType.Rgba12121212;
break;
case 10:
- options.ColorType = TiffColorType.Rgb101010;
+ options.ColorType = options.BitsPerSample.Channels is 3 ? TiffColorType.Rgb101010 : TiffColorType.Rgba10101010;
break;
case 8:
- options.ColorType = TiffColorType.Rgb888;
+ options.ColorType = options.BitsPerSample.Channels is 3 ? TiffColorType.Rgb888 : TiffColorType.Rgba8888;
+ break;
+ case 6:
+ options.ColorType = options.BitsPerSample.Channels is 3 ? TiffColorType.Rgb666 : TiffColorType.Rgba6666;
+ break;
+ case 5:
+ options.ColorType = options.BitsPerSample.Channels is 3 ? TiffColorType.Rgb555 : TiffColorType.Rgba5555;
break;
case 4:
- options.ColorType = TiffColorType.Rgb444;
+ options.ColorType = options.BitsPerSample.Channels is 3 ? TiffColorType.Rgb444 : TiffColorType.Rgba4444;
+ break;
+ case 3:
+ options.ColorType = options.BitsPerSample.Channels is 3 ? TiffColorType.Rgb333 : TiffColorType.Rgba3333;
break;
case 2:
- options.ColorType = TiffColorType.Rgb222;
+ options.ColorType = options.BitsPerSample.Channels is 3 ? TiffColorType.Rgb222 : TiffColorType.Rgba2222;
break;
default:
TiffThrowHelper.ThrowNotSupported("Bits per sample is not supported.");
diff --git a/src/ImageSharp/Formats/Tiff/TiffExtraSampleType.cs b/src/ImageSharp/Formats/Tiff/TiffExtraSampleType.cs
new file mode 100644
index 0000000000..5fbc29177d
--- /dev/null
+++ b/src/ImageSharp/Formats/Tiff/TiffExtraSampleType.cs
@@ -0,0 +1,27 @@
+// Copyright (c) Six Labors.
+// Licensed under the Apache License, Version 2.0.
+
+namespace SixLabors.ImageSharp.Formats.Tiff
+{
+ ///
+ /// Description of extra components.
+ ///
+ internal enum TiffExtraSampleType
+ {
+ ///
+ /// The data is unspecified, not supported.
+ ///
+ UnspecifiedData = 0,
+
+ ///
+ /// The extra data is associated alpha data (with pre-multiplied color).
+ ///
+ AssociatedAlphaData = 1,
+
+ ///
+ /// The extra data is unassociated alpha data is transparency information that logically exists independent of an image;
+ /// it is commonly called a soft matte.
+ ///
+ UnassociatedAlphaData = 2
+ }
+}
diff --git a/src/ImageSharp/Formats/Tiff/Utils/TiffUtils.cs b/src/ImageSharp/Formats/Tiff/Utils/TiffUtils.cs
index 4f71fa35c9..6ec905929f 100644
--- a/src/ImageSharp/Formats/Tiff/Utils/TiffUtils.cs
+++ b/src/ImageSharp/Formats/Tiff/Utils/TiffUtils.cs
@@ -54,6 +54,15 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Utils
return color;
}
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static TPixel ColorFromRgba64(Rgba64 rgba, ulong r, ulong g, ulong b, ulong a, TPixel color)
+ where TPixel : unmanaged, IPixel
+ {
+ rgba.PackedValue = r | (g << 16) | (b << 32) | (a << 48);
+ color.FromRgba64(rgba);
+ return color;
+ }
+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static TPixel ColorScaleTo24Bit(ulong r, ulong g, ulong b, TPixel color)
where TPixel : unmanaged, IPixel
@@ -72,6 +81,15 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Utils
return color;
}
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static TPixel ColorScaleTo32Bit(ulong r, ulong g, ulong b, ulong a, TPixel color)
+ where TPixel : unmanaged, IPixel
+ {
+ var colorVector = new Vector4(r * Scale32Bit, g * Scale32Bit, b * Scale32Bit, a);
+ color.FromVector4(colorVector);
+ return color;
+ }
+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static TPixel ColorFromL16(L16 l16, ushort intensity, TPixel color)
where TPixel : unmanaged, IPixel
diff --git a/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs
index e4f4d26b85..de8ae8e729 100644
--- a/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs
+++ b/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs
@@ -123,6 +123,21 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff
public void TiffDecoder_CanDecode_8Bit_Gray(TestImageProvider provider)
where TPixel : unmanaged, IPixel => TestTiffDecoder(provider);
+ [Theory]
+ [WithFile(Rgba2BitUnassociatedAlpha, PixelTypes.Rgba32)]
+ public void TiffDecoder_CanDecode_8Bit_WithUnassociatedAlpha(TestImageProvider provider)
+ where TPixel : unmanaged, IPixel => TestTiffDecoder(provider);
+
+ [Theory]
+ [WithFile(FLowerRgb3Bit, PixelTypes.Rgba32)]
+ public void TiffDecoder_CanDecode_9Bit_WithUnassociatedAlpha(TestImageProvider provider)
+ where TPixel : unmanaged, IPixel
+ {
+ // Note: because the MagickReferenceDecoder fails to load the image, we only debug save them.
+ using Image image = provider.GetImage();
+ image.DebugSave(provider);
+ }
+
[Theory]
[WithFile(Flower10BitGray, PixelTypes.Rgba32)]
public void TiffDecoder_CanDecode_10Bit_Gray(TestImageProvider provider)
@@ -139,11 +154,31 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff
public void TiffDecoder_CanDecode_12Bit_Gray(TestImageProvider provider)
where TPixel : unmanaged, IPixel => TestTiffDecoder(provider);
+ [Theory]
+ [WithFile(Rgba3BitUnassociatedAlpha, PixelTypes.Rgba32)]
+ public void TiffDecoder_CanDecode_12Bit_WithUnassociatedAlpha(TestImageProvider provider)
+ where TPixel : unmanaged, IPixel
+ {
+ // Note: because the MagickReferenceDecoder fails to load the image, we only debug save them.
+ using Image image = provider.GetImage();
+ image.DebugSave(provider);
+ }
+
[Theory]
[WithFile(Flower14BitGray, PixelTypes.Rgba32)]
public void TiffDecoder_CanDecode_14Bit_Gray(TestImageProvider provider)
where TPixel : unmanaged, IPixel => TestTiffDecoder(provider);
+ [Theory]
+ [WithFile(FLowerRgb5Bit, PixelTypes.Rgba32)]
+ public void TiffDecoder_CanDecode_15Bit(TestImageProvider provider)
+ where TPixel : unmanaged, IPixel
+ {
+ // Note: because the MagickReferenceDecoder fails to load the image, we only debug save them.
+ using Image image = provider.GetImage();
+ image.DebugSave(provider);
+ }
+
[Theory]
[WithFile(Flower16BitGrayLittleEndian, PixelTypes.Rgba32)]
[WithFile(Flower16BitGray, PixelTypes.Rgba32)]
@@ -158,6 +193,36 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff
public void TiffDecoder_CanDecode_16Bit_Gray_WithPredictor(TestImageProvider provider)
where TPixel : unmanaged, IPixel => TestTiffDecoder(provider);
+ [Theory]
+ [WithFile(Rgba4BitUnassociatedAlpha, PixelTypes.Rgba32)]
+ public void TiffDecoder_CanDecode_16Bit_WithUnassociatedAlpha(TestImageProvider provider)
+ where TPixel : unmanaged, IPixel => TestTiffDecoder(provider);
+
+ [Theory]
+ [WithFile(FLowerRgb6Bit, PixelTypes.Rgba32)]
+ public void TiffDecoder_CanDecode_18Bit(TestImageProvider provider)
+ where TPixel : unmanaged, IPixel => TestTiffDecoder(provider);
+
+ [Theory]
+ [WithFile(Rgba5BitUnassociatedAlpha, PixelTypes.Rgba32)]
+ public void TiffDecoder_CanDecode_20Bit_WithUnassociatedAlpha(TestImageProvider provider)
+ where TPixel : unmanaged, IPixel
+ {
+ // Note: because the MagickReferenceDecoder fails to load the image, we only debug save them.
+ using Image image = provider.GetImage();
+ image.DebugSave(provider);
+ }
+
+ [Theory]
+ [WithFile(FlowerRgb888Contiguous, PixelTypes.Rgba32)]
+ public void TiffDecoder_CanDecode_24Bit(TestImageProvider provider)
+ where TPixel : unmanaged, IPixel => TestTiffDecoder(provider);
+
+ [Theory]
+ [WithFile(Rgba6BitUnassociatedAlpha, PixelTypes.Rgba32)]
+ public void TiffDecoder_CanDecode_24Bit_WithUnassociatedAlpha(TestImageProvider provider)
+ where TPixel : unmanaged, IPixel => TestTiffDecoder(provider);
+
[Theory]
[WithFile(Flower24BitGray, PixelTypes.Rgba32)]
[WithFile(Flower24BitGrayLittleEndian, PixelTypes.Rgba32)]
@@ -207,6 +272,16 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff
image.DebugSave(provider);
}
+ [Theory]
+ [WithFile(Rgba8BitUnassociatedAlpha, PixelTypes.Rgba32)]
+ public void TiffDecoder_CanDecode_32Bit_WithUnassociatedAlpha(TestImageProvider provider)
+ where TPixel : unmanaged, IPixel
+ {
+ // Note: because the MagickReferenceDecoder fails to load the image, we only debug save them.
+ using Image image = provider.GetImage();
+ image.DebugSave(provider);
+ }
+
[Theory]
[WithFile(Flower32BitGrayPredictorBigEndian, PixelTypes.Rgba32)]
[WithFile(Flower32BitGrayPredictorLittleEndian, PixelTypes.Rgba32)]
@@ -223,6 +298,12 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff
public void TiffDecoder_CanDecode_36Bit(TestImageProvider provider)
where TPixel : unmanaged, IPixel => TestTiffDecoder(provider);
+ [Theory]
+ [WithFile(Rgba10BitUnassociatedAlphaBigEndian, PixelTypes.Rgba32)]
+ [WithFile(Rgba10BitUnassociatedAlphaLittleEndian, PixelTypes.Rgba32)]
+ public void TiffDecoder_CanDecode_40Bit_WithUnassociatedAlpha(TestImageProvider provider)
+ where TPixel : unmanaged, IPixel => TestTiffDecoder(provider);
+
[Theory]
[WithFile(FlowerRgb141414Contiguous, PixelTypes.Rgba32)]
[WithFile(FlowerRgb141414Planar, PixelTypes.Rgba32)]
@@ -238,12 +319,24 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff
public void TiffDecoder_CanDecode_48Bit(TestImageProvider provider)
where TPixel : unmanaged, IPixel => TestTiffDecoder(provider);
+ [Theory]
+ [WithFile(Rgba12BitUnassociatedAlphaBigEndian, PixelTypes.Rgba32)]
+ [WithFile(Rgba12BitUnassociatedAlphaLittleEndian, PixelTypes.Rgba32)]
+ public void TiffDecoder_CanDecode_48Bit_WithUnassociatedAlpha(TestImageProvider provider)
+ where TPixel : unmanaged, IPixel => TestTiffDecoder(provider);
+
[Theory]
[WithFile(FlowerRgb161616PredictorBigEndian, PixelTypes.Rgba32)]
[WithFile(FlowerRgb161616PredictorLittleEndian, PixelTypes.Rgba32)]
public void TiffDecoder_CanDecode_48Bit_WithPredictor(TestImageProvider provider)
where TPixel : unmanaged, IPixel => TestTiffDecoder(provider);
+ [Theory]
+ [WithFile(Rgba14BitUnassociatedAlphaBigEndian, PixelTypes.Rgba32)]
+ [WithFile(Rgba14BitUnassociatedAlphaLittleEndian, PixelTypes.Rgba32)]
+ public void TiffDecoder_CanDecode_56Bit_WithUnassociatedAlpha(TestImageProvider provider)
+ where TPixel : unmanaged, IPixel => TestTiffDecoder(provider);
+
[Theory]
[WithFile(FlowerRgb242424Contiguous, PixelTypes.Rgba32)]
[WithFile(FlowerRgb242424ContiguousLittleEndian, PixelTypes.Rgba32)]
@@ -270,6 +363,17 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff
image.DebugSave(provider);
}
+ [Theory]
+ [WithFile(Rgba24BitUnassociatedAlphaBigEndian, PixelTypes.Rgba32)]
+ [WithFile(Rgba24BitUnassociatedAlphaLittleEndian, PixelTypes.Rgba32)]
+ public void TiffDecoder_CanDecode_96Bit_WithUnassociatedAlpha(TestImageProvider provider)
+ where TPixel : unmanaged, IPixel
+ {
+ // Note: because the MagickReferenceDecoder fails to load the image, we only debug save them.
+ using Image image = provider.GetImage();
+ image.DebugSave(provider);
+ }
+
[Theory]
[WithFile(FlowerRgbFloat323232, PixelTypes.Rgba32)]
[WithFile(FlowerRgbFloat323232LittleEndian, PixelTypes.Rgba32)]
@@ -305,6 +409,23 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff
image.DebugSave(provider);
}
+ [Theory]
+ [WithFile(Rgba16BitUnassociatedAlphaBigEndian, PixelTypes.Rgba32)]
+ [WithFile(Rgba16BitUnassociatedAlphaLittleEndian, PixelTypes.Rgba32)]
+ public void TiffDecoder_CanDecode_128Bit_UnassociatedAlpha(TestImageProvider provider)
+ where TPixel : unmanaged, IPixel => TestTiffDecoder(provider);
+
+ [Theory]
+ [WithFile(Rgba32BitUnassociatedAlphaBigEndian, PixelTypes.Rgba32)]
+ [WithFile(Rgba32BitUnassociatedAlphaLittleEndian, PixelTypes.Rgba32)]
+ public void TiffDecoder_CanDecode_128Bit_WithUnassociatedAlpha(TestImageProvider provider)
+ where TPixel : unmanaged, IPixel
+ {
+ // Note: because the MagickReferenceDecoder fails to load the image, we only debug save them.
+ using Image image = provider.GetImage();
+ image.DebugSave(provider);
+ }
+
[Theory]
[WithFile(GrayscaleDeflateMultistrip, PixelTypes.Rgba32)]
[WithFile(RgbDeflateMultistrip, PixelTypes.Rgba32)]
diff --git a/tests/ImageSharp.Tests/TestImages.cs b/tests/ImageSharp.Tests/TestImages.cs
index aa4314b8e0..476d54e83f 100644
--- a/tests/ImageSharp.Tests/TestImages.cs
+++ b/tests/ImageSharp.Tests/TestImages.cs
@@ -831,6 +831,9 @@ namespace SixLabors.ImageSharp.Tests
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 FLowerRgb3Bit = "Tiff/flower-rgb-3bit.tiff";
+ public const string FLowerRgb5Bit = "Tiff/flower-rgb-5bit.tiff";
+ public const string FLowerRgb6Bit = "Tiff/flower-rgb-6bit.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";
@@ -855,6 +858,26 @@ namespace SixLabors.ImageSharp.Tests
public const string Flower32BitGrayPredictorBigEndian = "Tiff/flower-minisblack-32_msb_deflate_predictor.tiff";
public const string Flower32BitGrayPredictorLittleEndian = "Tiff/flower-minisblack-32_lsb_deflate_predictor.tiff";
+ // Images with alpha channel.
+ public const string Rgba2BitUnassociatedAlpha = "Tiff/RgbaUnassociatedAlpha2bit.tiff";
+ public const string Rgba3BitUnassociatedAlpha = "Tiff/RgbaUnassociatedAlpha3bit.tiff";
+ public const string Rgba4BitUnassociatedAlpha = "Tiff/RgbaUnassociatedAlpha4bit.tiff";
+ public const string Rgba5BitUnassociatedAlpha = "Tiff/RgbaUnassociatedAlpha5bit.tiff";
+ public const string Rgba6BitUnassociatedAlpha = "Tiff/RgbaUnassociatedAlpha6bit.tiff";
+ public const string Rgba8BitUnassociatedAlpha = "Tiff/RgbaUnassociatedAlpha8bit.tiff";
+ public const string Rgba10BitUnassociatedAlphaBigEndian = "Tiff/RgbaUnassociatedAlpha10bit_msb.tiff";
+ public const string Rgba10BitUnassociatedAlphaLittleEndian = "Tiff/RgbaUnassociatedAlpha10bit_msb.tiff";
+ public const string Rgba12BitUnassociatedAlphaBigEndian = "Tiff/RgbaUnassociatedAlpha12bit_msb.tiff";
+ public const string Rgba12BitUnassociatedAlphaLittleEndian = "Tiff/RgbaUnassociatedAlpha12bit_msb.tiff";
+ public const string Rgba14BitUnassociatedAlphaBigEndian = "Tiff/RgbaUnassociatedAlpha14bit_msb.tiff";
+ public const string Rgba14BitUnassociatedAlphaLittleEndian = "Tiff/RgbaUnassociatedAlpha14bit_msb.tiff";
+ public const string Rgba16BitUnassociatedAlphaBigEndian = "Tiff/RgbaUnassociatedAlpha16bit_msb.tiff";
+ public const string Rgba16BitUnassociatedAlphaLittleEndian = "Tiff/RgbaUnassociatedAlpha16bit_msb.tiff";
+ public const string Rgba24BitUnassociatedAlphaBigEndian = "Tiff/RgbaUnassociatedAlpha24bit_msb.tiff";
+ public const string Rgba24BitUnassociatedAlphaLittleEndian = "Tiff/RgbaUnassociatedAlpha24bit_msb.tiff";
+ public const string Rgba32BitUnassociatedAlphaBigEndian = "Tiff/RgbaUnassociatedAlpha32bit_msb.tiff";
+ public const string Rgba32BitUnassociatedAlphaLittleEndian = "Tiff/RgbaUnassociatedAlpha32bit_msb.tiff";
+
public const string Issues1716Rgb161616BitLittleEndian = "Tiff/Issues/Issue1716.tiff";
public const string Issues1891 = "Tiff/Issues/Issue1891.tiff";
diff --git a/tests/Images/Input/Tiff/RgbaUnassociatedAlpha10bit_lsb.tiff b/tests/Images/Input/Tiff/RgbaUnassociatedAlpha10bit_lsb.tiff
new file mode 100644
index 0000000000..f4a1a3f6bc
--- /dev/null
+++ b/tests/Images/Input/Tiff/RgbaUnassociatedAlpha10bit_lsb.tiff
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:7f78ef11e4044d13ea3bf699e33472a708df3a5cc817dc41edb4df184f127f2b
+size 294278
diff --git a/tests/Images/Input/Tiff/RgbaUnassociatedAlpha10bit_msb.tiff b/tests/Images/Input/Tiff/RgbaUnassociatedAlpha10bit_msb.tiff
new file mode 100644
index 0000000000..06beb72f3a
--- /dev/null
+++ b/tests/Images/Input/Tiff/RgbaUnassociatedAlpha10bit_msb.tiff
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:d9c2d6f4e16677d9fdfb38cc2bfb7df05eedbb8dc0e3c26a6dba9b427c2c698a
+size 294278
diff --git a/tests/Images/Input/Tiff/RgbaUnassociatedAlpha12bit_lsb.tiff b/tests/Images/Input/Tiff/RgbaUnassociatedAlpha12bit_lsb.tiff
new file mode 100644
index 0000000000..94a9447050
--- /dev/null
+++ b/tests/Images/Input/Tiff/RgbaUnassociatedAlpha12bit_lsb.tiff
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:53e9ff25da2a2a7a613328cfaf33799df51fe150586fb8de52070e8cc8830d97
+size 353078
diff --git a/tests/Images/Input/Tiff/RgbaUnassociatedAlpha12bit_msb.tiff b/tests/Images/Input/Tiff/RgbaUnassociatedAlpha12bit_msb.tiff
new file mode 100644
index 0000000000..26d911272e
--- /dev/null
+++ b/tests/Images/Input/Tiff/RgbaUnassociatedAlpha12bit_msb.tiff
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:caff76e01bc39b7a295f01a11e3787a6487ac002af5586dd956166a9c91eb048
+size 353078
diff --git a/tests/Images/Input/Tiff/RgbaUnassociatedAlpha14bit_lsb.tiff b/tests/Images/Input/Tiff/RgbaUnassociatedAlpha14bit_lsb.tiff
new file mode 100644
index 0000000000..f1bd4c405f
--- /dev/null
+++ b/tests/Images/Input/Tiff/RgbaUnassociatedAlpha14bit_lsb.tiff
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:9193b6a194be970b2cfb26369fa487fd6ec2f1656af11df2e48f1d6b0971bbf8
+size 411878
diff --git a/tests/Images/Input/Tiff/RgbaUnassociatedAlpha14bit_msb.tiff b/tests/Images/Input/Tiff/RgbaUnassociatedAlpha14bit_msb.tiff
new file mode 100644
index 0000000000..b098877e0c
--- /dev/null
+++ b/tests/Images/Input/Tiff/RgbaUnassociatedAlpha14bit_msb.tiff
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:888bc84af8dffc4565b215412a8a2bb56f0c78211a082b893d87595cd9f555c1
+size 411878
diff --git a/tests/Images/Input/Tiff/RgbaUnassociatedAlpha16bit_lsb.tiff b/tests/Images/Input/Tiff/RgbaUnassociatedAlpha16bit_lsb.tiff
new file mode 100644
index 0000000000..cfb5082f14
--- /dev/null
+++ b/tests/Images/Input/Tiff/RgbaUnassociatedAlpha16bit_lsb.tiff
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:6eae92c012ad56c084929e0a2aff7c93091224d9f8ab7f52f71b845792d6b763
+size 470678
diff --git a/tests/Images/Input/Tiff/RgbaUnassociatedAlpha16bit_msb.tiff b/tests/Images/Input/Tiff/RgbaUnassociatedAlpha16bit_msb.tiff
new file mode 100644
index 0000000000..5cd4d9c457
--- /dev/null
+++ b/tests/Images/Input/Tiff/RgbaUnassociatedAlpha16bit_msb.tiff
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:cbab54f221956215266c35bfd26fdfb123e092e3836e2401b9f24e1c5b23516e
+size 470678
diff --git a/tests/Images/Input/Tiff/RgbaUnassociatedAlpha24bit_lsb.tiff b/tests/Images/Input/Tiff/RgbaUnassociatedAlpha24bit_lsb.tiff
new file mode 100644
index 0000000000..c0f54d865b
--- /dev/null
+++ b/tests/Images/Input/Tiff/RgbaUnassociatedAlpha24bit_lsb.tiff
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:fd9fa514619604275cede0b4747291db2f8e5ad02095565c891ace2b537d6336
+size 705878
diff --git a/tests/Images/Input/Tiff/RgbaUnassociatedAlpha24bit_msb.tiff b/tests/Images/Input/Tiff/RgbaUnassociatedAlpha24bit_msb.tiff
new file mode 100644
index 0000000000..33f7bee0fa
--- /dev/null
+++ b/tests/Images/Input/Tiff/RgbaUnassociatedAlpha24bit_msb.tiff
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:915ca9bbda952fc9ac78b44be07dab603948d51fb1a274935905e73cfe5bb0b9
+size 705878
diff --git a/tests/Images/Input/Tiff/RgbaUnassociatedAlpha2bit.tiff b/tests/Images/Input/Tiff/RgbaUnassociatedAlpha2bit.tiff
new file mode 100644
index 0000000000..cfbc058325
--- /dev/null
+++ b/tests/Images/Input/Tiff/RgbaUnassociatedAlpha2bit.tiff
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:f650c49faed4fd19b5527a0771489110090948e4ed33daa53b42c1776e288d89
+size 59078
diff --git a/tests/Images/Input/Tiff/RgbaUnassociatedAlpha32bit_lsb.tiff b/tests/Images/Input/Tiff/RgbaUnassociatedAlpha32bit_lsb.tiff
new file mode 100644
index 0000000000..0e11ef26cb
--- /dev/null
+++ b/tests/Images/Input/Tiff/RgbaUnassociatedAlpha32bit_lsb.tiff
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:8cad4c5f42d77539ce1f67efa7e0ed1fa4f5dd32b3269e5862453d878c6b18d7
+size 941078
diff --git a/tests/Images/Input/Tiff/RgbaUnassociatedAlpha32bit_msb.tiff b/tests/Images/Input/Tiff/RgbaUnassociatedAlpha32bit_msb.tiff
new file mode 100644
index 0000000000..cfb8beb2bb
--- /dev/null
+++ b/tests/Images/Input/Tiff/RgbaUnassociatedAlpha32bit_msb.tiff
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:8874322776b8620573c26a3c84b8c7c9bf0aeaa7d68a7fef009f8838d14dca5b
+size 941078
diff --git a/tests/Images/Input/Tiff/RgbaUnassociatedAlpha3bit.tiff b/tests/Images/Input/Tiff/RgbaUnassociatedAlpha3bit.tiff
new file mode 100644
index 0000000000..aed59c3317
--- /dev/null
+++ b/tests/Images/Input/Tiff/RgbaUnassociatedAlpha3bit.tiff
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:d0d89ddcda8525799b90c1cb4a15f3ea1cf399c2259017f219b1d09876161587
+size 88478
diff --git a/tests/Images/Input/Tiff/RgbaUnassociatedAlpha4bit.tiff b/tests/Images/Input/Tiff/RgbaUnassociatedAlpha4bit.tiff
new file mode 100644
index 0000000000..7176c382f1
--- /dev/null
+++ b/tests/Images/Input/Tiff/RgbaUnassociatedAlpha4bit.tiff
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:be006e56c2c2f34686293e8a5f4397a7bf873ff927d4dd0808cac90310569254
+size 117878
diff --git a/tests/Images/Input/Tiff/RgbaUnassociatedAlpha5bit.tiff b/tests/Images/Input/Tiff/RgbaUnassociatedAlpha5bit.tiff
new file mode 100644
index 0000000000..aad945b8e7
--- /dev/null
+++ b/tests/Images/Input/Tiff/RgbaUnassociatedAlpha5bit.tiff
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:2928f06ef146625f5c696272901a63644699e3410dc155b7e4e470009a7f6dfc
+size 147278
diff --git a/tests/Images/Input/Tiff/RgbaUnassociatedAlpha6bit.tiff b/tests/Images/Input/Tiff/RgbaUnassociatedAlpha6bit.tiff
new file mode 100644
index 0000000000..9909afe71e
--- /dev/null
+++ b/tests/Images/Input/Tiff/RgbaUnassociatedAlpha6bit.tiff
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:514ce84d3506aab7360b24f63aa1da1ea66abd9b1e534a12487d03486a7e593b
+size 176678
diff --git a/tests/Images/Input/Tiff/RgbaUnassociatedAlpha8bit.tiff b/tests/Images/Input/Tiff/RgbaUnassociatedAlpha8bit.tiff
new file mode 100644
index 0000000000..47270d98de
--- /dev/null
+++ b/tests/Images/Input/Tiff/RgbaUnassociatedAlpha8bit.tiff
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:234401d70156cc748a67992919f8780bb855bc5e87e404b573f61b5eb4817dcf
+size 266816
diff --git a/tests/Images/Input/Tiff/flower-rgb-3bit.tiff b/tests/Images/Input/Tiff/flower-rgb-3bit.tiff
new file mode 100644
index 0000000000..db5f7916c7
--- /dev/null
+++ b/tests/Images/Input/Tiff/flower-rgb-3bit.tiff
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:3b778a97467b1475c47c71b5f029c23b0962309095b8702cfc81c8fbaf4b8edb
+size 3886
diff --git a/tests/Images/Input/Tiff/flower-rgb-5bit.tiff b/tests/Images/Input/Tiff/flower-rgb-5bit.tiff
new file mode 100644
index 0000000000..af1bc3921d
--- /dev/null
+++ b/tests/Images/Input/Tiff/flower-rgb-5bit.tiff
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:44a53ffce2bfd3f1010a1fe232c8010708458880230f11b75ea3ef16b5164ce1
+size 6208
diff --git a/tests/Images/Input/Tiff/flower-rgb-6bit.tiff b/tests/Images/Input/Tiff/flower-rgb-6bit.tiff
new file mode 100644
index 0000000000..b0399487d5
--- /dev/null
+++ b/tests/Images/Input/Tiff/flower-rgb-6bit.tiff
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:3d1db5b448aa9d61dd38dfb86e91e04fd0779a9c68cc2073913bcee3c635b5fe
+size 7412