diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgb161616TiffColor{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgb161616TiffColor{TPixel}.cs
index b0106cc096..89cf1cb48e 100644
--- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgb161616TiffColor{TPixel}.cs
+++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgb161616TiffColor{TPixel}.cs
@@ -2,7 +2,6 @@
// Licensed under the Apache License, Version 2.0.
using System;
-using System.Buffers.Binary;
using SixLabors.ImageSharp.Formats.Tiff.Utils;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgb16PlanarTiffColor{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgb16PlanarTiffColor{TPixel}.cs
new file mode 100644
index 0000000000..75b0b3a8b6
--- /dev/null
+++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgb16PlanarTiffColor{TPixel}.cs
@@ -0,0 +1,53 @@
+// Copyright (c) Six Labors.
+// Licensed under the Apache License, Version 2.0.
+
+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 all 16 bit.
+ ///
+ internal class Rgb16PlanarTiffColor : 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 Rgb16PlanarTiffColor(bool isBigEndian) => this.isBigEndian = isBigEndian;
+
+ ///
+ public override void Decode(IMemoryOwner[] data, Buffer2D pixels, int left, int top, int width, int height)
+ {
+ var color = default(TPixel);
+
+ System.Span redData = data[0].GetSpan();
+ System.Span greenData = data[1].GetSpan();
+ System.Span blueData = data[2].GetSpan();
+
+ int offset = 0;
+ var rgba = default(Rgba64);
+ for (int y = top; y < top + height; y++)
+ {
+ for (int x = left; x < left + width; x++)
+ {
+ ulong r = TiffUtils.ConvertToShort(redData.Slice(offset, 2), this.isBigEndian);
+ ulong g = TiffUtils.ConvertToShort(greenData.Slice(offset, 2), this.isBigEndian);
+ ulong b = TiffUtils.ConvertToShort(blueData.Slice(offset, 2), this.isBigEndian);
+
+ offset += 2;
+
+ rgba.PackedValue = r | (g << 16) | (b << 32) | (0xfffful << 48);
+ color.FromRgba64(rgba);
+ pixels[x, y] = color;
+ }
+ }
+ }
+ }
+}
diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/RgbPlanarTiffColor{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/RgbPlanarTiffColor{TPixel}.cs
index 3400bd65d8..5df68ee59b 100644
--- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/RgbPlanarTiffColor{TPixel}.cs
+++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/RgbPlanarTiffColor{TPixel}.cs
@@ -12,7 +12,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
///
/// Implements the 'RGB' photometric interpretation with 'Planar' layout (for all bit depths).
///
- internal class RgbPlanarTiffColor
+ internal class RgbPlanarTiffColor : TiffBasePlanarColorDecoder
where TPixel : unmanaged, IPixel
{
private readonly float rFactor;
@@ -47,7 +47,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
/// The y-coordinate of the top of the image block.
/// The width of the image block.
/// The height of the image block.
- public void Decode(IMemoryOwner[] data, Buffer2D pixels, int left, int top, int width, int height)
+ public override void Decode(IMemoryOwner[] data, Buffer2D pixels, int left, int top, int width, int height)
{
var color = default(TPixel);
diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/TiffBasePlanarColorDecoder{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/TiffBasePlanarColorDecoder{TPixel}.cs
new file mode 100644
index 0000000000..57d8588cee
--- /dev/null
+++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/TiffBasePlanarColorDecoder{TPixel}.cs
@@ -0,0 +1,28 @@
+// Copyright (c) Six Labors.
+// Licensed under the Apache License, Version 2.0.
+
+using System.Buffers;
+using SixLabors.ImageSharp.Memory;
+using SixLabors.ImageSharp.PixelFormats;
+
+namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
+{
+ ///
+ /// The base class for planar color decoders.
+ ///
+ /// The pixel format.
+ internal abstract class TiffBasePlanarColorDecoder
+ where TPixel : unmanaged, IPixel
+ {
+ ///
+ /// Decodes source raw pixel data using the current photometric interpretation.
+ ///
+ /// The buffers to read image data from.
+ /// The image buffer to write pixels to.
+ /// The x-coordinate of the left-hand side of the image block.
+ /// The y-coordinate of the top of the image block.
+ /// The width of the image block.
+ /// The height of the image block.
+ public abstract void Decode(IMemoryOwner[] data, Buffer2D pixels, int left, int top, int width, int height);
+ }
+}
diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/TiffColorDecoderFactory{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/TiffColorDecoderFactory{TPixel}.cs
index 25b441ab0a..0c93998c48 100644
--- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/TiffColorDecoderFactory{TPixel}.cs
+++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/TiffColorDecoderFactory{TPixel}.cs
@@ -145,12 +145,17 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
}
}
- public static RgbPlanarTiffColor CreatePlanar(TiffColorType colorType, TiffBitsPerSample bitsPerSample, ushort[] colorMap)
+ public static TiffBasePlanarColorDecoder CreatePlanar(TiffColorType colorType, TiffBitsPerSample bitsPerSample, ushort[] colorMap, ByteOrder byteOrder)
{
switch (colorType)
{
case TiffColorType.RgbPlanar:
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);
default:
diff --git a/src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs b/src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs
index 484e182c59..72f2336a8c 100644
--- a/src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs
+++ b/src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs
@@ -266,7 +266,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff
using TiffBaseDecompressor decompressor = TiffDecompressorsFactory.Create(this.CompressionType, this.memoryAllocator, this.PhotometricInterpretation, frame.Width, bitsPerPixel, this.Predictor, this.FaxCompressionOptions);
- RgbPlanarTiffColor colorDecoder = TiffColorDecoderFactory.CreatePlanar(this.ColorType, this.BitsPerSample, this.ColorMap);
+ TiffBasePlanarColorDecoder colorDecoder = TiffColorDecoderFactory.CreatePlanar(this.ColorType, this.BitsPerSample, this.ColorMap, this.byteOrder);
for (int i = 0; i < stripsPerPlane; i++)
{
diff --git a/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs
index 9346c4bfd6..105b871dae 100644
--- a/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs
+++ b/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs
@@ -166,6 +166,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff
[Theory]
[WithFile(FlowerRgb161616Contiguous, PixelTypes.Rgba32)]
[WithFile(FlowerRgb161616Planar, PixelTypes.Rgba32)]
+ [WithFile(FlowerRgb161616PlanarLittleEndian, PixelTypes.Rgba32)]
[WithFile(Issues1716Rgb161616BitLittleEndian, PixelTypes.Rgba32)]
public void TiffDecoder_CanDecode_48Bit(TestImageProvider provider)
where TPixel : unmanaged, IPixel => TestTiffDecoder(provider);
diff --git a/tests/ImageSharp.Tests/TestImages.cs b/tests/ImageSharp.Tests/TestImages.cs
index 212bb94e3c..e0ae8f63d2 100644
--- a/tests/ImageSharp.Tests/TestImages.cs
+++ b/tests/ImageSharp.Tests/TestImages.cs
@@ -563,6 +563,7 @@ namespace SixLabors.ImageSharp.Tests
public const string RgbPaletteDeflate = "Tiff/rgb_palette_deflate.tiff";
public const string FlowerRgb161616Contiguous = "Tiff/flower-rgb-contig-16.tiff";
public const string FlowerRgb161616Planar = "Tiff/flower-rgb-planar-16.tiff";
+ public const string FlowerRgb161616PlanarLittleEndian = "Tiff/flower-rgb-planar-16_lsb.tiff";
public const string FlowerRgb141414Contiguous = "Tiff/flower-rgb-contig-14.tiff";
public const string FlowerRgb141414Planar = "Tiff/flower-rgb-planar-14.tiff";
public const string FlowerRgb101010Contiguous = "Tiff/flower-rgb-contig-10.tiff";
diff --git a/tests/Images/Input/Tiff/flower-rgb-planar-16_lsb.tiff b/tests/Images/Input/Tiff/flower-rgb-planar-16_lsb.tiff
new file mode 100644
index 0000000000..425ea42efd
--- /dev/null
+++ b/tests/Images/Input/Tiff/flower-rgb-planar-16_lsb.tiff
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:46a60552a7ff37f2c16c43e030e7180872af712f5d9c9c7673e2547049af3da9
+size 19168