Browse Source

Add support for decoding 32bit per channel color tiff with planar pixel data

pull/1724/head
Brian Popow 5 years ago
parent
commit
8c7ee589e6
  1. 71
      src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgb32PlanarTiffColor{TPixel}.cs
  2. 22
      src/ImageSharp/Formats/Tiff/PhotometricInterpretation/TiffColorDecoderFactory{TPixel}.cs
  3. 19
      src/ImageSharp/Formats/Tiff/PhotometricInterpretation/TiffColorType.cs
  4. 17
      src/ImageSharp/Formats/Tiff/TiffDecoderOptionsParser.cs
  5. 1
      tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs
  6. 1
      tests/ImageSharp.Tests/TestImages.cs
  7. 3
      tests/Images/Input/Tiff/flower-rgb-planar-32.tiff

71
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
{
/// <summary>
/// Implements the 'RGB' photometric interpretation with 'Planar' layout for each color channel with 32 bit.
/// </summary>
internal class Rgb32PlanarTiffColor<TPixel> : TiffBasePlanarColorDecoder<TPixel>
where TPixel : unmanaged, IPixel<TPixel>
{
private readonly bool isBigEndian;
/// <summary>
/// Initializes a new instance of the <see cref="Rgb32PlanarTiffColor{TPixel}" /> class.
/// </summary>
/// <param name="isBigEndian">if set to <c>true</c> decodes the pixel data as big endian, otherwise as little endian.</param>
public Rgb32PlanarTiffColor(bool isBigEndian) => this.isBigEndian = isBigEndian;
/// <inheritdoc/>
public override void Decode(IMemoryOwner<byte>[] data, Buffer2D<TPixel> 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<byte> redData = data[0].GetSpan();
Span<byte> greenData = data[1].GetSpan();
Span<byte> blueData = data[2].GetSpan();
int offset = 0;
for (int y = top; y < top + height; y++)
{
Span<TPixel> 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);
}
}
}
}
}
}

22
src/ImageSharp/Formats/Tiff/PhotometricInterpretation/TiffColorDecoderFactory{TPixel}.cs

@ -189,19 +189,21 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
{ {
switch (colorType) switch (colorType)
{ {
case TiffColorType.RgbPlanar: case TiffColorType.Rgb888Planar:
DebugGuard.IsTrue(colorMap == null, "colorMap"); DebugGuard.IsTrue(colorMap == null, "colorMap");
if (bitsPerSample.Channel0 == 16 && bitsPerSample.Channel1 == 16 && bitsPerSample.Channel2 == 16) return new RgbPlanarTiffColor<TPixel>(bitsPerSample);
{
return new Rgb16PlanarTiffColor<TPixel>(byteOrder == ByteOrder.BigEndian);
}
if (bitsPerSample.Channel0 == 24 && bitsPerSample.Channel1 == 24 && bitsPerSample.Channel2 == 24) case TiffColorType.Rgb161616Planar:
{ DebugGuard.IsTrue(colorMap == null, "colorMap");
return new Rgb24PlanarTiffColor<TPixel>(byteOrder == ByteOrder.BigEndian); return new Rgb16PlanarTiffColor<TPixel>(byteOrder == ByteOrder.BigEndian);
}
return new RgbPlanarTiffColor<TPixel>(bitsPerSample); case TiffColorType.Rgb242424Planar:
DebugGuard.IsTrue(colorMap == null, "colorMap");
return new Rgb24PlanarTiffColor<TPixel>(byteOrder == ByteOrder.BigEndian);
case TiffColorType.Rgb323232Planar:
DebugGuard.IsTrue(colorMap == null, "colorMap");
return new Rgb32PlanarTiffColor<TPixel>(byteOrder == ByteOrder.BigEndian);
default: default:
throw TiffThrowHelper.InvalidColorType(colorType.ToString()); throw TiffThrowHelper.InvalidColorType(colorType.ToString());

19
src/ImageSharp/Formats/Tiff/PhotometricInterpretation/TiffColorType.cs

@ -134,8 +134,23 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
Rgb323232, Rgb323232,
/// <summary> /// <summary>
/// RGB Full Color. Planar configuration of data. /// RGB Full Color. Planar configuration of data. 8 Bit per color channel.
/// </summary> /// </summary>
RgbPlanar, Rgb888Planar,
/// <summary>
/// RGB Full Color. Planar configuration of data. 16 Bit per color channel.
/// </summary>
Rgb161616Planar,
/// <summary>
/// RGB Full Color. Planar configuration of data. 24 Bit per color channel.
/// </summary>
Rgb242424Planar,
/// <summary>
/// RGB Full Color. Planar configuration of data. 32 Bit per color channel.
/// </summary>
Rgb323232Planar,
} }
} }

17
src/ImageSharp/Formats/Tiff/TiffDecoderOptionsParser.cs

@ -270,7 +270,22 @@ namespace SixLabors.ImageSharp.Formats.Tiff
} }
else 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; break;

1
tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs

@ -201,6 +201,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff
[Theory] [Theory]
[WithFile(FlowerRgb323232Contiguous, PixelTypes.Rgba32)] [WithFile(FlowerRgb323232Contiguous, PixelTypes.Rgba32)]
[WithFile(FlowerRgb323232Planar, PixelTypes.Rgba32)]
public void TiffDecoder_CanDecode_96Bit<TPixel>(TestImageProvider<TPixel> provider) public void TiffDecoder_CanDecode_96Bit<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel> => TestTiffDecoder(provider); where TPixel : unmanaged, IPixel<TPixel> => TestTiffDecoder(provider);

1
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 Rgb4BitPalette = "Tiff/bike_colorpalette_4bit.tiff";
public const string RgbPaletteDeflate = "Tiff/rgb_palette_deflate.tiff"; public const string RgbPaletteDeflate = "Tiff/rgb_palette_deflate.tiff";
public const string FlowerRgb323232Contiguous = "Tiff/flower-rgb-contig-32.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 FlowerRgb242424Planar = "Tiff/flower-rgb-planar-24.tiff";
public const string FlowerRgb242424PlanarLittleEndian = "Tiff/flower-rgb-planar-24_lsb.tiff"; public const string FlowerRgb242424PlanarLittleEndian = "Tiff/flower-rgb-planar-24_lsb.tiff";
public const string FlowerRgb242424Contiguous = "Tiff/flower-rgb-contig-24.tiff"; public const string FlowerRgb242424Contiguous = "Tiff/flower-rgb-contig-24.tiff";

3
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
Loading…
Cancel
Save