Browse Source

Add support for decoding Tiff images with associated alpha data

pull/2062/head
Brian Popow 4 years ago
parent
commit
5d894d4f2c
  1. 42
      src/ImageSharp/Formats/Tiff/Constants/TiffCompression.cs
  2. 2
      src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgb161616TiffColor{TPixel}.cs
  3. 4
      src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgb16PlanarTiffColor{TPixel}.cs
  4. 24
      src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba16161616TiffColor{TPixel}.cs
  5. 22
      src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba16PlanarTiffColor{TPixel}.cs
  6. 20
      src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba24242424TiffColor{TPixel}.cs
  7. 18
      src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba24PlanarTiffColor{TPixel}.cs
  8. 19
      src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba32323232TiffColor{TPixel}.cs
  9. 18
      src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba32PlanarTiffColor{TPixel}.cs
  10. 24
      src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba8888TiffColor{TPixel}.cs
  11. 18
      src/ImageSharp/Formats/Tiff/PhotometricInterpretation/RgbaPlanarTiffColor{TPixel}.cs
  12. 20
      src/ImageSharp/Formats/Tiff/PhotometricInterpretation/RgbaTiffColor{TPixel}.cs
  13. 34
      src/ImageSharp/Formats/Tiff/PhotometricInterpretation/TiffColorDecoderFactory{TPixel}.cs
  14. 13
      src/ImageSharp/Formats/Tiff/README.md
  15. 6
      src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs
  16. 6
      src/ImageSharp/Formats/Tiff/TiffDecoderOptionsParser.cs
  17. 48
      src/ImageSharp/Formats/Tiff/Utils/TiffUtils.cs
  18. 46
      tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs
  19. 13
      tests/ImageSharp.Tests/TestImages.cs
  20. 3
      tests/Images/Input/Tiff/RgbaAlpha8bit.tiff
  21. 3
      tests/Images/Input/Tiff/RgbaAssociatedAlpha10bit_lsb.tiff
  22. 3
      tests/Images/Input/Tiff/RgbaAssociatedAlpha10bit_msb.tiff
  23. 3
      tests/Images/Input/Tiff/RgbaAssociatedAlpha12bit_lsb.tiff
  24. 3
      tests/Images/Input/Tiff/RgbaAssociatedAlpha12bit_msb.tiff
  25. 3
      tests/Images/Input/Tiff/RgbaAssociatedAlpha14bit_lsb.tiff
  26. 3
      tests/Images/Input/Tiff/RgbaAssociatedAlpha14bit_msb.tiff
  27. 3
      tests/Images/Input/Tiff/RgbaAssociatedAlpha16bit_lsb.tiff
  28. 3
      tests/Images/Input/Tiff/RgbaAssociatedAlpha16bit_msb.tiff
  29. 3
      tests/Images/Input/Tiff/RgbaAssociatedAlpha3bit.tiff
  30. 3
      tests/Images/Input/Tiff/RgbaAssociatedAlpha4bit.tiff
  31. 3
      tests/Images/Input/Tiff/RgbaAssociatedAlpha5bit.tiff
  32. 3
      tests/Images/Input/Tiff/RgbaAssociatedAlpha6bit.tiff

42
src/ImageSharp/Formats/Tiff/Constants/TiffCompression.cs

@ -23,11 +23,6 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Constants
/// </summary>
Ccitt1D = 2,
/// <summary>
/// PackBits compression
/// </summary>
PackBits = 32773,
/// <summary>
/// T4-encoding: CCITT T.4 bi-level encoding (see Section 11 of the TIFF 6.0 specification).
/// </summary>
@ -65,27 +60,48 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Constants
Deflate = 8,
/// <summary>
/// Deflate compression - old.
/// ITU-T Rec. T.82 coding, applying ITU-T Rec. T.85 (JBIG) (see RFC2301).
///
/// Note: The TIFF encoder does not support this compression and will default to use no compression instead,
/// Note: The TIFF encoder does not yet support this compression and will default to use no compression instead,
/// if this is chosen.
/// </summary>
OldDeflate = 32946,
ItuTRecT82 = 9,
/// <summary>
/// ITU-T Rec. T.82 coding, applying ITU-T Rec. T.85 (JBIG) (see RFC2301).
/// ITU-T Rec. T.43 representation, using ITU-T Rec. T.82 (JBIG) (see RFC2301).
///
/// Note: The TIFF encoder does not yet support this compression and will default to use no compression instead,
/// if this is chosen.
/// </summary>
ItuTRecT82 = 9,
ItuTRecT43 = 10,
/// <summary>
/// ITU-T Rec. T.43 representation, using ITU-T Rec. T.82 (JBIG) (see RFC2301).
/// NeXT 2-bit Grey Scale compression algorithm.
///
/// Note: The TIFF encoder does not yet support this compression and will default to use no compression instead,
/// Note: The TIFF encoder does not support this compression and will default to use no compression instead,
/// if this is chosen.
/// </summary>
NeXT = 32766,
/// <summary>
/// PackBits compression.
/// </summary>
PackBits = 32773,
/// <summary>
/// ThunderScan 4-bit compression.
///
/// Note: The TIFF encoder does not support this compression and will default to use no compression instead,
/// if this is chosen.
/// </summary>
ItuTRecT43 = 10
ThunderScan = 32809,
/// <summary>
/// Deflate compression - old.
///
/// Note: The TIFF encoder does not support this compression and will default to use no compression instead,
/// if this is chosen.
/// </summary>
OldDeflate = 32946,
}
}

2
src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgb161616TiffColor{TPixel}.cs

@ -55,7 +55,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
ulong b = TiffUtils.ConvertToUShortBigEndian(data.Slice(offset, 2));
offset += 2;
pixelRow[x] = TiffUtils.ColorFromRgba64(rgba, r, g, b, color);
pixelRow[x] = TiffUtils.ColorFromRgb64(rgba, r, g, b, color);
}
}
else

4
src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgb16PlanarTiffColor{TPixel}.cs

@ -50,7 +50,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
offset += 2;
pixelRow[x] = TiffUtils.ColorFromRgba64(rgba, r, g, b, color);
pixelRow[x] = TiffUtils.ColorFromRgb64(rgba, r, g, b, color);
}
}
else
@ -63,7 +63,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
offset += 2;
pixelRow[x] = TiffUtils.ColorFromRgba64(rgba, r, g, b, color);
pixelRow[x] = TiffUtils.ColorFromRgb64(rgba, r, g, b, color);
}
}
}

24
src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba16161616TiffColor{TPixel}.cs

