diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgb32PlanarTiffColor{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgb32PlanarTiffColor{TPixel}.cs
new file mode 100644
index 0000000000..a7432549ce
--- /dev/null
+++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgb32PlanarTiffColor{TPixel}.cs
@@ -0,0 +1,71 @@
+// Copyright (c) Six Labors.
+// Licensed under the Apache License, Version 2.0.
+
+using System;
+using System.Buffers;
+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 'Planar' layout for each color channel with 32 bit.
+ ///
+ internal class Rgb32PlanarTiffColor : TiffBasePlanarColorDecoder
+ 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 Rgb32PlanarTiffColor(bool isBigEndian) => this.isBigEndian = isBigEndian;
+
+ ///
+ public override void Decode(IMemoryOwner[] data, Buffer2D pixels, int left, int top, int width, int height)
+ {
+ // Note: due to an issue with netcore 2.1 and default values and unpredictable behavior with those,
+ // we define our own defaults as a workaround. See: https://github.com/dotnet/runtime/issues/55623
+ var color = default(TPixel);
+ color.FromVector4(TiffUtils.Vector4Default);
+
+ Span redData = data[0].GetSpan();
+ Span greenData = data[1].GetSpan();
+ Span blueData = data[2].GetSpan();
+
+ int offset = 0;
+ for (int y = top; y < top + height; y++)
+ {
+ Span pixelRow = pixels.GetRowSpan(y).Slice(left, width);
+ if (this.isBigEndian)
+ {
+ for (int x = 0; x < pixelRow.Length; x++)
+ {
+ ulong r = TiffUtils.ConvertToUIntBigEndian(redData.Slice(offset, 4));
+ ulong g = TiffUtils.ConvertToUIntBigEndian(greenData.Slice(offset, 4));
+ ulong b = TiffUtils.ConvertToUIntBigEndian(blueData.Slice(offset, 4));
+
+ offset += 4;
+
+ pixelRow[x] = TiffUtils.ColorScaleTo32Bit(r, g, b, color);
+ }
+ }
+ else
+ {
+ for (int x = 0; x < pixelRow.Length; x++)
+ {
+ ulong r = TiffUtils.ConvertToUIntLittleEndian(redData.Slice(offset, 4));
+ ulong g = TiffUtils.ConvertToUIntLittleEndian(greenData.Slice(offset, 4));
+ ulong b = TiffUtils.ConvertToUIntLittleEndian(blueData.Slice(offset, 4));
+
+ offset += 4;
+
+ pixelRow[x] = TiffUtils.ColorScaleTo32Bit(r, g, b, color);
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/TiffColorDecoderFactory{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/TiffColorDecoderFactory{TPixel}.cs
index a34b1ad3e0..9b3fb058ba 100644
--- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/TiffColorDecoderFactory{TPixel}.cs
+++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/TiffColorDecoderFactory{TPixel}.cs
@@ -189,19 +189,21 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
{
switch (colorType)
{
- case TiffColorType.RgbPlanar:
+ case TiffColorType.Rgb888Planar:
DebugGuard.IsTrue(colorMap == null, "colorMap");
- if (bitsPerSample.Channel0 == 16 && bitsPerSample.Channel1 == 16 && bitsPerSample.Channel2 == 16)
- {
- return new Rgb16PlanarTiffColor(byteOrder == ByteOrder.BigEndian);
- }
+ return new RgbPlanarTiffColor(bitsPerSample);
- if (bitsPerSample.Channel0 == 24 && bitsPerSample.Channel1 == 24 && bitsPerSample.Channel2 == 24)
- {
- return new Rgb24PlanarTiffColor(byteOrder == ByteOrder.BigEndian);
- }
+ case TiffColorType.Rgb161616Planar:
+ DebugGuard.IsTrue(colorMap == null, "colorMap");
+ return new Rgb16PlanarTiffColor(byteOrder == ByteOrder.BigEndian);
- return new RgbPlanarTiffColor(bitsPerSample);
+ case TiffColorType.Rgb242424Planar:
+ DebugGuard.IsTrue(colorMap == null, "colorMap");
+ return new Rgb24PlanarTiffColor(byteOrder == ByteOrder.BigEndian);
+
+ case TiffColorType.Rgb323232Planar:
+ DebugGuard.IsTrue(colorMap == null, "colorMap");
+ return new Rgb32PlanarTiffColor(byteOrder == ByteOrder.BigEndian);
default:
throw TiffThrowHelper.InvalidColorType(colorType.ToString());
diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/TiffColorType.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/TiffColorType.cs
index ffc5a81673..dc47dc8cd4 100644
--- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/TiffColorType.cs
+++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/TiffColorType.cs
@@ -134,8 +134,23 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
Rgb323232,
///
- /// RGB Full Color. Planar configuration of data.
+ /// RGB Full Color. Planar configuration of data. 8 Bit per color channel.
///
- RgbPlanar,
+ Rgb888Planar,
+
+ ///
+ /// RGB Full Color. Planar configuration of data. 16 Bit per color channel.
+ ///
+ Rgb161616Planar,
+
+ ///
+ /// RGB Full Color. Planar configuration of data. 24 Bit per color channel.
+ ///
+ Rgb242424Planar,
+
+ ///
+ /// RGB Full Color. Planar configuration of data. 32 Bit per color channel.
+ ///
+ Rgb323232Planar,
}
}
diff --git a/src/ImageSharp/Formats/Tiff/TiffDecoderOptionsParser.cs b/src/ImageSharp/Formats/Tiff/TiffDecoderOptionsParser.cs
index ceb2a3c94b..dadf8d707a 100644
--- a/src/ImageSharp/Formats/Tiff/TiffDecoderOptionsParser.cs
+++ b/src/ImageSharp/Formats/Tiff/TiffDecoderOptionsParser.cs
@@ -270,7 +270,22 @@ namespace SixLabors.ImageSharp.Formats.Tiff
}
else
{
- options.ColorType = TiffColorType.RgbPlanar;
+ ushort bitsPerChannel = options.BitsPerSample.Channel0;
+ switch (bitsPerChannel)
+ {
+ case 32:
+ options.ColorType = TiffColorType.Rgb323232Planar;
+ break;
+ case 24:
+ options.ColorType = TiffColorType.Rgb242424Planar;
+ break;
+ case 16:
+ options.ColorType = TiffColorType.Rgb161616Planar;
+ break;
+ default:
+ options.ColorType = TiffColorType.Rgb888Planar;
+ break;
+ }
}
break;
diff --git a/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs
index 19237b4b9e..8001701ff5 100644
--- a/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs
+++ b/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs
@@ -201,6 +201,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff
[Theory]
[WithFile(FlowerRgb323232Contiguous, PixelTypes.Rgba32)]
+ [WithFile(FlowerRgb323232Planar, PixelTypes.Rgba32)]
public void TiffDecoder_CanDecode_96Bit(TestImageProvider provider)
where TPixel : unmanaged, IPixel => TestTiffDecoder(provider);
diff --git a/tests/ImageSharp.Tests/TestImages.cs b/tests/ImageSharp.Tests/TestImages.cs
index bb22cbcc82..c5dec8efcb 100644
--- a/tests/ImageSharp.Tests/TestImages.cs
+++ b/tests/ImageSharp.Tests/TestImages.cs
@@ -562,6 +562,7 @@ namespace SixLabors.ImageSharp.Tests
public const string Rgb4BitPalette = "Tiff/bike_colorpalette_4bit.tiff";
public const string RgbPaletteDeflate = "Tiff/rgb_palette_deflate.tiff";
public const string FlowerRgb323232Contiguous = "Tiff/flower-rgb-contig-32.tiff";
+ public const string FlowerRgb323232Planar = "Tiff/flower-rgb-planar-32.tiff";
public const string FlowerRgb242424Planar = "Tiff/flower-rgb-planar-24.tiff";
public const string FlowerRgb242424PlanarLittleEndian = "Tiff/flower-rgb-planar-24_lsb.tiff";
public const string FlowerRgb242424Contiguous = "Tiff/flower-rgb-contig-24.tiff";
diff --git a/tests/Images/Input/Tiff/flower-rgb-planar-32.tiff b/tests/Images/Input/Tiff/flower-rgb-planar-32.tiff
new file mode 100644
index 0000000000..a84b4ab37f
--- /dev/null
+++ b/tests/Images/Input/Tiff/flower-rgb-planar-32.tiff
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:a718ae37d6d7a5bb5702cc75350f6feec3e9cdcd7e22aaa4753c7fe9c2db9aae
+size 38035