Browse Source

Add support for decoding tiff's with 32bit float gray pixel data with min is black

pull/1727/head
Brian Popow 5 years ago
parent
commit
9d6b7a6204
  1. 69
      src/ImageSharp/Formats/Tiff/PhotometricInterpretation/BlackIsZero32FloatTiffColor{TPixel}.cs
  2. 1
      src/ImageSharp/Formats/Tiff/PhotometricInterpretation/BlackIsZero32TiffColor{TPixel}.cs
  3. 1
      src/ImageSharp/Formats/Tiff/PhotometricInterpretation/RgbFloat323232TiffColor{TPixel}.cs
  4. 5
      src/ImageSharp/Formats/Tiff/PhotometricInterpretation/TiffColorDecoderFactory{TPixel}.cs
  5. 5
      src/ImageSharp/Formats/Tiff/PhotometricInterpretation/TiffColorType.cs
  6. 18
      src/ImageSharp/Formats/Tiff/TiffDecoderOptionsParser.cs
  7. 11
      tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs
  8. 2
      tests/ImageSharp.Tests/TestImages.cs
  9. 3
      tests/Images/Input/Tiff/flower-minisblack-float32_lsb.tiff
  10. 3
      tests/Images/Input/Tiff/flower-minisblack-float32_msb.tiff

69
src/ImageSharp/Formats/Tiff/PhotometricInterpretation/BlackIsZero32FloatTiffColor{TPixel}.cs

@ -0,0 +1,69 @@
// Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0.
using System;
using System.Numerics;
using SixLabors.ImageSharp.Formats.Tiff.Utils;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
{
/// <summary>
/// Implements the 'BlackIsZero' photometric interpretation for 32-bit float grayscale images.
/// </summary>
internal class BlackIsZero32FloatTiffColor<TPixel> : TiffBaseColorDecoder<TPixel>
where TPixel : unmanaged, IPixel<TPixel>
{
private readonly bool isBigEndian;
/// <summary>
/// Initializes a new instance of the <see cref="BlackIsZero32FloatTiffColor{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 BlackIsZero32FloatTiffColor(bool isBigEndian) => this.isBigEndian = isBigEndian;
/// <inheritdoc/>
public override void Decode(ReadOnlySpan<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);
byte[] buffer = new byte[4];
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++)
{
data.Slice(offset, 4).CopyTo(buffer);
Array.Reverse(buffer);
float intensity = BitConverter.ToSingle(buffer, 0);
offset += 4;
var colorVector = new Vector4(intensity, intensity, intensity, 1.0f);
color.FromVector4(colorVector);
pixelRow[x] = color;
}
}
else
{
for (int x = 0; x < pixelRow.Length; x++)
{
data.Slice(offset, 4).CopyTo(buffer);
float intensity = BitConverter.ToSingle(buffer, 0);
offset += 4;
var colorVector = new Vector4(intensity, intensity, intensity, 1.0f);
color.FromVector4(colorVector);
pixelRow[x] = color;
}
}
}
}
}
}

1
src/ImageSharp/Formats/Tiff/PhotometricInterpretation/BlackIsZero32TiffColor{TPixel}.cs

@ -2,7 +2,6 @@
// Licensed under the Apache License, Version 2.0.
using System;
using System.Numerics;
using SixLabors.ImageSharp.Formats.Tiff.Utils;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;

1
src/ImageSharp/Formats/Tiff/PhotometricInterpretation/RgbFloat323232TiffColor{TPixel}.cs

@ -57,7 +57,6 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
offset += 4;
var colorVector = new Vector4(r, g, b, 1.0f);
Array.Reverse(buffer);
color.FromVector4(colorVector);
pixelRow[x] = color;
}

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