@ -2,6 +2,7 @@
// 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;
@ -18,15 +19,23 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
private readonly Configuration configuration;
private readonly MemoryAllocator memoryAllocator;
private readonly TiffExtraSampleType? extraSamplesType;
/// <summary>
/// Initializes a new instance of the <see cref="Rgba16161616TiffColor{TPixel}" /> class.
/// </summary>
/// <param name="configuration">The configuration.</param>
/// <param name="memoryAllocator">The memory allocator.</param>
/// <param name="isBigEndian">if set to <c>true</c> decodes the pixel data as big endian, otherwise as little endian.</param>
public Rgba16161616TiffColor(Configuration configuration, bool isBigEndian)
/// <param name="extraSamplesType">The type of the extra samples.</param>
public Rgba16161616TiffColor(Configuration configuration, MemoryAllocator memoryAllocator, TiffExtraSampleType? extraSamplesType, bool isBigEndian)
{
this.configuration = configuration;
this.isBigEndian = isBigEndian;
this.memoryAllocator = memoryAllocator;
this.extraSamplesType = extraSamplesType;
}
/// <inheritdoc/>
@ -38,8 +47,11 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
var color = default(TPixel);
color.FromVector4(TiffUtils.Vector4Default);
bool hasAssociatedAlpha = this.extraSamplesType.HasValue && this.extraSamplesType == TiffExtraSampleType.AssociatedAlphaData;
int offset = 0;
System.Buffers.IMemoryOwner<Vector4> vectors = hasAssociatedAlpha ? this.memoryAllocator.Allocate<Vector4>(width) : null;
Span<Vector4> vectorsSpan = hasAssociatedAlpha ? vectors.GetSpan() : Span<Vector4>.Empty;
for (int y = top; y < top + height; y++)
{
Span<TPixel> pixelRow = pixels.DangerousGetRowSpan(y).Slice(left, width);
@ -57,7 +69,9 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
ulong a = TiffUtils.ConvertToUShortBigEndian(data.Slice(offset, 2));
offset += 2;
pixelRow[x] = TiffUtils.ColorFromRgba64(rgba, r, g, b, a, color);
pixelRow[x] = hasAssociatedAlpha ?
TiffUtils.ColorFromRgba64Premultiplied(rgba, r, g, b, a, color) :
TiffUtils.ColorFromRgba64(rgba, r, g, b, a, color);
}
}
else
@ -69,6 +83,12 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
pixelRow,
pixelRow.Length);
if (hasAssociatedAlpha)
{
PixelOperations<TPixel>.Instance.ToVector4(this.configuration, pixelRow, vectorsSpan);
TiffUtils.UnPremultiplyRow(vectorsSpan, pixelRow, color);
}
offset += byteCount;
}
}

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

@ -17,11 +17,18 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
{
private readonly bool isBigEndian;
private readonly TiffExtraSampleType? extraSamplesType;
/// <summary>
/// Initializes a new instance of the <see cref="Rgba16PlanarTiffColor{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 Rgba16PlanarTiffColor(bool isBigEndian) => this.isBigEndian = isBigEndian;
/// <param name="extraSamplesType">The extra samples type.</param>
/// <param name="isBigEndian">If set to <c>true</c> decodes the pixel data as big endian, otherwise as little endian.</param>
public Rgba16PlanarTiffColor(TiffExtraSampleType? extraSamplesType, bool isBigEndian)
{
this.extraSamplesType = extraSamplesType;
this.isBigEndian = isBigEndian;
}
/// <inheritdoc/>
public override void Decode(IMemoryOwner<byte>[] data, Buffer2D<TPixel> pixels, int left, int top, int width, int height)
@ -37,6 +44,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
Span<byte> blueData = data[2].GetSpan();
Span<byte> alphaData = data[3].GetSpan();
bool hasAssociatedAlpha = this.extraSamplesType.HasValue && this.extraSamplesType == TiffExtraSampleType.AssociatedAlphaData;
int offset = 0;
for (int y = top; y < top + height; y++)
{
@ -52,7 +60,9 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
offset += 2;
pixelRow[x] = TiffUtils.ColorFromRgba64(rgba, r, g, b, a, color);
pixelRow[x] = hasAssociatedAlpha ?
TiffUtils.ColorFromRgba64Premultiplied(rgba, r, g, b, a, color) :
TiffUtils.ColorFromRgba64(rgba, r, g, b, a, color);
}
}
else
@ -62,11 +72,13 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
ulong r = TiffUtils.ConvertToUShortLittleEndian(redData.Slice(offset, 2));
ulong g = TiffUtils.ConvertToUShortLittleEndian(greenData.Slice(offset, 2));
ulong b = TiffUtils.ConvertToUShortLittleEndian(blueData.Slice(offset, 2));
ulong a = TiffUtils.ConvertToUShortBigEndian(alphaData.Slice(offset, 2));
ulong a = TiffUtils.ConvertToUShortLittleEndian(alphaData.Slice(offset, 2));
offset += 2;
pixelRow[x] = TiffUtils.ColorFromRgba64(rgba, r, g, b, a, color);
pixelRow[x] = hasAssociatedAlpha ?
TiffUtils.ColorFromRgba64Premultiplied(rgba, r, g, b, a, color) :
TiffUtils.ColorFromRgba64(rgba, r, g, b, a, color);
}
}
}

20
src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba24242424TiffColor{TPixel}.cs

@ -16,11 +16,18 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
{
private readonly bool isBigEndian;
private readonly TiffExtraSampleType? extraSamplesType;
/// <summary>
/// Initializes a new instance of the <see cref="Rgba24242424TiffColor{TPixel}" /> class.
/// </summary>
/// <param name="extraSamplesType">The type of the extra samples.</param>
/// <param name="isBigEndian">if set to <c>true</c> decodes the pixel data as big endian, otherwise as little endian.</param>
public Rgba24242424TiffColor(bool isBigEndian) => this.isBigEndian = isBigEndian;
public Rgba24242424TiffColor(TiffExtraSampleType? extraSamplesType, bool isBigEndian)
{
this.extraSamplesType = extraSamplesType;
this.isBigEndian = isBigEndian;
}
/// <inheritdoc/>
public override void Decode(ReadOnlySpan<byte> data, Buffer2D<TPixel> pixels, int left, int top, int width, int height)
@ -29,7 +36,10 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
// we define our own defaults as a workaround. See: https://github.com/dotnet/runtime/issues/55623
var color = default(TPixel);
color.FromVector4(TiffUtils.Vector4Default);
bool hasAssociatedAlpha = this.extraSamplesType.HasValue && this.extraSamplesType == TiffExtraSampleType.AssociatedAlphaData;
int offset = 0;
Span<byte> buffer = stackalloc byte[4];
int bufferStartIdx = this.isBigEndian ? 1 : 0;
@ -58,7 +68,9 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
ulong a = TiffUtils.ConvertToUIntBigEndian(buffer);
offset += 3;
pixelRow[x] = TiffUtils.ColorScaleTo24Bit(r, g, b, a, color);
pixelRow[x] = hasAssociatedAlpha ?
TiffUtils.ColorScaleTo24BitPremultiplied(r, g, b, a, color) :
TiffUtils.ColorScaleTo24Bit(r, g, b, a, color);
}
}
else
@ -81,7 +93,9 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
ulong a = TiffUtils.ConvertToUIntLittleEndian(buffer);
offset += 3;
pixelRow[x] = TiffUtils.ColorScaleTo24Bit(r, g, b, a, color);
pixelRow[x] = hasAssociatedAlpha ?
TiffUtils.ColorScaleTo24BitPremultiplied(r, g, b, a, color) :
TiffUtils.ColorScaleTo24Bit(r, g, b, a, color);
}
}
}

