diff --git a/src/ImageSharp/Formats/Tiff/TiffBitsPerSample.cs b/src/ImageSharp/Formats/Tiff/TiffBitsPerSample.cs
new file mode 100644
index 000000000..b556e5b95
--- /dev/null
+++ b/src/ImageSharp/Formats/Tiff/TiffBitsPerSample.cs
@@ -0,0 +1,36 @@
+// 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,
+
+ ///
+ /// One bit per sample for bicolor images.
+ ///
+ One,
+
+ ///
+ /// Four bits per sample for grayscale images with 16 different levels of gray or paletted images with a palette of 16 colors.
+ ///
+ Four,
+
+ ///
+ /// Eight bits per sample for grayscale images with 256 different levels of gray or paletted images with a palette of 256 colors.
+ ///
+ Eight,
+
+ ///
+ /// Each channel has 8 Bits.
+ ///
+ Rgb888,
+ }
+}
diff --git a/src/ImageSharp/Formats/Tiff/TiffBitsPerSampleExtensions.cs b/src/ImageSharp/Formats/Tiff/TiffBitsPerSampleExtensions.cs
new file mode 100644
index 000000000..884481b98
--- /dev/null
+++ b/src/ImageSharp/Formats/Tiff/TiffBitsPerSampleExtensions.cs
@@ -0,0 +1,99 @@
+// Copyright (c) Six Labors.
+// Licensed under the Apache License, Version 2.0.
+
+using System;
+using SixLabors.ImageSharp.Formats.Experimental.Tiff;
+
+namespace SixLabors.ImageSharp.Formats.Tiff
+{
+ internal static class TiffBitsPerSampleExtensions
+ {
+ private static readonly ushort[] One = { 1 };
+
+ private static readonly ushort[] Four = { 4 };
+
+ private static readonly ushort[] Eight = { 8 };
+
+ private static readonly ushort[] Rgb888 = { 8, 8, 8 };
+
+ ///
+ /// 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.One:
+ return One;
+ case TiffBitsPerSample.Four:
+ return Four;
+ case TiffBitsPerSample.Eight:
+ return Eight;
+ case TiffBitsPerSample.Rgb888:
+ return Rgb888;
+
+ default:
+ TiffThrowHelper.ThrowNotSupported("The bits per pixels are not supported");
+ 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[0] == Rgb888[0] && bitsPerSample[1] == Rgb888[1] && bitsPerSample[2] == Rgb888[2])
+ {
+ return TiffBitsPerSample.Rgb888;
+ }
+
+ break;
+
+ case 1:
+ if (bitsPerSample[0] == One[0])
+ {
+ return TiffBitsPerSample.One;
+ }
+
+ if (bitsPerSample[0] == Four[0])
+ {
+ return TiffBitsPerSample.Four;
+ }
+
+ if (bitsPerSample[0] == Eight[0])
+ {
+ return TiffBitsPerSample.Eight;
+ }
+
+ break;
+ }
+
+ return TiffBitsPerSample.Unknown;
+ }
+
+ ///
+ /// Gets the bits per pixel for the given bits per sample.
+ ///
+ /// The tiff bits per sample.
+ /// Bits per pixel.
+ public static int BitsPerPixel(this TiffBitsPerSample tiffBitsPerSample)
+ {
+ var bitsPerSample = tiffBitsPerSample.Bits();
+ int bitsPerPixel = 0;
+ foreach (var bits in bitsPerSample)
+ {
+ bitsPerPixel += bits;
+ }
+
+ return bitsPerPixel;
+ }
+ }
+}
diff --git a/src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs b/src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs
index fe81d2edb..876816a36 100644
--- a/src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs
+++ b/src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs
@@ -5,6 +5,7 @@ using System.Collections.Generic;
using System.Threading;
using SixLabors.ImageSharp.Formats.Experimental.Tiff.Compression;
using SixLabors.ImageSharp.Formats.Experimental.Tiff.Constants;
+using SixLabors.ImageSharp.Formats.Tiff;
using SixLabors.ImageSharp.IO;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.Metadata;
@@ -48,9 +49,9 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff
}
///
- /// Gets or sets the number of bits for each sample of the pixel format used to encode the image.
+ /// Gets or sets the number of bits per component of the pixel format used to decode the image.
///
- public ushort[] BitsPerSample { get; set; }
+ public TiffBitsPerSample BitsPerSample { get; set; }
///
/// Gets or sets the bits per pixel.
@@ -154,7 +155,7 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff
ImageMetadata metadata = TiffDecoderMetadataCreator.Create(framesMetadata, this.ignoreMetadata, reader.ByteOrder);
TiffFrameMetadata root = framesMetadata[0];
- return new ImageInfo(new PixelTypeInfo(root.BitsPerPixel), (int)root.Width, (int)root.Height, metadata);
+ return new ImageInfo(new PixelTypeInfo(root.BitsPerSample.BitsPerPixel()), (int)root.Width, (int)root.Height, metadata);
}
///
@@ -213,7 +214,7 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff
}
else
{
- bitsPerPixel = this.BitsPerSample[plane];
+ bitsPerPixel = this.BitsPerSample.Bits()[plane];
}
int bytesPerRow = ((width * bitsPerPixel) + 7) / 8;
@@ -233,7 +234,7 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff
private void DecodeStripsPlanar(ImageFrame frame, int rowsPerStrip, Number[] stripOffsets, Number[] stripByteCounts)
where TPixel : unmanaged, IPixel
{
- int stripsPerPixel = this.BitsPerSample.Length;
+ int stripsPerPixel = this.BitsPerSample.Bits().Length;
int stripsPerPlane = stripOffsets.Length / stripsPerPixel;
int bitsPerPixel = this.BitsPerPixel;
@@ -251,7 +252,7 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff
using TiffBaseDecompresor decompressor = TiffDecompressorsFactory.Create(this.CompressionType, this.memoryAllocator, this.PhotometricInterpretation, frame.Width, bitsPerPixel, this.Predictor, this.FaxCompressionOptions);
- RgbPlanarTiffColor colorDecoder = TiffColorDecoderFactory.CreatePlanar(this.ColorType, this.BitsPerSample, this.ColorMap);
+ RgbPlanarTiffColor colorDecoder = TiffColorDecoderFactory.CreatePlanar(this.ColorType, this.BitsPerSample.Bits(), this.ColorMap);
for (int i = 0; i < stripsPerPlane; i++)
{
@@ -294,7 +295,7 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff
using TiffBaseDecompresor decompressor = TiffDecompressorsFactory.Create(this.CompressionType, this.memoryAllocator, this.PhotometricInterpretation, frame.Width, bitsPerPixel, this.Predictor, this.FaxCompressionOptions);
- TiffBaseColorDecoder colorDecoder = TiffColorDecoderFactory.Create(this.ColorType, this.BitsPerSample, this.ColorMap);
+ TiffBaseColorDecoder colorDecoder = TiffColorDecoderFactory.Create(this.ColorType, this.BitsPerSample.Bits(), this.ColorMap);
for (int stripIndex = 0; stripIndex < stripOffsets.Length; stripIndex++)
{
diff --git a/src/ImageSharp/Formats/Tiff/TiffDecoderMetadataCreator.cs b/src/ImageSharp/Formats/Tiff/TiffDecoderMetadataCreator.cs
index de17ada5d..b1696dc86 100644
--- a/src/ImageSharp/Formats/Tiff/TiffDecoderMetadataCreator.cs
+++ b/src/ImageSharp/Formats/Tiff/TiffDecoderMetadataCreator.cs
@@ -4,7 +4,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
-
+using SixLabors.ImageSharp.Formats.Tiff;
using SixLabors.ImageSharp.Metadata;
using SixLabors.ImageSharp.Metadata.Profiles.Exif;
using SixLabors.ImageSharp.Metadata.Profiles.Icc;
@@ -129,6 +129,6 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff
}
private static TiffBitsPerPixel GetBitsPerPixel(TiffFrameMetadata firstFrameMetaData)
- => (TiffBitsPerPixel)firstFrameMetaData.BitsPerPixel;
+ => (TiffBitsPerPixel)firstFrameMetaData.BitsPerSample.BitsPerPixel();
}
}
diff --git a/src/ImageSharp/Formats/Tiff/TiffDecoderOptionsParser.cs b/src/ImageSharp/Formats/Tiff/TiffDecoderOptionsParser.cs
index 123b8494e..fa90c4522 100644
--- a/src/ImageSharp/Formats/Tiff/TiffDecoderOptionsParser.cs
+++ b/src/ImageSharp/Formats/Tiff/TiffDecoderOptionsParser.cs
@@ -3,6 +3,7 @@
using SixLabors.ImageSharp.Formats.Experimental.Tiff.Compression;
using SixLabors.ImageSharp.Formats.Experimental.Tiff.Constants;
+using SixLabors.ImageSharp.Formats.Tiff;
using SixLabors.ImageSharp.Metadata.Profiles.Exif;
namespace SixLabors.ImageSharp.Formats.Experimental.Tiff
@@ -59,7 +60,7 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff
options.Predictor = entries.Predictor;
options.PhotometricInterpretation = entries.PhotometricInterpretation;
options.BitsPerSample = entries.BitsPerSample;
- options.BitsPerPixel = entries.BitsPerPixel;
+ options.BitsPerPixel = entries.BitsPerSample.BitsPerPixel();
ParseColorType(options, entries);
ParseCompression(options, entries);
@@ -71,38 +72,36 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff
{
case TiffPhotometricInterpretation.WhiteIsZero:
{
- if (options.BitsPerSample.Length == 1)
+ if (options.BitsPerSample.Bits().Length != 1)
{
- switch (options.BitsPerSample[0])
- {
- case 8:
- {
- options.ColorType = TiffColorType.WhiteIsZero8;
- break;
- }
-
- case 4:
- {
- options.ColorType = TiffColorType.WhiteIsZero4;
- break;
- }
-
- case 1:
- {
- options.ColorType = TiffColorType.WhiteIsZero1;
- break;
- }
-
- default:
- {
- options.ColorType = TiffColorType.WhiteIsZero;
- break;
- }
- }
+ TiffThrowHelper.ThrowNotSupported("The number of samples in the TIFF BitsPerSample entry is not supported.");
}
- else
+
+ switch (options.BitsPerSample)
{
- TiffThrowHelper.ThrowNotSupported("The number of samples in the TIFF BitsPerSample entry is not supported.");
+ case TiffBitsPerSample.Eight:
+ {
+ options.ColorType = TiffColorType.WhiteIsZero8;
+ break;
+ }
+
+ case TiffBitsPerSample.Four:
+ {
+ options.ColorType = TiffColorType.WhiteIsZero4;
+ break;
+ }
+
+ case TiffBitsPerSample.One:
+ {
+ options.ColorType = TiffColorType.WhiteIsZero1;
+ break;
+ }
+
+ default:
+ {
+ options.ColorType = TiffColorType.WhiteIsZero;
+ break;
+ }
}
break;
@@ -110,38 +109,36 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff
case TiffPhotometricInterpretation.BlackIsZero:
{
- if (options.BitsPerSample.Length == 1)
+ if (options.BitsPerSample.Bits().Length != 1)
{
- switch (options.BitsPerSample[0])
- {
- case 8:
- {
- options.ColorType = TiffColorType.BlackIsZero8;
- break;
- }
-
- case 4:
- {
- options.ColorType = TiffColorType.BlackIsZero4;
- break;
- }
-
- case 1:
- {
- options.ColorType = TiffColorType.BlackIsZero1;
- break;
- }
-
- default:
- {
- options.ColorType = TiffColorType.BlackIsZero;
- break;
- }
- }
+ TiffThrowHelper.ThrowNotSupported("The number of samples in the TIFF BitsPerSample entry is not supported.");
}
- else
+
+ switch (options.BitsPerSample)
{
- TiffThrowHelper.ThrowNotSupported("The number of samples in the TIFF BitsPerSample entry is not supported.");
+ case TiffBitsPerSample.Eight:
+ {
+ options.ColorType = TiffColorType.BlackIsZero8;
+ break;
+ }
+
+ case TiffBitsPerSample.Four:
+ {
+ options.ColorType = TiffColorType.BlackIsZero4;
+ break;
+ }
+
+ case TiffBitsPerSample.One:
+ {
+ options.ColorType = TiffColorType.BlackIsZero1;
+ break;
+ }
+
+ default:
+ {
+ options.ColorType = TiffColorType.BlackIsZero;
+ break;
+ }
}
break;
@@ -149,27 +146,18 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff
case TiffPhotometricInterpretation.Rgb:
{
- if (options.BitsPerSample.Length == 3)
+ if (options.BitsPerSample.Bits().Length != 3)
{
- if (options.PlanarConfiguration == TiffPlanarConfiguration.Chunky)
- {
- if (options.BitsPerSample[0] == 8 && options.BitsPerSample[1] == 8 && options.BitsPerSample[2] == 8)
- {
- options.ColorType = TiffColorType.Rgb888;
- }
- else
- {
- options.ColorType = TiffColorType.Rgb;
- }
- }
- else
- {
- options.ColorType = TiffColorType.RgbPlanar;
- }
+ TiffThrowHelper.ThrowNotSupported("The number of samples in the TIFF BitsPerSample entry is not supported.");
+ }
+
+ if (options.PlanarConfiguration == TiffPlanarConfiguration.Chunky)
+ {
+ options.ColorType = options.BitsPerSample == TiffBitsPerSample.Rgb888 ? TiffColorType.Rgb888 : TiffColorType.Rgb;
}
else
{
- TiffThrowHelper.ThrowNotSupported("The number of samples in the TIFF BitsPerSample entry is not supported.");
+ options.ColorType = TiffColorType.RgbPlanar;
}
break;
@@ -180,21 +168,12 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff
options.ColorMap = entries.ColorMap;
if (options.ColorMap != null)
{
- if (options.BitsPerSample.Length == 1)
- {
- switch (options.BitsPerSample[0])
- {
- default:
- {
- options.ColorType = TiffColorType.PaletteColor;
- break;
- }
- }
- }
- else
+ if (options.BitsPerSample.Bits().Length != 1)
{
TiffThrowHelper.ThrowNotSupported("The number of samples in the TIFF BitsPerSample entry is not supported.");
}
+
+ options.ColorType = TiffColorType.PaletteColor;
}
else
{
@@ -206,7 +185,7 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff
default:
{
- TiffThrowHelper.ThrowNotSupported("The specified TIFF photometric interpretation is not supported: " + options.PhotometricInterpretation);
+ TiffThrowHelper.ThrowNotSupported($"The specified TIFF photometric interpretation is not supported: {options.PhotometricInterpretation}");
}
break;
diff --git a/src/ImageSharp/Formats/Tiff/TiffFrameMetadata.cs b/src/ImageSharp/Formats/Tiff/TiffFrameMetadata.cs
index 363e68cee..21a24896d 100644
--- a/src/ImageSharp/Formats/Tiff/TiffFrameMetadata.cs
+++ b/src/ImageSharp/Formats/Tiff/TiffFrameMetadata.cs
@@ -4,6 +4,7 @@
using System.Collections.Generic;
using System.Linq;
using SixLabors.ImageSharp.Formats.Experimental.Tiff.Constants;
+using SixLabors.ImageSharp.Formats.Tiff;
using SixLabors.ImageSharp.Metadata;
using SixLabors.ImageSharp.Metadata.Profiles.Exif;
@@ -88,7 +89,7 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff
///
/// Gets the number of bits per component.
///
- public ushort[] BitsPerSample
+ public TiffBitsPerSample BitsPerSample
{
get
{
@@ -98,32 +99,21 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff
if (this.PhotometricInterpretation == TiffPhotometricInterpretation.WhiteIsZero
|| this.PhotometricInterpretation == TiffPhotometricInterpretation.BlackIsZero)
{
- bits = new[] { (ushort)1 };
+ return TiffBitsPerSample.One;
}
- else
- {
- TiffThrowHelper.ThrowNotSupported("The TIFF BitsPerSample entry is missing.");
- }
- }
- return bits;
- }
- }
-
- internal int BitsPerPixel
- {
- get
- {
- int bitsPerPixel = 0;
- foreach (var bits in this.BitsPerSample)
- {
- bitsPerPixel += bits;
+ TiffThrowHelper.ThrowNotSupported("The TIFF BitsPerSample entry is missing which is required to decode the image.");
}
- return bitsPerPixel;
+ return bits.GetBitsPerSample();
}
}
+ ///
+ /// Gets the bits per pixel.
+ ///
+ public int BitsPerPixel => this.BitsPerSample.BitsPerPixel();
+
///
/// Gets the compression scheme used on the image data.
///
diff --git a/tests/ImageSharp.Tests/Formats/Tiff/TiffMetadataTests.cs b/tests/ImageSharp.Tests/Formats/Tiff/TiffMetadataTests.cs
index 9acd44608..e4b935e0f 100644
--- a/tests/ImageSharp.Tests/Formats/Tiff/TiffMetadataTests.cs
+++ b/tests/ImageSharp.Tests/Formats/Tiff/TiffMetadataTests.cs
@@ -8,6 +8,7 @@ using System.Linq;
using SixLabors.ImageSharp.Formats.Experimental.Tiff;
using SixLabors.ImageSharp.Formats.Experimental.Tiff.Constants;
+using SixLabors.ImageSharp.Formats.Tiff;
using SixLabors.ImageSharp.Metadata;
using SixLabors.ImageSharp.Metadata.Profiles.Exif;
using SixLabors.ImageSharp.Metadata.Profiles.Icc;
@@ -187,7 +188,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff
Assert.Equal(32u, frame.Width);
Assert.Equal(32u, frame.Height);
- Assert.Equal(new ushort[] { 4 }, frame.BitsPerSample);
+ Assert.Equal(TiffBitsPerSample.Four, frame.BitsPerSample);
Assert.Equal(TiffCompression.Lzw, frame.Compression);
Assert.Equal(TiffPhotometricInterpretation.PaletteColor, frame.PhotometricInterpretation);
Assert.Equal("This is Название", frame.ImageDescription);