diff --git a/src/ImageSharp/Formats/Tiff/Constants/TiffConstants.cs b/src/ImageSharp/Formats/Tiff/Constants/TiffConstants.cs
index 6fe412b925..5733bada97 100644
--- a/src/ImageSharp/Formats/Tiff/Constants/TiffConstants.cs
+++ b/src/ImageSharp/Formats/Tiff/Constants/TiffConstants.cs
@@ -85,16 +85,46 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Constants
///
public static readonly ushort[] BitsPerSample1Bit = { 1 };
+ ///
+ /// The bits per sample for images with a 2 color palette.
+ ///
+ public static readonly ushort[] BitsPerSample2Bit = { 2 };
+
///
/// The bits per sample for images with a 4 color palette.
///
public static readonly ushort[] BitsPerSample4Bit = { 4 };
+ ///
+ /// The bits per sample for 6 bit gray images.
+ ///
+ public static readonly ushort[] BitsPerSample6Bit = { 6 };
+
///
/// The bits per sample for 8 bit images.
///
public static readonly ushort[] BitsPerSample8Bit = { 8 };
+ ///
+ /// The bits per sample for 10 bit gray images.
+ ///
+ public static readonly ushort[] BitsPerSample10Bit = { 10 };
+
+ ///
+ /// The bits per sample for 12 bit gray images.
+ ///
+ public static readonly ushort[] BitsPerSample12Bit = { 12 };
+
+ ///
+ /// The bits per sample for 14 bit gray images.
+ ///
+ public static readonly ushort[] BitsPerSample14Bit = { 14 };
+
+ ///
+ /// The bits per sample for 16 bit gray images.
+ ///
+ public static readonly ushort[] BitsPerSample16Bit = { 16 };
+
///
/// The bits per sample for color images with 2 bits for each color channel.
///
@@ -115,11 +145,21 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Constants
///
public static readonly ushort[] BitsPerSampleRgb10Bit = { 10, 10, 10 };
+ ///
+ /// The bits per sample for color images with 12 bits for each color channel.
+ ///
+ public static readonly ushort[] BitsPerSampleRgb12Bit = { 12, 12, 12 };
+
///
/// The bits per sample for color images with 14 bits for each color channel.
///
public static readonly ushort[] BitsPerSampleRgb14Bit = { 14, 14, 14 };
+ ///
+ /// The bits per sample for color images with 14 bits for each color channel.
+ ///
+ public static readonly ushort[] BitsPerSampleRgb16Bit = { 16, 16, 16 };
+
///
/// The list of mimetypes that equate to a tiff.
///
diff --git a/src/ImageSharp/Formats/Tiff/TiffBitsPerSample.cs b/src/ImageSharp/Formats/Tiff/TiffBitsPerSample.cs
new file mode 100644
index 0000000000..71f6b5bf9f
--- /dev/null
+++ b/src/ImageSharp/Formats/Tiff/TiffBitsPerSample.cs
@@ -0,0 +1,96 @@
+// Copyright (c) Six Labors.
+// Licensed under the Apache License, Version 2.0.
+
+namespace SixLabors.ImageSharp.Formats.Tiff
+{
+ ///
+ /// The number of bits per component.
+ ///
+ public enum TiffBitsPerSample
+ {
+ ///
+ /// The bits per samples is not known.
+ ///
+ Unknown = 0,
+
+ ///
+ /// One bit per sample for bicolor images.
+ ///
+ Bit1,
+
+ ///
+ /// Two bits per sample for grayscale images with 4 different levels of gray or paletted images with a palette of 4 colors.
+ ///
+ Bit2,
+
+ ///
+ /// Four bits per sample for grayscale images with 16 different levels of gray or paletted images with a palette of 16 colors.
+ ///
+ Bit4,
+
+ ///
+ /// Six bits per sample for grayscale images.
+ ///
+ Bit6,
+
+ ///
+ /// Eight bits per sample for grayscale images with 256 different levels of gray or paletted images with a palette of 256 colors.
+ ///
+ Bit8,
+
+ ///
+ /// Ten bits per sample for grayscale images.
+ ///
+ Bit10,
+
+ ///
+ /// Twelve bits per sample for grayscale images.
+ ///
+ Bit12,
+
+ ///
+ /// Fourteen bits per sample for grayscale images.
+ ///
+ Bit14,
+
+ ///
+ /// Sixteen bits per sample for grayscale images.
+ ///
+ Bit16,
+
+ ///
+ /// 6 bits per sample, each channel has 2 bits.
+ ///
+ Rgb222,
+
+ ///
+ /// Twelve bits per sample, each channel has 4 bits.
+ ///
+ Rgb444,
+
+ ///
+ /// 24 bits per sample, each color channel has 8 Bits.
+ ///
+ Rgb888,
+
+ ///
+ /// Thirty bits per sample, each channel has 10 bits.
+ ///
+ Rgb101010,
+
+ ///
+ /// Thirty six bits per sample, each channel has 12 bits.
+ ///
+ Rgb121212,
+
+ ///
+ /// Forty two bits per sample, each channel has 14 bits.
+ ///
+ Rgb141414,
+
+ ///
+ /// Forty eight bits per sample, each channel has 16 bits.
+ ///
+ Rgb161616,
+ }
+}
diff --git a/src/ImageSharp/Formats/Tiff/TiffBitsPerSampleExtensions.cs b/src/ImageSharp/Formats/Tiff/TiffBitsPerSampleExtensions.cs
new file mode 100644
index 0000000000..5ec1331b31
--- /dev/null
+++ b/src/ImageSharp/Formats/Tiff/TiffBitsPerSampleExtensions.cs
@@ -0,0 +1,170 @@
+// 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[] BitsPerChannel(this TiffBitsPerSample tiffBitsPerSample)
+ {
+ switch (tiffBitsPerSample)
+ {
+ case TiffBitsPerSample.Bit1:
+ return TiffConstants.BitsPerSample1Bit;
+ case TiffBitsPerSample.Bit2:
+ return TiffConstants.BitsPerSample2Bit;
+ case TiffBitsPerSample.Bit4:
+ return TiffConstants.BitsPerSample4Bit;
+ case TiffBitsPerSample.Bit6:
+ return TiffConstants.BitsPerSample6Bit;
+ case TiffBitsPerSample.Bit8:
+ return TiffConstants.BitsPerSample8Bit;
+ case TiffBitsPerSample.Bit10:
+ return TiffConstants.BitsPerSample10Bit;
+ case TiffBitsPerSample.Bit12:
+ return TiffConstants.BitsPerSample12Bit;
+ case TiffBitsPerSample.Bit14:
+ return TiffConstants.BitsPerSample14Bit;
+ case TiffBitsPerSample.Bit16:
+ return TiffConstants.BitsPerSample16Bit;
+ case TiffBitsPerSample.Rgb222:
+ return TiffConstants.BitsPerSampleRgb2Bit;
+ case TiffBitsPerSample.Rgb444:
+ return TiffConstants.BitsPerSampleRgb4Bit;
+ case TiffBitsPerSample.Rgb888:
+ return TiffConstants.BitsPerSampleRgb8Bit;
+ case TiffBitsPerSample.Rgb101010:
+ return TiffConstants.BitsPerSampleRgb10Bit;
+ case TiffBitsPerSample.Rgb121212:
+ return TiffConstants.BitsPerSampleRgb12Bit;
+ case TiffBitsPerSample.Rgb141414:
+ return TiffConstants.BitsPerSampleRgb14Bit;
+ case TiffBitsPerSample.Rgb161616:
+ return TiffConstants.BitsPerSampleRgb16Bit;
+ 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.BitsPerSampleRgb16Bit[2] &&
+ bitsPerSample[1] == TiffConstants.BitsPerSampleRgb16Bit[1] &&
+ bitsPerSample[0] == TiffConstants.BitsPerSampleRgb16Bit[0])
+ {
+ return TiffBitsPerSample.Rgb161616;
+ }
+
+ if (bitsPerSample[2] == TiffConstants.BitsPerSampleRgb14Bit[2] &&
+ bitsPerSample[1] == TiffConstants.BitsPerSampleRgb14Bit[1] &&
+ bitsPerSample[0] == TiffConstants.BitsPerSampleRgb14Bit[0])
+ {
+ return TiffBitsPerSample.Rgb141414;
+ }
+
+ if (bitsPerSample[2] == TiffConstants.BitsPerSampleRgb12Bit[2] &&
+ bitsPerSample[1] == TiffConstants.BitsPerSampleRgb12Bit[1] &&
+ bitsPerSample[0] == TiffConstants.BitsPerSampleRgb12Bit[0])
+ {
+ return TiffBitsPerSample.Rgb121212;
+ }
+
+ if (bitsPerSample[2] == TiffConstants.BitsPerSampleRgb10Bit[2] &&
+ bitsPerSample[1] == TiffConstants.BitsPerSampleRgb10Bit[1] &&
+ bitsPerSample[0] == TiffConstants.BitsPerSampleRgb10Bit[0])
+ {
+ return TiffBitsPerSample.Rgb101010;
+ }
+
+ if (bitsPerSample[2] == TiffConstants.BitsPerSampleRgb8Bit[2] &&
+ bitsPerSample[1] == TiffConstants.BitsPerSampleRgb8Bit[1] &&
+ bitsPerSample[0] == TiffConstants.BitsPerSampleRgb8Bit[0])
+ {
+ return TiffBitsPerSample.Rgb888;
+ }
+
+ if (bitsPerSample[2] == TiffConstants.BitsPerSampleRgb4Bit[2] &&
+ bitsPerSample[1] == TiffConstants.BitsPerSampleRgb4Bit[1] &&
+ bitsPerSample[0] == TiffConstants.BitsPerSampleRgb4Bit[0])
+ {
+ return TiffBitsPerSample.Rgb444;
+ }
+
+ if (bitsPerSample[2] == TiffConstants.BitsPerSampleRgb2Bit[2] &&
+ bitsPerSample[1] == TiffConstants.BitsPerSampleRgb2Bit[1] &&
+ bitsPerSample[0] == TiffConstants.BitsPerSampleRgb2Bit[0])
+ {
+ return TiffBitsPerSample.Rgb222;
+ }
+
+ break;
+
+ case 1:
+ if (bitsPerSample[0] == TiffConstants.BitsPerSample1Bit[0])
+ {
+ return TiffBitsPerSample.Bit1;
+ }
+
+ if (bitsPerSample[0] == TiffConstants.BitsPerSample2Bit[0])
+ {
+ return TiffBitsPerSample.Bit2;
+ }
+
+ if (bitsPerSample[0] == TiffConstants.BitsPerSample4Bit[0])
+ {
+ return TiffBitsPerSample.Bit4;
+ }
+
+ if (bitsPerSample[0] == TiffConstants.BitsPerSample6Bit[0])
+ {
+ return TiffBitsPerSample.Bit6;
+ }
+
+ if (bitsPerSample[0] == TiffConstants.BitsPerSample8Bit[0])
+ {
+ return TiffBitsPerSample.Bit8;
+ }
+
+ if (bitsPerSample[0] == TiffConstants.BitsPerSample10Bit[0])
+ {
+ return TiffBitsPerSample.Bit10;
+ }
+
+ if (bitsPerSample[0] == TiffConstants.BitsPerSample12Bit[0])
+ {
+ return TiffBitsPerSample.Bit12;
+ }
+
+ if (bitsPerSample[0] == TiffConstants.BitsPerSample14Bit[0])
+ {
+ return TiffBitsPerSample.Bit14;
+ }
+
+ if (bitsPerSample[0] == TiffConstants.BitsPerSample16Bit[0])
+ {
+ return TiffBitsPerSample.Bit16;
+ }
+
+ break;
+ }
+
+ return TiffBitsPerSample.Unknown;
+ }
+ }
+}
diff --git a/src/ImageSharp/Formats/Tiff/TiffDecoderOptionsParser.cs b/src/ImageSharp/Formats/Tiff/TiffDecoderOptionsParser.cs
index 014dd55380..1efc826027 100644
--- a/src/ImageSharp/Formats/Tiff/TiffDecoderOptionsParser.cs
+++ b/src/ImageSharp/Formats/Tiff/TiffDecoderOptionsParser.cs
@@ -69,7 +69,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 = frameMetadata.BitsPerSample ?? Array.Empty();
+ options.BitsPerSample = frameMetadata.BitsPerSample != null ? frameMetadata.BitsPerSample?.BitsPerChannel() : Array.Empty();
options.ParseColorType(exifProfile);
options.ParseCompression(frameMetadata.Compression, exifProfile);
diff --git a/src/ImageSharp/Formats/Tiff/TiffFrameMetadata.cs b/src/ImageSharp/Formats/Tiff/TiffFrameMetadata.cs
index ef7573d3e0..62e9fb4e21 100644
--- a/src/ImageSharp/Formats/Tiff/TiffFrameMetadata.cs
+++ b/src/ImageSharp/Formats/Tiff/TiffFrameMetadata.cs
@@ -38,7 +38,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff
///
/// Gets or sets number of bits per component.
///
- public ushort[] BitsPerSample { get; set; }
+ public TiffBitsPerSample? BitsPerSample { get; set; }
///
/// Gets or sets the compression scheme used on the image data.
@@ -77,11 +77,10 @@ namespace SixLabors.ImageSharp.Formats.Tiff
{
if (profile != null)
{
- meta.BitsPerSample = profile.GetValue(ExifTag.BitsPerSample)?.Value;
- meta.BitsPerPixel = BitsPerPixelFromBitsPerSample(meta.BitsPerSample);
+ meta.BitsPerSample = profile.GetValue(ExifTag.BitsPerSample) != null ? profile.GetValue(ExifTag.BitsPerSample)?.Value.GetBitsPerSample() : null;
+ meta.BitsPerPixel = BitsPerPixelFromBitsPerSample(meta.BitsPerSample?.BitsPerChannel());
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);
diff --git a/tests/ImageSharp.Tests/TestImages.cs b/tests/ImageSharp.Tests/TestImages.cs
index 28ef20cf4c..7eca4795df 100644
--- a/tests/ImageSharp.Tests/TestImages.cs
+++ b/tests/ImageSharp.Tests/TestImages.cs
@@ -558,8 +558,6 @@ 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";
@@ -573,6 +571,8 @@ namespace SixLabors.ImageSharp.Tests
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";