18
src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba24PlanarTiffColor{TPixel}.cs

@ -17,11 +17,18 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
{
private readonly bool isBigEndian;
private readonly TiffExtraSampleType? extraSamplesType;
/// <summary>
/// Initializes a new instance of the <see cref="Rgba24PlanarTiffColor{TPixel}" /> class.
/// </summary>
/// <param name="extraSamplesType">The extra samples type.</param>
/// <param name="isBigEndian">if set to <c>true</c> decodes the pixel data as big endian, otherwise as little endian.</param>
public Rgba24PlanarTiffColor(bool isBigEndian) => this.isBigEndian = isBigEndian;
public Rgba24PlanarTiffColor(TiffExtraSampleType? extraSamplesType, bool isBigEndian)
{
this.extraSamplesType = extraSamplesType;
this.isBigEndian = isBigEndian;
}
/// <inheritdoc/>
public override void Decode(IMemoryOwner<byte>[] data, Buffer2D<TPixel> pixels, int left, int top, int width, int height)
@ -39,6 +46,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
Span<byte> alphaData = data[3].GetSpan();
Span<byte> bufferSpan = buffer.Slice(bufferStartIdx);
bool hasAssociatedAlpha = this.extraSamplesType.HasValue && this.extraSamplesType == TiffExtraSampleType.AssociatedAlphaData;
int offset = 0;
for (int y = top; y < top + height; y++)
{
@ -58,7 +66,9 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
offset += 3;
pixelRow[x] = TiffUtils.ColorScaleTo24Bit(r, g, b, a, color);
pixelRow[x] = hasAssociatedAlpha ?
TiffUtils.ColorScaleTo24BitPremultiplied(r, g, b, a, color) :
TiffUtils.ColorScaleTo24Bit(r, g, b, a, color);
}
}
else
@ -76,7 +86,9 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
offset += 3;
pixelRow[x] = TiffUtils.ColorScaleTo24Bit(r, g, b, a, color);
pixelRow[x] = hasAssociatedAlpha ?
TiffUtils.ColorScaleTo24BitPremultiplied(r, g, b, a, color) :
TiffUtils.ColorScaleTo24Bit(r, g, b, a, color);
}
}
}

19
src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba32323232TiffColor{TPixel}.cs

@ -16,11 +16,18 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
{
private readonly bool isBigEndian;
private readonly TiffExtraSampleType? extraSamplesType;
/// <summary>
/// Initializes a new instance of the <see cref="Rgba32323232TiffColor{TPixel}" /> class.
/// </summary>
/// <param name="extraSamplesType">The type of the extra samples.</param>
/// <param name="isBigEndian">if set to <c>true</c> decodes the pixel data as big endian, otherwise as little endian.</param>
public Rgba32323232TiffColor(bool isBigEndian) => this.isBigEndian = isBigEndian;
public Rgba32323232TiffColor(TiffExtraSampleType? extraSamplesType, bool isBigEndian)
{
this.extraSamplesType = extraSamplesType;
this.isBigEndian = isBigEndian;
}
/// <inheritdoc/>
public override void Decode(ReadOnlySpan<byte> data, Buffer2D<TPixel> pixels, int left, int top, int width, int height)
@ -29,6 +36,8 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
// we define our own defaults as a workaround. See: https://github.com/dotnet/runtime/issues/55623
var color = default(TPixel);
color.FromVector4(TiffUtils.Vector4Default);
bool hasAssociatedAlpha = this.extraSamplesType.HasValue && this.extraSamplesType == TiffExtraSampleType.AssociatedAlphaData;
int offset = 0;
for (int y = top; y < top + height; y++)
@ -51,7 +60,9 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
ulong a = TiffUtils.ConvertToUIntBigEndian(data.Slice(offset, 4));
offset += 4;
pixelRow[x] = TiffUtils.ColorScaleTo32Bit(r, g, b, a, color);
pixelRow[x] = hasAssociatedAlpha ?
TiffUtils.ColorScaleTo32BitPremultiplied(r, g, b, a, color) :
TiffUtils.ColorScaleTo32Bit(r, g, b, a, color);
}
}
else
@ -70,7 +81,9 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
ulong a = TiffUtils.ConvertToUIntLittleEndian(data.Slice(offset, 4));
offset += 4;
pixelRow[x] = TiffUtils.ColorScaleTo32Bit(r, g, b, a, color);
pixelRow[x] = hasAssociatedAlpha ?
TiffUtils.ColorScaleTo32BitPremultiplied(r, g, b, a, color) :
TiffUtils.ColorScaleTo32Bit(r, g, b, a, color);
}
}
}

18
src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba32PlanarTiffColor{TPixel}.cs