@ -82,6 +82,11 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
DebugGuard.IsTrue(colorMap == null, "colorMap");
return new BlackIsZero32TiffColor<TPixel>(byteOrder == ByteOrder.BigEndian);
case TiffColorType.BlackIsZero32Float:
DebugGuard.IsTrue(bitsPerSample.Channels == 1 && bitsPerSample.Channel0 == 32, "bitsPerSample");
DebugGuard.IsTrue(colorMap == null, "colorMap");
return new BlackIsZero32FloatTiffColor<TPixel>(byteOrder == ByteOrder.BigEndian);
case TiffColorType.Rgb:
DebugGuard.IsTrue(colorMap == null, "colorMap");
return new RgbTiffColor<TPixel>(bitsPerSample);

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

@ -43,6 +43,11 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
/// </summary>
BlackIsZero32,
/// <summary>
/// Grayscale: 0 is imaged as black. The maximum value is imaged as white. Pixel data is 32-bit float.
/// </summary>
BlackIsZero32Float,
/// <summary>
/// Grayscale: 0 is imaged as white. The maximum value is imaged as black.
/// </summary>

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

@ -177,6 +177,12 @@ namespace SixLabors.ImageSharp.Formats.Tiff
{
case 32:
{
if (options.SampleFormat == TiffSampleFormat.Float)
{
options.ColorType = TiffColorType.BlackIsZero32Float;
return;
}
options.ColorType = TiffColorType.BlackIsZero32;
break;
}
@ -234,18 +240,18 @@ namespace SixLabors.ImageSharp.Formats.Tiff
TiffThrowHelper.ThrowNotSupported("Only BitsPerSample with equal bits per channel are supported.");
}
if (options.SampleFormat == TiffSampleFormat.Float)
{
options.ColorType = TiffColorType.RgbFloat323232;
return;
}
if (options.PlanarConfiguration == TiffPlanarConfiguration.Chunky)
{
ushort bitsPerChannel = options.BitsPerSample.Channel0;
switch (bitsPerChannel)
{
case 32:
if (options.SampleFormat == TiffSampleFormat.Float)
{
options.ColorType = TiffColorType.RgbFloat323232;
return;
}
options.ColorType = TiffColorType.Rgb323232;
break;

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

@ -248,6 +248,17 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff
image.DebugSave(provider);
}
[Theory]
[WithFile(Flower32BitFloatGray, PixelTypes.Rgba32)]
[WithFile(Flower32BitFloatGrayLittleEndian, PixelTypes.Rgba32)]
public void TiffDecoder_CanDecode_Float_96Bit_Gray<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel>
{
// Note: because the MagickReferenceDecoder fails to load the image, we only debug save them.
using Image<TPixel> image = provider.GetImage();
image.DebugSave(provider);
}
[Theory]
[WithFile(GrayscaleDeflateMultistrip, PixelTypes.Rgba32)]
[WithFile(RgbDeflateMultistrip, PixelTypes.Rgba32)]

2
tests/ImageSharp.Tests/TestImages.cs

@ -605,6 +605,8 @@ namespace SixLabors.ImageSharp.Tests
public const string Flower24BitGrayLittleEndian = "Tiff/flower-minisblack-24_lsb.tiff";
public const string Flower32BitGray = "Tiff/flower-minisblack-32.tiff";
public const string Flower32BitGrayLittleEndian = "Tiff/flower-minisblack-32_lsb.tiff";
public const string Flower32BitFloatGray = "Tiff/flower-minisblack-float32_msb.tiff";
public const string Flower32BitFloatGrayLittleEndian = "Tiff/flower-minisblack-float32_lsb.tiff";
public const string Flower32BitGrayMinIsWhite = "Tiff/flower-miniswhite-32.tiff";
public const string Flower32BitGrayMinIsWhiteLittleEndian = "Tiff/flower-miniswhite-32_lsb.tiff";

3
tests/Images/Input/Tiff/flower-minisblack-float32_lsb.tiff

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:af82e07e6298082c91d60a97acb29b67ecabf386bc14371fcb698b248cfd3b40
size 12814

3
tests/Images/Input/Tiff/flower-minisblack-float32_msb.tiff

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:5c918b8aa9968c03c12d85b3bcacd35ae57663a19f5490fc1c351521ed835f30
size 12814
Loading…
Cancel
Save