@ -17,11 +17,18 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
{
private readonly bool isBigEndian;
private readonly TiffExtraSampleType? extraSamplesType;
/// <summary>
/// Initializes a new instance of the <see cref="Rgba32PlanarTiffColor{TPixel}" /> class.
/// </summary>
/// <param name="extraSamplesType">The extra samples type.</param>
/// <param name="isBigEndian">if set to <c>true</c> decodes the pixel data as big endian, otherwise as little endian.</param>
public Rgba32PlanarTiffColor(bool isBigEndian) => this.isBigEndian = isBigEndian;
public Rgba32PlanarTiffColor(TiffExtraSampleType? extraSamplesType, bool isBigEndian)
{
this.extraSamplesType = extraSamplesType;
this.isBigEndian = isBigEndian;
}
/// <inheritdoc/>
public override void Decode(IMemoryOwner<byte>[] data, Buffer2D<TPixel> pixels, int left, int top, int width, int height)
@ -36,6 +43,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
Span<byte> blueData = data[2].GetSpan();
Span<byte> alphaData = data[3].GetSpan();
bool hasAssociatedAlpha = this.extraSamplesType.HasValue && this.extraSamplesType == TiffExtraSampleType.AssociatedAlphaData;
int offset = 0;
for (int y = top; y < top + height; y++)
{
@ -51,7 +59,9 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
offset += 4;
pixelRow[x] = TiffUtils.ColorScaleTo32Bit(r, g, b, a, color);
pixelRow[x] = hasAssociatedAlpha ?
TiffUtils.ColorScaleTo32BitPremultiplied(r, g, b, a, color) :
TiffUtils.ColorScaleTo32Bit(r, g, b, a, color);
}
}
else
@ -65,7 +75,9 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
offset += 4;
pixelRow[x] = TiffUtils.ColorScaleTo32Bit(r, g, b, a, color);
pixelRow[x] = hasAssociatedAlpha ?
TiffUtils.ColorScaleTo32BitPremultiplied(r, g, b, a, color) :
TiffUtils.ColorScaleTo32Bit(r, g, b, a, color);
}
}
}

24
src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba8888TiffColor{TPixel}.cs

@ -2,6 +2,8 @@
// 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;
@ -15,13 +17,27 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
{
private readonly Configuration configuration;
public Rgba8888TiffColor(Configuration configuration) => this.configuration = configuration;
private readonly MemoryAllocator memoryAllocator;
private readonly TiffExtraSampleType? extraSamplesType;
public Rgba8888TiffColor(Configuration configuration, MemoryAllocator memoryAllocator, TiffExtraSampleType? extraSamplesType)
{
this.configuration = configuration;
this.memoryAllocator = memoryAllocator;
this.extraSamplesType = extraSamplesType;
}
/// <inheritdoc/>
public override void Decode(ReadOnlySpan<byte> data, Buffer2D<TPixel> pixels, int left, int top, int width, int height)
{
int offset = 0;
bool hasAssociatedAlpha = this.extraSamplesType.HasValue && this.extraSamplesType == TiffExtraSampleType.AssociatedAlphaData;
var color = default(TPixel);
color.FromVector4(TiffUtils.Vector4Default);
System.Buffers.IMemoryOwner<Vector4> vectors = hasAssociatedAlpha ? this.memoryAllocator.Allocate<Vector4>(width) : null;
Span<Vector4> vectorsSpan = hasAssociatedAlpha ? vectors.GetSpan() : Span<Vector4>.Empty;
for (int y = top; y < top + height; y++)
{
Span<TPixel> pixelRow = pixels.DangerousGetRowSpan(y).Slice(left, width);
@ -32,6 +48,12 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
pixelRow,
pixelRow.Length);
if (hasAssociatedAlpha)
{
PixelOperations<TPixel>.Instance.ToVector4(this.configuration, pixelRow, vectorsSpan);
TiffUtils.UnPremultiplyRow(vectorsSpan, pixelRow, color);
}
offset += byteCount;
}
}

18
src/ImageSharp/Formats/Tiff/PhotometricInterpretation/RgbaPlanarTiffColor{TPixel}.cs

@ -32,7 +32,9 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
private readonly ushort bitsPerSampleA;
public RgbaPlanarTiffColor(TiffBitsPerSample bitsPerSample)
private readonly TiffExtraSampleType? extraSampleType;
public RgbaPlanarTiffColor(TiffExtraSampleType? extraSampleType, TiffBitsPerSample bitsPerSample)
{
this.bitsPerSampleR = bitsPerSample.Channel0;
this.bitsPerSampleG = bitsPerSample.Channel1;
@ -43,6 +45,8 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
this.gFactor = (1 << this.bitsPerSampleG) - 1.0f;
this.bFactor = (1 << this.bitsPerSampleB) - 1.0f;
this.aFactor = (1 << this.bitsPerSampleA) - 1.0f;
this.extraSampleType = extraSampleType;
}
/// <summary>
@ -57,6 +61,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
public override void Decode(IMemoryOwner<byte>[] data, Buffer2D<TPixel> pixels, int left, int top, int width, int height)
{
var color = default(TPixel);
bool hasAssociatedAlpha = this.extraSampleType.HasValue && this.extraSampleType == TiffExtraSampleType.AssociatedAlphaData;
var rBitReader = new BitReader(data[0].GetSpan());
var gBitReader = new BitReader(data[1].GetSpan());
@ -73,7 +78,16 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
float b = bBitReader.ReadBits(this.bitsPerSampleB) / this.bFactor;
float a = aBitReader.ReadBits(this.bitsPerSampleA) / this.aFactor;
color.FromVector4(new Vector4(r, g, b, a));
var vec = new Vector4(r, g, b, a);
if (hasAssociatedAlpha)
{
color = TiffUtils.UnPremultiply(vec, color);
}
else
{
color.FromVector4(vec);
}
pixelRow[x] = color;
}

20
src/ImageSharp/Formats/Tiff/PhotometricInterpretation/RgbaTiffColor{TPixel}.cs

@ -31,7 +31,9 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
private readonly ushort bitsPerSampleA;
public RgbaTiffColor(TiffBitsPerSample bitsPerSample)
private readonly TiffExtraSampleType? extraSamplesType;
public RgbaTiffColor(TiffExtraSampleType? extraSampleType, TiffBitsPerSample bitsPerSample)
{
this.bitsPerSampleR = bitsPerSample.Channel0;
this.bitsPerSampleG = bitsPerSample.Channel1;
@ -42,6 +44,8 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
this.gFactor = (1 << this.bitsPerSampleG) - 1.0f;
this.bFactor = (1 << this.bitsPerSampleB) - 1.0f;
this.aFactor = (1 << this.bitsPerSampleA) - 1.0f;
this.extraSamplesType = extraSampleType;
}
/// <inheritdoc/>
@ -51,6 +55,8 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
var bitReader = new BitReader(data);
bool hasAssociatedAlpha = this.extraSamplesType.HasValue && this.extraSamplesType == TiffExtraSampleType.AssociatedAlphaData;
for (int y = top; y < top + height; y++)
{
Span<TPixel> pixelRow = pixels.DangerousGetRowSpan(y).Slice(left, width);
@ -61,8 +67,16 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
float b = bitReader.ReadBits(this.bitsPerSampleB) / this.bFactor;
float a = bitReader.ReadBits(this.bitsPerSampleB) / this.aFactor;
color.FromVector4(new Vector4(r, g, b, a));
pixelRow[x] = color;
var vec = new Vector4(r, g, b, a);
if (hasAssociatedAlpha)
{
pixelRow[x] = TiffUtils.UnPremultiply(vec, color);
}
else
{
color.FromVector4(vec);
pixelRow[x] = color;
}
}
bitReader.NextRow();

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

@ -14,6 +14,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
MemoryAllocator memoryAllocator,
TiffColorType colorType,
TiffBitsPerSample bitsPerSample,
TiffExtraSampleType? extraSampleType,
ushort[] colorMap,
Rational[] referenceBlackAndWhite,
Rational[] ycbcrCoefficients,
@ -125,7 +126,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
&& bitsPerSample.Channel0 == 2,
"bitsPerSample");
DebugGuard.IsTrue(colorMap == null, "colorMap");
return new RgbaTiffColor<TPixel>(bitsPerSample);
return new RgbaTiffColor<TPixel>(extraSampleType, bitsPerSample);
case TiffColorType.Rgb333:
DebugGuard.IsTrue(
@ -146,7 +147,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
&& bitsPerSample.Channel0 == 3,
"bitsPerSample");
DebugGuard.IsTrue(colorMap == null, "colorMap");
return new RgbaTiffColor<TPixel>(bitsPerSample);
return new RgbaTiffColor<TPixel>(extraSampleType, bitsPerSample);
case TiffColorType.Rgb444:
DebugGuard.IsTrue(
@ -167,7 +168,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
&& bitsPerSample.Channel0 == 4,
"bitsPerSample");
DebugGuard.IsTrue(colorMap == null, "colorMap");
return new RgbaTiffColor<TPixel>(bitsPerSample);
return new RgbaTiffColor<TPixel>(extraSampleType, bitsPerSample);
case TiffColorType.Rgb555:
DebugGuard.IsTrue(
@ -188,7 +189,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
&& bitsPerSample.Channel0 == 5,
"bitsPerSample");
DebugGuard.IsTrue(colorMap == null, "colorMap");
return new RgbaTiffColor<TPixel>(bitsPerSample);
return new RgbaTiffColor<TPixel>(extraSampleType, bitsPerSample);
case TiffColorType.Rgb666:
DebugGuard.IsTrue(
@ -209,7 +210,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
&& bitsPerSample.Channel0 == 6,
"bitsPerSample");
DebugGuard.IsTrue(colorMap == null, "colorMap");
return new RgbaTiffColor<TPixel>(bitsPerSample);
return new RgbaTiffColor<TPixel>(extraSampleType, bitsPerSample);
case TiffColorType.Rgb888:
DebugGuard.IsTrue(
@ -230,7 +231,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
&& bitsPerSample.Channel0 == 8,
"bitsPerSample");
DebugGuard.IsTrue(colorMap == null, "colorMap");
return new Rgba8888TiffColor<TPixel>(configuration);
return new Rgba8888TiffColor<TPixel>(configuration, memoryAllocator, extraSampleType);
case TiffColorType.Rgb101010:
DebugGuard.IsTrue(
@ -251,7 +252,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
&& bitsPerSample.Channel0 == 10,
"bitsPerSample");
DebugGuard.IsTrue(colorMap == null, "colorMap");
return new RgbaTiffColor<TPixel>(bitsPerSample);
return new RgbaTiffColor<TPixel>(extraSampleType, bitsPerSample);
case TiffColorType.Rgb121212:
DebugGuard.IsTrue(
@ -272,7 +273,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
&& bitsPerSample.Channel0 == 12,
"bitsPerSample");
DebugGuard.IsTrue(colorMap == null, "colorMap");
return new RgbaTiffColor<TPixel>(bitsPerSample);
return new RgbaTiffColor<TPixel>(extraSampleType, bitsPerSample);
case TiffColorType.Rgb141414:
DebugGuard.IsTrue(
@ -293,7 +294,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
&& bitsPerSample.Channel0 == 14,
"bitsPerSample");
DebugGuard.IsTrue(colorMap == null, "colorMap");
return new RgbaTiffColor<TPixel>(bitsPerSample);
return new RgbaTiffColor<TPixel>(extraSampleType, bitsPerSample);
case TiffColorType.Rgb161616:
DebugGuard.IsTrue(
@ -314,7 +315,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
&& bitsPerSample.Channel0 == 16,
"bitsPerSample");
DebugGuard.IsTrue(colorMap == null, "colorMap");
return new Rgba16161616TiffColor<TPixel>(configuration, isBigEndian: byteOrder == ByteOrder.BigEndian);
return new Rgba16161616TiffColor<TPixel>(configuration, memoryAllocator, extraSampleType, isBigEndian: byteOrder == ByteOrder.BigEndian);
case TiffColorType.Rgb242424:
DebugGuard.IsTrue(
@ -335,7 +336,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
&& bitsPerSample.Channel0 == 24,
"bitsPerSample");
DebugGuard.IsTrue(colorMap == null, "colorMap");
return new Rgba24242424TiffColor<TPixel>(isBigEndian: byteOrder == ByteOrder.BigEndian);
return new Rgba24242424TiffColor<TPixel>(extraSampleType, isBigEndian: byteOrder == ByteOrder.BigEndian);
case TiffColorType.Rgb323232:
DebugGuard.IsTrue(
@ -356,7 +357,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
&& bitsPerSample.Channel0 == 32,
"bitsPerSample");
DebugGuard.IsTrue(colorMap == null, "colorMap");
return new Rgba32323232TiffColor<TPixel>(isBigEndian: byteOrder == ByteOrder.BigEndian);
return new Rgba32323232TiffColor<TPixel>(extraSampleType, isBigEndian: byteOrder == ByteOrder.BigEndian);
case TiffColorType.RgbFloat323232:
DebugGuard.IsTrue(
@ -394,6 +395,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
public static TiffBasePlanarColorDecoder<TPixel> CreatePlanar(
TiffColorType colorType,
TiffBitsPerSample bitsPerSample,
TiffExtraSampleType? extraSampleType,
ushort[] colorMap,
Rational[] referenceBlackAndWhite,
Rational[] ycbcrCoefficients,
@ -408,7 +410,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
case TiffColorType.Rgba8888Planar:
DebugGuard.IsTrue(colorMap == null, "colorMap");
return new RgbaPlanarTiffColor<TPixel>(bitsPerSample);
return new RgbaPlanarTiffColor<TPixel>(extraSampleType, bitsPerSample);
case TiffColorType.YCbCrPlanar:
return new YCbCrPlanarTiffColor<TPixel>(referenceBlackAndWhite, ycbcrCoefficients, ycbcrSubSampling);
@ -419,7 +421,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
case TiffColorType.Rgba16161616Planar:
DebugGuard.IsTrue(colorMap == null, "colorMap");
return new Rgba16PlanarTiffColor<TPixel>(byteOrder == ByteOrder.BigEndian);
return new Rgba16PlanarTiffColor<TPixel>(extraSampleType, byteOrder == ByteOrder.BigEndian);
case TiffColorType.Rgb242424Planar:
DebugGuard.IsTrue(colorMap == null, "colorMap");
@ -427,7 +429,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
case TiffColorType.Rgba24242424Planar:
DebugGuard.IsTrue(colorMap == null, "colorMap");
return new Rgba24PlanarTiffColor<TPixel>(byteOrder == ByteOrder.BigEndian);
return new Rgba24PlanarTiffColor<TPixel>(extraSampleType, byteOrder == ByteOrder.BigEndian);
case TiffColorType.Rgb323232Planar:
DebugGuard.IsTrue(colorMap == null, "colorMap");
@ -435,7 +437,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
case TiffColorType.Rgba32323232Planar:
DebugGuard.IsTrue(colorMap == null, "colorMap");
return new Rgba32PlanarTiffColor<TPixel>(byteOrder == ByteOrder.BigEndian);
return new Rgba32PlanarTiffColor<TPixel>(extraSampleType, byteOrder == ByteOrder.BigEndian);
default:
throw TiffThrowHelper.InvalidColorType(colorType.ToString());

13
src/ImageSharp/Formats/Tiff/README.md

@ -28,15 +28,6 @@
- The Decoder currently only supports decoding multiframe images, which have the same dimensions.
- Some compression formats are not yet supported. See the list below.
### Deviations from the TIFF spec (to be fixed)
- Decoder
- A Baseline TIFF reader must skip over extra components (e.g. RGB with 4 samples per pixels)
- NB: Need to handle this for both planar and chunky data
- If the SampleFormat field is present and not 1 - fail gracefully if you cannot handle this
- Compression=None should treat 16/32-BitsPerSample for all samples as SHORT/LONG (for byte order and padding rows)
- Check Planar format data - is this encoded as strips in order RGBRGBRGB or RRRGGGBBB?
### Compression Formats
| |Encoder|Decoder|Comments |
@ -87,7 +78,7 @@
|Model | Y | Y | |
|StripOffsets | Y | Y | |
|Orientation | | - | Ignore. Many readers ignore this tag. |
|SamplesPerPixel | Y | - | Currently ignored, as can be inferred from count of BitsPerSample |
|SamplesPerPixel | Y | - | Currently ignored, as can be inferred from count of BitsPerSample. |
|RowsPerStrip | Y | Y | |
|StripByteCounts | Y | Y | |
|MinSampleValue | | | |
@ -105,7 +96,7 @@
|Artist | Y | Y | |
|HostComputer | Y | Y | |
|ColorMap | Y | Y | |
|ExtraSamples | | (Y) | Only UnassociatedAlphaData is supported so far |
|ExtraSamples | | Y | Unspecified alpha data is not supported. |
|Copyright | Y | Y | |
### Extension TIFF Tags

6
src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs

@ -118,9 +118,9 @@ namespace SixLabors.ImageSharp.Formats.Tiff
public TiffFillOrder FillOrder { get; set; }
/// <summary>
/// Gets or sets the extra samples, which can contain the alpha channel data.
/// Gets or sets the extra samples type.
/// </summary>
public TiffExtraSampleType? ExtraSamples { get; set; }
public TiffExtraSampleType? ExtraSamplesType { get; set; }
/// <summary>
/// Gets or sets the JPEG tables when jpeg compression is used.
@ -375,6 +375,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff
TiffBasePlanarColorDecoder<TPixel> colorDecoder = TiffColorDecoderFactory<TPixel>.CreatePlanar(
this.ColorType,
this.BitsPerSample,
this.ExtraSamplesType,
this.ColorMap,
this.ReferenceBlackAndWhite,
this.YcbcrCoefficients,
@ -456,6 +457,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff
this.memoryAllocator,
this.ColorType,
this.BitsPerSample,
this.ExtraSamplesType,
this.ColorMap,
this.ReferenceBlackAndWhite,
this.YcbcrCoefficients,

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

@ -39,10 +39,10 @@ namespace SixLabors.ImageSharp.Formats.Tiff
}
var extraSamplesType = (TiffExtraSampleType)extraSamples[0];
options.ExtraSamples = extraSamplesType;
if (extraSamplesType is not TiffExtraSampleType.UnassociatedAlphaData)
options.ExtraSamplesType = extraSamplesType;
if (extraSamplesType is not (TiffExtraSampleType.UnassociatedAlphaData or TiffExtraSampleType.AssociatedAlphaData))
{
TiffThrowHelper.ThrowNotSupported("Decoding Tiff images with ExtraSamples is only supported with UnassociatedAlphaData.");
TiffThrowHelper.ThrowNotSupported("Decoding Tiff images with ExtraSamples is not supported with UnspecifiedData.");
}
}

48
src/ImageSharp/Formats/Tiff/Utils/TiffUtils.cs

@ -46,7 +46,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Utils
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static TPixel ColorFromRgba64<TPixel>(Rgba64 rgba, ulong r, ulong g, ulong b, TPixel color)
public static TPixel ColorFromRgb64<TPixel>(Rgba64 rgba, ulong r, ulong g, ulong b, TPixel color)
where TPixel : unmanaged, IPixel<TPixel>
{
rgba.PackedValue = r | (g << 16) | (b << 32) | (0xfffful << 48);
@ -63,6 +63,15 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Utils
return color;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static TPixel ColorFromRgba64Premultiplied<TPixel>(Rgba64 rgba, ulong r, ulong g, ulong b, ulong a, TPixel color)
where TPixel : unmanaged, IPixel<TPixel>
{
rgba.PackedValue = r | (g << 16) | (b << 32) | (a << 48);
var vec = rgba.ToVector4();
return UnPremultiply(vec, color);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static TPixel ColorScaleTo24Bit<TPixel>(ulong r, ulong g, ulong b, TPixel color)
where TPixel : unmanaged, IPixel<TPixel>
@ -81,6 +90,14 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Utils
return color;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static TPixel ColorScaleTo24BitPremultiplied<TPixel>(ulong r, ulong g, ulong b, ulong a, TPixel color)
where TPixel : unmanaged, IPixel<TPixel>
{
var colorVector = new Vector4(r * Scale24Bit, g * Scale24Bit, b * Scale24Bit, a * Scale24Bit);
return UnPremultiply(colorVector, color);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static TPixel ColorScaleTo32Bit<TPixel>(ulong r, ulong g, ulong b, TPixel color)
where TPixel : unmanaged, IPixel<TPixel>
@ -99,6 +116,14 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Utils
return color;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static TPixel ColorScaleTo32BitPremultiplied<TPixel>(ulong r, ulong g, ulong b, ulong a, TPixel color)
where TPixel : unmanaged, IPixel<TPixel>
{
var colorVector = new Vector4(r * Scale32Bit, g * Scale32Bit, b * Scale32Bit, a * Scale32Bit);
return UnPremultiply(colorVector, color);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static TPixel ColorFromL16<TPixel>(L16 l16, ushort intensity, TPixel color)
where TPixel : unmanaged, IPixel<TPixel>
@ -126,6 +151,27 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Utils
return color;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void UnPremultiplyRow<TPixel>(Span<Vector4> vectors, Span<TPixel> pixelRow, TPixel color)
where TPixel : unmanaged, IPixel<TPixel>
{
for (int x = 0; x < vectors.Length; x++)
{
Vector4 vec = vectors[x];
pixelRow[x] = UnPremultiply(vec, color);
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static TPixel UnPremultiply<TPixel>(Vector4 vec, TPixel color)
where TPixel : unmanaged, IPixel<TPixel>
{
float invW = 1.0f / vec.W;
color.FromVector4(new Vector4(vec.X * invW, vec.Y * invW, vec.Z * invW, vec.W));
return color;
}
/// <summary>
/// Finds the padding needed to round 'valueToRoundUp' to the next integer multiple of subSampling value.
/// </summary>

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

@ -187,6 +187,13 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff
public void TiffDecoder_CanDecode_12Bit_WithUnassociatedAlpha<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel> => TestTiffDecoder(provider);
[Theory]
[WithFile(Rgba3BitAssociatedAlpha, PixelTypes.Rgba32)]
public void TiffDecoder_CanDecode_12Bit_WithAssociatedAlpha<TPixel>(TestImageProvider<TPixel> provider)
// Note: Using tolerant comparer here, because there is a small difference to the reference decoder probably due to floating point rounding issues.
where TPixel : unmanaged, IPixel<TPixel> => TestTiffDecoder(provider, useExactComparer: false);
[Theory]
[WithFile(Flower14BitGray, PixelTypes.Rgba32)]
public void TiffDecoder_CanDecode_14Bit_Gray<TPixel>(TestImageProvider<TPixel> provider)
@ -226,6 +233,13 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff
public void TiffDecoder_CanDecode_20Bit_WithUnassociatedAlpha<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel> => TestTiffDecoder(provider);
[Theory]
[WithFile(Rgba5BitAssociatedAlpha, PixelTypes.Rgba32)]
public void TiffDecoder_CanDecode_20Bit_WithAssociatedAlpha<TPixel>(TestImageProvider<TPixel> provider)
// Note: Using tolerant comparer here, because there is a small difference to the reference decoder probably due to floating point rounding issues.
where TPixel : unmanaged, IPixel<TPixel> => TestTiffDecoder(provider, useExactComparer: false);
[Theory]
[WithFile(FlowerRgb888Contiguous, PixelTypes.Rgba32)]
public void TiffDecoder_CanDecode_24Bit<TPixel>(TestImageProvider<TPixel> provider)
@ -236,6 +250,13 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff
public void TiffDecoder_CanDecode_24Bit_WithUnassociatedAlpha<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel> => TestTiffDecoder(provider);
[Theory]
[WithFile(Rgba6BitAssociatedAlpha, PixelTypes.Rgba32)]
public void TiffDecoder_CanDecode_24Bit_WithAssociatedAlpha<TPixel>(TestImageProvider<TPixel> provider)
// Note: Using tolerant comparer here, because there is a small difference to the reference decoder probably due to floating point rounding issues.
where TPixel : unmanaged, IPixel<TPixel> => TestTiffDecoder(provider, useExactComparer: false);
[Theory]
[WithFile(Flower24BitGray, PixelTypes.Rgba32)]
[WithFile(Flower24BitGrayLittleEndian, PixelTypes.Rgba32)]
@ -296,6 +317,13 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff
image.DebugSave(provider);
}
[Theory]
[WithFile(Rgba8BitAssociatedAlpha, PixelTypes.Rgba32)]
public void TiffDecoder_CanDecode_32Bit_WithAssociatedAlpha<TPixel>(TestImageProvider<TPixel> provider)
// Note: Using tolerant comparer here, because there is a small difference to the reference decoder probably due to floating point rounding issues.
where TPixel : unmanaged, IPixel<TPixel> => TestTiffDecoder(provider, useExactComparer: false);
[Theory]
[WithFile(Flower32BitGrayPredictorBigEndian, PixelTypes.Rgba32)]
[WithFile(Flower32BitGrayPredictorLittleEndian, PixelTypes.Rgba32)]
@ -318,6 +346,12 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff
public void TiffDecoder_CanDecode_40Bit_WithUnassociatedAlpha<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel> => TestTiffDecoder(provider);
[Theory]
[WithFile(Rgba10BitAssociatedAlphaBigEndian, PixelTypes.Rgba32)]
[WithFile(Rgba10BitAssociatedAlphaLittleEndian, PixelTypes.Rgba32)]
public void TiffDecoder_CanDecode_40Bit_WithAssociatedAlpha<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel> => TestTiffDecoder(provider, useExactComparer: false);
[Theory]
[WithFile(FlowerRgb141414Contiguous, PixelTypes.Rgba32)]
[WithFile(FlowerRgb141414Planar, PixelTypes.Rgba32)]
@ -339,6 +373,12 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff
public void TiffDecoder_CanDecode_48Bit_WithUnassociatedAlpha<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel> => TestTiffDecoder(provider);
[Theory]
[WithFile(Rgba12BitAssociatedAlphaBigEndian, PixelTypes.Rgba32)]
[WithFile(Rgba12BitAssociatedAlphaLittleEndian, PixelTypes.Rgba32)]
public void TiffDecoder_CanDecode_48Bit_WithAssociatedAlpha<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel> => TestTiffDecoder(provider, useExactComparer: false, compareTolerance: 0.0002f);
[Theory]
[WithFile(FlowerRgb161616PredictorBigEndian, PixelTypes.Rgba32)]
[WithFile(FlowerRgb161616PredictorLittleEndian, PixelTypes.Rgba32)]
@ -351,6 +391,12 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff
public void TiffDecoder_CanDecode_56Bit_WithUnassociatedAlpha<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel> => TestTiffDecoder(provider);
[Theory]
[WithFile(Rgba14BitAssociatedAlphaBigEndian, PixelTypes.Rgba32)]
[WithFile(Rgba14BitAssociatedAlphaLittleEndian, PixelTypes.Rgba32)]
public void TiffDecoder_CanDecode_56Bit_WithAssociatedAlpha<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel> => TestTiffDecoder(provider, useExactComparer: false, compareTolerance: 0.0002f);
[Theory]
[WithFile(FlowerRgb242424Contiguous, PixelTypes.Rgba32)]
[WithFile(FlowerRgb242424ContiguousLittleEndian, PixelTypes.Rgba32)]

13
tests/ImageSharp.Tests/TestImages.cs

@ -861,20 +861,33 @@ namespace SixLabors.ImageSharp.Tests
// Images with alpha channel.
public const string Rgba2BitUnassociatedAlpha = "Tiff/RgbaUnassociatedAlpha2bit.tiff";
public const string Rgba3BitUnassociatedAlpha = "Tiff/RgbaUnassociatedAlpha3bit.tiff";
public const string Rgba3BitAssociatedAlpha = "Tiff/RgbaAssociatedAlpha3bit.tiff";
public const string Rgba4BitUnassociatedAlpha = "Tiff/RgbaUnassociatedAlpha4bit.tiff";
public const string Rgba4BitAassociatedAlpha = "Tiff/RgbaAssociatedAlpha4bit.tiff";
public const string Rgba5BitUnassociatedAlpha = "Tiff/RgbaUnassociatedAlpha5bit.tiff";
public const string Rgba5BitAssociatedAlpha = "Tiff/RgbaAssociatedAlpha5bit.tiff";
public const string Rgba6BitUnassociatedAlpha = "Tiff/RgbaUnassociatedAlpha6bit.tiff";
public const string Rgba6BitAssociatedAlpha = "Tiff/RgbaAssociatedAlpha6bit.tiff";
public const string Rgba8BitUnassociatedAlpha = "Tiff/RgbaUnassociatedAlpha8bit.tiff";
public const string Rgba8BitAssociatedAlpha = "Tiff/RgbaAlpha8bit.tiff";
public const string Rgba8BitUnassociatedAlphaWithPredictor = "Tiff/RgbaUnassociatedAlphaPredictor8bit.tiff";
public const string Rgba8BitPlanarUnassociatedAlpha = "Tiff/RgbaUnassociatedAlphaPlanar8bit.tiff";
public const string Rgba10BitUnassociatedAlphaBigEndian = "Tiff/RgbaUnassociatedAlpha10bit_msb.tiff";
public const string Rgba10BitUnassociatedAlphaLittleEndian = "Tiff/RgbaUnassociatedAlpha10bit_lsb.tiff";
public const string Rgba10BitAssociatedAlphaBigEndian = "Tiff/RgbaAssociatedAlpha10bit_msb.tiff";
public const string Rgba10BitAssociatedAlphaLittleEndian = "Tiff/RgbaAssociatedAlpha10bit_lsb.tiff";
public const string Rgba12BitUnassociatedAlphaBigEndian = "Tiff/RgbaUnassociatedAlpha12bit_msb.tiff";
public const string Rgba12BitUnassociatedAlphaLittleEndian = "Tiff/RgbaUnassociatedAlpha12bit_lsb.tiff";
public const string Rgba12BitAssociatedAlphaBigEndian = "Tiff/RgbaAssociatedAlpha12bit_msb.tiff";
public const string Rgba12BitAssociatedAlphaLittleEndian = "Tiff/RgbaAssociatedAlpha12bit_lsb.tiff";
public const string Rgba14BitUnassociatedAlphaBigEndian = "Tiff/RgbaUnassociatedAlpha14bit_msb.tiff";
public const string Rgba14BitUnassociatedAlphaLittleEndian = "Tiff/RgbaUnassociatedAlpha14bit_lsb.tiff";
public const string Rgba14BitAssociatedAlphaBigEndian = "Tiff/RgbaAssociatedAlpha14bit_msb.tiff";
public const string Rgba14BitAssociatedAlphaLittleEndian = "Tiff/RgbaAssociatedAlpha14bit_lsb.tiff";
public const string Rgba16BitUnassociatedAlphaBigEndian = "Tiff/RgbaUnassociatedAlpha16bit_msb.tiff";
public const string Rgba16BitUnassociatedAlphaLittleEndian = "Tiff/RgbaUnassociatedAlpha16bit_lsb.tiff";
public const string Rgba16BitAssociatedAlphaBigEndian = "Tiff/RgbaAssociatedAlpha16bit_msb.tiff";
public const string Rgba16BitAssociatedAlphaLittleEndian = "Tiff/RgbaAssociatedAlpha16bit_lsb.tiff";
public const string Rgba16BitUnassociatedAlphaBigEndianWithPredictor = "Tiff/RgbaUnassociatedAlphaPredictor16bit_msb.tiff";
public const string Rgba16BitUnassociatedAlphaLittleEndianWithPredictor = "Tiff/RgbaUnassociatedAlphaPredictor16bit_lsb.tiff";
public const string Rgba16BitPlanarUnassociatedAlphaBigEndian = "Tiff/RgbaUnassociatedAlphaPlanar16bit_msb.tiff";

3
tests/Images/Input/Tiff/RgbaAlpha8bit.tiff

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

3
tests/Images/Input/Tiff/RgbaAssociatedAlpha10bit_lsb.tiff

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

3
tests/Images/Input/Tiff/RgbaAssociatedAlpha10bit_msb.tiff

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

3
tests/Images/Input/Tiff/RgbaAssociatedAlpha12bit_lsb.tiff

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

3
tests/Images/Input/Tiff/RgbaAssociatedAlpha12bit_msb.tiff

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

3
tests/Images/Input/Tiff/RgbaAssociatedAlpha14bit_lsb.tiff

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

3
tests/Images/Input/Tiff/RgbaAssociatedAlpha14bit_msb.tiff

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

3
tests/Images/Input/Tiff/RgbaAssociatedAlpha16bit_lsb.tiff

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

3
tests/Images/Input/Tiff/RgbaAssociatedAlpha16bit_msb.tiff

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

3
tests/Images/Input/Tiff/RgbaAssociatedAlpha3bit.tiff

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

3
tests/Images/Input/Tiff/RgbaAssociatedAlpha4bit.tiff

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

3
tests/Images/Input/Tiff/RgbaAssociatedAlpha5bit.tiff

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

3
tests/Images/Input/Tiff/RgbaAssociatedAlpha6bit.tiff

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