Browse Source

Merge pull request #2037 from SixLabors/bp/extrasamples

Add support for decoding Tiff images with UnassociatedAlphaData
pull/2050/head
James Jackson-South 4 years ago
committed by GitHub
parent
commit
8b2ebc5d53
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 4
      src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgb242424TiffColor{TPixel}.cs
  2. 4
      src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgb24PlanarTiffColor{TPixel}.cs
  3. 77
      src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba16161616TiffColor{TPixel}.cs
  4. 75
      src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba16PlanarTiffColor{TPixel}.cs
  5. 90
      src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba24242424TiffColor{TPixel}.cs
  6. 85
      src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba24PlanarTiffColor{TPixel}.cs
  7. 79
      src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba32323232TiffColor{TPixel}.cs
  8. 74
      src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba32PlanarTiffColor{TPixel}.cs
  9. 39
      src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba8888TiffColor{TPixel}.cs
  10. 97
      src/ImageSharp/Formats/Tiff/PhotometricInterpretation/RgbaFloat32323232TiffColor{TPixel}.cs
  11. 87
      src/ImageSharp/Formats/Tiff/PhotometricInterpretation/RgbaPlanarTiffColor{TPixel}.cs
  12. 72
      src/ImageSharp/Formats/Tiff/PhotometricInterpretation/RgbaTiffColor{TPixel}.cs
  13. 189
      src/ImageSharp/Formats/Tiff/PhotometricInterpretation/TiffColorDecoderFactory{TPixel}.cs
  14. 100
      src/ImageSharp/Formats/Tiff/PhotometricInterpretation/TiffColorType.cs
  15. 2
      src/ImageSharp/Formats/Tiff/README.md
  16. 38
      src/ImageSharp/Formats/Tiff/TiffBitsPerSample.cs
  17. 22
      src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs
  18. 60
      src/ImageSharp/Formats/Tiff/TiffDecoderOptionsParser.cs
  19. 27
      src/ImageSharp/Formats/Tiff/TiffExtraSampleType.cs
  20. 33
      src/ImageSharp/Formats/Tiff/Utils/TiffUtils.cs
  21. 136
      tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs
  22. 30
      tests/ImageSharp.Tests/TestImages.cs
  23. 4
      tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/MagickReferenceDecoder.cs
  24. 3
      tests/Images/Input/Tiff/RgbaUnassociatedAlpha10bit_lsb.tiff
  25. 3
      tests/Images/Input/Tiff/RgbaUnassociatedAlpha10bit_msb.tiff
  26. 3
      tests/Images/Input/Tiff/RgbaUnassociatedAlpha12bit_lsb.tiff
  27. 3
      tests/Images/Input/Tiff/RgbaUnassociatedAlpha12bit_msb.tiff
  28. 3
      tests/Images/Input/Tiff/RgbaUnassociatedAlpha14bit_lsb.tiff
  29. 3
      tests/Images/Input/Tiff/RgbaUnassociatedAlpha14bit_msb.tiff
  30. 3
      tests/Images/Input/Tiff/RgbaUnassociatedAlpha16bit_lsb.tiff
  31. 3
      tests/Images/Input/Tiff/RgbaUnassociatedAlpha16bit_msb.tiff
  32. 3
      tests/Images/Input/Tiff/RgbaUnassociatedAlpha24bit_lsb.tiff
  33. 3
      tests/Images/Input/Tiff/RgbaUnassociatedAlpha24bit_msb.tiff
  34. 3
      tests/Images/Input/Tiff/RgbaUnassociatedAlpha2bit.tiff
  35. 3
      tests/Images/Input/Tiff/RgbaUnassociatedAlpha32bit_lsb.tiff
  36. 3
      tests/Images/Input/Tiff/RgbaUnassociatedAlpha32bit_msb.tiff
  37. 3
      tests/Images/Input/Tiff/RgbaUnassociatedAlpha3bit.tiff
  38. 3
      tests/Images/Input/Tiff/RgbaUnassociatedAlpha4bit.tiff
  39. 3
      tests/Images/Input/Tiff/RgbaUnassociatedAlpha5bit.tiff
  40. 3
      tests/Images/Input/Tiff/RgbaUnassociatedAlpha6bit.tiff
  41. 3
      tests/Images/Input/Tiff/RgbaUnassociatedAlpha8bit.tiff
  42. 3
      tests/Images/Input/Tiff/RgbaUnassociatedAlphaPlanar16bit_lsb.tiff
  43. 3
      tests/Images/Input/Tiff/RgbaUnassociatedAlphaPlanar16bit_msb.tiff
  44. 3
      tests/Images/Input/Tiff/RgbaUnassociatedAlphaPlanar24bit_lsb.tiff
  45. 3
      tests/Images/Input/Tiff/RgbaUnassociatedAlphaPlanar24bit_msb.tiff
  46. 3
      tests/Images/Input/Tiff/RgbaUnassociatedAlphaPlanar32bit_lsb.tiff
  47. 3
      tests/Images/Input/Tiff/RgbaUnassociatedAlphaPlanar32bit_msb.tiff
  48. 3
      tests/Images/Input/Tiff/RgbaUnassociatedAlphaPlanar8bit.tiff
  49. 3
      tests/Images/Input/Tiff/flower-rgb-3bit.tiff
  50. 3
      tests/Images/Input/Tiff/flower-rgb-5bit.tiff
  51. 3
      tests/Images/Input/Tiff/flower-rgb-6bit.tiff

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

@ -30,10 +30,10 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
var color = default(TPixel);
color.FromVector4(TiffUtils.Vector4Default);
int offset = 0;
byte[] buffer = new byte[4];
Span<byte> buffer = stackalloc byte[4];
int bufferStartIdx = this.isBigEndian ? 1 : 0;
Span<byte> bufferSpan = buffer.AsSpan(bufferStartIdx);
Span<byte> bufferSpan = buffer.Slice(bufferStartIdx);
for (int y = top; y < top + height; y++)
{
Span<TPixel> pixelRow = pixels.DangerousGetRowSpan(y).Slice(left, width);

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

@ -30,13 +30,13 @@ 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);
byte[] buffer = new byte[4];
Span<byte> buffer = stackalloc byte[4];
int bufferStartIdx = this.isBigEndian ? 1 : 0;
Span<byte> redData = data[0].GetSpan();
Span<byte> greenData = data[1].GetSpan();
Span<byte> blueData = data[2].GetSpan();
Span<byte> bufferSpan = buffer.AsSpan(bufferStartIdx);
Span<byte> bufferSpan = buffer.Slice(bufferStartIdx);
int offset = 0;
for (int y = top; y < top + height; y++)

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

@ -0,0 +1,77 @@
// Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0.
using System;
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 an alpha channel and with 16 bits for each channel.
/// </summary>
internal class Rgba16161616TiffColor<TPixel> : TiffBaseColorDecoder<TPixel>
where TPixel : unmanaged, IPixel<TPixel>
{
private readonly bool isBigEndian;
private readonly Configuration configuration;
/// <summary>
/// Initializes a new instance of the <see cref="Rgba16161616TiffColor{TPixel}" /> class.
/// </summary>
/// <param name="configuration">The configuration.</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)
{
this.configuration = configuration;
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
Rgba64 rgba = TiffUtils.Rgba64Default;
var color = default(TPixel);
color.FromVector4(TiffUtils.Vector4Default);
int offset = 0;
for (int y = top; y < top + height; y++)
{
Span<TPixel> pixelRow = pixels.DangerousGetRowSpan(y).Slice(left, width);
if (this.isBigEndian)
{
for (int x = 0; x < pixelRow.Length; x++)
{
ulong r = TiffUtils.ConvertToUShortBigEndian(data.Slice(offset, 2));
offset += 2;
ulong g = TiffUtils.ConvertToUShortBigEndian(data.Slice(offset, 2));
offset += 2;
ulong b = TiffUtils.ConvertToUShortBigEndian(data.Slice(offset, 2));
offset += 2;
ulong a = TiffUtils.ConvertToUShortBigEndian(data.Slice(offset, 2));
offset += 2;
pixelRow[x] = TiffUtils.ColorFromRgba64(rgba, r, g, b, a, color);
}
}
else
{
int byteCount = pixelRow.Length * 8;
PixelOperations<TPixel>.Instance.FromRgba64Bytes(
this.configuration,
data.Slice(offset, byteCount),
pixelRow,
pixelRow.Length);
offset += byteCount;
}
}
}
}
}

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

@ -0,0 +1,75 @@
// 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 an alpha channel and with 'Planar' layout for each color channel with 16 bit.
/// </summary>
internal class Rgba16PlanarTiffColor<TPixel> : TiffBasePlanarColorDecoder<TPixel>
where TPixel : unmanaged, IPixel<TPixel>
{
private readonly bool isBigEndian;
/// <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;
/// <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
Rgba64 rgba = TiffUtils.Rgba64Default;
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();
Span<byte> alphaData = data[3].GetSpan();
int offset = 0;
for (int y = top; y < top + height; y++)
{
Span<TPixel> pixelRow = pixels.DangerousGetRowSpan(y).Slice(left, width);
if (this.isBigEndian)
{
for (int x = 0; x < pixelRow.Length; x++)
{
ulong r = TiffUtils.ConvertToUShortBigEndian(redData.Slice(offset, 2));
ulong g = TiffUtils.ConvertToUShortBigEndian(greenData.Slice(offset, 2));
ulong b = TiffUtils.ConvertToUShortBigEndian(blueData.Slice(offset, 2));
ulong a = TiffUtils.ConvertToUShortBigEndian(alphaData.Slice(offset, 2));
offset += 2;
pixelRow[x] = TiffUtils.ColorFromRgba64(rgba, r, g, b, a, color);
}
}
else
{
for (int x = 0; x < pixelRow.Length; x++)
{
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));
offset += 2;
pixelRow[x] = TiffUtils.ColorFromRgba64(rgba, r, g, b, a, color);
}
}
}
}
}
}

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

@ -0,0 +1,90 @@
// Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0.
using System;
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 an alpha channel and with 24 bits for each channel.
/// </summary>
internal class Rgba24242424TiffColor<TPixel> : TiffBaseColorDecoder<TPixel>
where TPixel : unmanaged, IPixel<TPixel>
{
private readonly bool isBigEndian;
/// <summary>
/// Initializes a new instance of the <see cref="Rgba24242424TiffColor{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 Rgba24242424TiffColor(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);
int offset = 0;
Span<byte> buffer = stackalloc byte[4];
int bufferStartIdx = this.isBigEndian ? 1 : 0;
Span<byte> bufferSpan = buffer.Slice(bufferStartIdx);
for (int y = top; y < top + height; y++)
{
Span<TPixel> pixelRow = pixels.DangerousGetRowSpan(y).Slice(left, width);
if (this.isBigEndian)
{
for (int x = 0; x < pixelRow.Length; x++)
{
data.Slice(offset, 3).CopyTo(bufferSpan);
ulong r = TiffUtils.ConvertToUIntBigEndian(buffer);
offset += 3;
data.Slice(offset, 3).CopyTo(bufferSpan);
ulong g = TiffUtils.ConvertToUIntBigEndian(buffer);
offset += 3;
data.Slice(offset, 3).CopyTo(bufferSpan);
ulong b = TiffUtils.ConvertToUIntBigEndian(buffer);
offset += 3;
data.Slice(offset, 3).CopyTo(bufferSpan);
ulong a = TiffUtils.ConvertToUIntBigEndian(buffer);
offset += 3;
pixelRow[x] = TiffUtils.ColorScaleTo24Bit(r, g, b, a, color);
}
}
else
{
for (int x = 0; x < pixelRow.Length; x++)
{
data.Slice(offset, 3).CopyTo(bufferSpan);
ulong r = TiffUtils.ConvertToUIntLittleEndian(buffer);
offset += 3;
data.Slice(offset, 3).CopyTo(bufferSpan);
ulong g = TiffUtils.ConvertToUIntLittleEndian(buffer);
offset += 3;
data.Slice(offset, 3).CopyTo(bufferSpan);
ulong b = TiffUtils.ConvertToUIntLittleEndian(buffer);
offset += 3;
data.Slice(offset, 3).CopyTo(bufferSpan);
ulong a = TiffUtils.ConvertToUIntLittleEndian(buffer);
offset += 3;
pixelRow[x] = TiffUtils.ColorScaleTo24Bit(r, g, b, a, color);
}
}
}
}
}
}

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

@ -0,0 +1,85 @@
// 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 an alpha channel and with 'Planar' layout for each color channel with 24 bit.
/// </summary>
internal class Rgba24PlanarTiffColor<TPixel> : TiffBasePlanarColorDecoder<TPixel>
where TPixel : unmanaged, IPixel<TPixel>
{
private readonly bool isBigEndian;
/// <summary>
/// Initializes a new instance of the <see cref="Rgba24PlanarTiffColor{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 Rgba24PlanarTiffColor(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> buffer = stackalloc byte[4];
int bufferStartIdx = this.isBigEndian ? 1 : 0;
Span<byte> redData = data[0].GetSpan();
Span<byte> greenData = data[1].GetSpan();
Span<byte> blueData = data[2].GetSpan();
Span<byte> alphaData = data[3].GetSpan();
Span<byte> bufferSpan = buffer.Slice(bufferStartIdx);
int offset = 0;
for (int y = top; y < top + height; y++)
{
Span<TPixel> pixelRow = pixels.DangerousGetRowSpan(y).Slice(left, width);
if (this.isBigEndian)
{
for (int x = 0; x < pixelRow.Length; x++)
{
redData.Slice(offset, 3).CopyTo(bufferSpan);
ulong r = TiffUtils.ConvertToUIntBigEndian(buffer);
greenData.Slice(offset, 3).CopyTo(bufferSpan);
ulong g = TiffUtils.ConvertToUIntBigEndian(buffer);
blueData.Slice(offset, 3).CopyTo(bufferSpan);
ulong b = TiffUtils.ConvertToUIntBigEndian(buffer);
alphaData.Slice(offset, 3).CopyTo(bufferSpan);
ulong a = TiffUtils.ConvertToUIntBigEndian(buffer);
offset += 3;
pixelRow[x] = TiffUtils.ColorScaleTo24Bit(r, g, b, a, color);
}
}
else
{
for (int x = 0; x < pixelRow.Length; x++)
{
redData.Slice(offset, 3).CopyTo(bufferSpan);
ulong r = TiffUtils.ConvertToUIntLittleEndian(buffer);
greenData.Slice(offset, 3).CopyTo(bufferSpan);
ulong g = TiffUtils.ConvertToUIntLittleEndian(buffer);
blueData.Slice(offset, 3).CopyTo(bufferSpan);
ulong b = TiffUtils.ConvertToUIntLittleEndian(buffer);
alphaData.Slice(offset, 3).CopyTo(bufferSpan);
ulong a = TiffUtils.ConvertToUIntLittleEndian(buffer);
offset += 3;
pixelRow[x] = TiffUtils.ColorScaleTo24Bit(r, g, b, a, color);
}
}
}
}
}
}

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

@ -0,0 +1,79 @@
// Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0.
using System;
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 an alpha channel and with 32 bits for each channel.
/// </summary>
internal class Rgba32323232TiffColor<TPixel> : TiffBaseColorDecoder<TPixel>
where TPixel : unmanaged, IPixel<TPixel>
{
private readonly bool isBigEndian;
/// <summary>
/// Initializes a new instance of the <see cref="Rgba32323232TiffColor{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 Rgba32323232TiffColor(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);
int offset = 0;
for (int y = top; y < top + height; y++)
{
Span<TPixel> pixelRow = pixels.DangerousGetRowSpan(y).Slice(left, width);
if (this.isBigEndian)
{
for (int x = 0; x < pixelRow.Length; x++)
{
ulong r = TiffUtils.ConvertToUIntBigEndian(data.Slice(offset, 4));
offset += 4;
ulong g = TiffUtils.ConvertToUIntBigEndian(data.Slice(offset, 4));
offset += 4;
ulong b = TiffUtils.ConvertToUIntBigEndian(data.Slice(offset, 4));
offset += 4;
ulong a = TiffUtils.ConvertToUIntBigEndian(data.Slice(offset, 4));
offset += 4;
pixelRow[x] = TiffUtils.ColorScaleTo32Bit(r, g, b, a, color);
}
}
else
{
for (int x = 0; x < pixelRow.Length; x++)
{
ulong r = TiffUtils.ConvertToUIntLittleEndian(data.Slice(offset, 4));
offset += 4;
ulong g = TiffUtils.ConvertToUIntLittleEndian(data.Slice(offset, 4));
offset += 4;
ulong b = TiffUtils.ConvertToUIntLittleEndian(data.Slice(offset, 4));
offset += 4;
ulong a = TiffUtils.ConvertToUIntLittleEndian(data.Slice(offset, 4));
offset += 4;
pixelRow[x] = TiffUtils.ColorScaleTo32Bit(r, g, b, a, color);
}
}
}
}
}
}

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

@ -0,0 +1,74 @@
// 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 an alpha channel and a 'Planar' layout for each color channel with 32 bit.
/// </summary>
internal class Rgba32PlanarTiffColor<TPixel> : TiffBasePlanarColorDecoder<TPixel>
where TPixel : unmanaged, IPixel<TPixel>
{
private readonly bool isBigEndian;
/// <summary>
/// Initializes a new instance of the <see cref="Rgba32PlanarTiffColor{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 Rgba32PlanarTiffColor(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();
Span<byte> alphaData = data[3].GetSpan();
int offset = 0;
for (int y = top; y < top + height; y++)
{
Span<TPixel> pixelRow = pixels.DangerousGetRowSpan(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));
ulong a = TiffUtils.ConvertToUIntBigEndian(alphaData.Slice(offset, 4));
offset += 4;
pixelRow[x] = TiffUtils.ColorScaleTo32Bit(r, g, b, a, 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));
ulong a = TiffUtils.ConvertToUIntLittleEndian(alphaData.Slice(offset, 4));
offset += 4;
pixelRow[x] = TiffUtils.ColorScaleTo32Bit(r, g, b, a, color);
}
}
}
}
}
}

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

@ -0,0 +1,39 @@
// Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0.
using System;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
{
/// <summary>
/// Implements the 'RGB' photometric interpretation with an alpha channel and 8 bits per channel.
/// </summary>
internal class Rgba8888TiffColor<TPixel> : TiffBaseColorDecoder<TPixel>
where TPixel : unmanaged, IPixel<TPixel>
{
private readonly Configuration configuration;
public Rgba8888TiffColor(Configuration configuration) => this.configuration = configuration;
/// <inheritdoc/>
public override void Decode(ReadOnlySpan<byte> data, Buffer2D<TPixel> pixels, int left, int top, int width, int height)
{
int offset = 0;
for (int y = top; y < top + height; y++)
{
Span<TPixel> pixelRow = pixels.DangerousGetRowSpan(y).Slice(left, width);
int byteCount = pixelRow.Length * 4;
PixelOperations<TPixel>.Instance.FromRgba32Bytes(
this.configuration,
data.Slice(offset, byteCount),
pixelRow,
pixelRow.Length);
offset += byteCount;
}
}
}
}

97
src/ImageSharp/Formats/Tiff/PhotometricInterpretation/RgbaFloat32323232TiffColor{TPixel}.cs

@ -0,0 +1,97 @@
// 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 'RGB' photometric interpretation with an alpha channel and with 32 bits for each channel.
/// </summary>
internal class RgbaFloat32323232TiffColor<TPixel> : TiffBaseColorDecoder<TPixel>
where TPixel : unmanaged, IPixel<TPixel>
{
private readonly bool isBigEndian;
/// <summary>
/// Initializes a new instance of the <see cref="RgbaFloat32323232TiffColor{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 RgbaFloat32323232TiffColor(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);
int offset = 0;
byte[] buffer = new byte[4];
for (int y = top; y < top + height; y++)
{
Span<TPixel> pixelRow = pixels.DangerousGetRowSpan(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 r = BitConverter.ToSingle(buffer, 0);
offset += 4;
data.Slice(offset, 4).CopyTo(buffer);
Array.Reverse(buffer);
float g = BitConverter.ToSingle(buffer, 0);
offset += 4;
data.Slice(offset, 4).CopyTo(buffer);
Array.Reverse(buffer);
float b = BitConverter.ToSingle(buffer, 0);
offset += 4;
data.Slice(offset, 4).CopyTo(buffer);
Array.Reverse(buffer);
float a = BitConverter.ToSingle(buffer, 0);
offset += 4;
var colorVector = new Vector4(r, g, b, a);
color.FromVector4(colorVector);
pixelRow[x] = color;
}
}
else
{
for (int x = 0; x < pixelRow.Length; x++)
{
data.Slice(offset, 4).CopyTo(buffer);
float r = BitConverter.ToSingle(buffer, 0);
offset += 4;
data.Slice(offset, 4).CopyTo(buffer);
float g = BitConverter.ToSingle(buffer, 0);
offset += 4;
data.Slice(offset, 4).CopyTo(buffer);
float b = BitConverter.ToSingle(buffer, 0);
offset += 4;
data.Slice(offset, 4).CopyTo(buffer);
float a = BitConverter.ToSingle(buffer, 0);
offset += 4;
var colorVector = new Vector4(r, g, b, a);
color.FromVector4(colorVector);
pixelRow[x] = color;
}
}
}
}
}
}

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

@ -0,0 +1,87 @@
// Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0.
using System;
using System.Buffers;
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 'RGB' photometric interpretation with an alpha channel and with 'Planar' layout (for all bit depths).
/// </summary>
internal class RgbaPlanarTiffColor<TPixel> : TiffBasePlanarColorDecoder<TPixel>
where TPixel : unmanaged, IPixel<TPixel>
{
private readonly float rFactor;
private readonly float gFactor;
private readonly float bFactor;
private readonly float aFactor;
private readonly ushort bitsPerSampleR;
private readonly ushort bitsPerSampleG;
private readonly ushort bitsPerSampleB;
private readonly ushort bitsPerSampleA;
public RgbaPlanarTiffColor(TiffBitsPerSample bitsPerSample)
{
this.bitsPerSampleR = bitsPerSample.Channel0;
this.bitsPerSampleG = bitsPerSample.Channel1;
this.bitsPerSampleB = bitsPerSample.Channel2;
this.bitsPerSampleA = bitsPerSample.Channel3;
this.rFactor = (1 << this.bitsPerSampleR) - 1.0f;
this.gFactor = (1 << this.bitsPerSampleG) - 1.0f;
this.bFactor = (1 << this.bitsPerSampleB) - 1.0f;
this.aFactor = (1 << this.bitsPerSampleA) - 1.0f;
}
/// <summary>
/// Decodes pixel data using the current photometric interpretation.
/// </summary>
/// <param name="data">The buffers to read image data from.</param>
/// <param name="pixels">The image buffer to write pixels to.</param>
/// <param name="left">The x-coordinate of the left-hand side of the image block.</param>
/// <param name="top">The y-coordinate of the top of the image block.</param>
/// <param name="width">The width of the image block.</param>
/// <param name="height">The height of the image block.</param>
public override void Decode(IMemoryOwner<byte>[] data, Buffer2D<TPixel> pixels, int left, int top, int width, int height)
{
var color = default(TPixel);
var rBitReader = new BitReader(data[0].GetSpan());
var gBitReader = new BitReader(data[1].GetSpan());
var bBitReader = new BitReader(data[2].GetSpan());
var aBitReader = new BitReader(data[3].GetSpan());
for (int y = top; y < top + height; y++)
{
Span<TPixel> pixelRow = pixels.DangerousGetRowSpan(y).Slice(left, width);
for (int x = 0; x < pixelRow.Length; x++)
{
float r = rBitReader.ReadBits(this.bitsPerSampleR) / this.rFactor;
float g = gBitReader.ReadBits(this.bitsPerSampleG) / this.gFactor;
float b = bBitReader.ReadBits(this.bitsPerSampleB) / this.bFactor;
float a = aBitReader.ReadBits(this.bitsPerSampleA) / this.aFactor;
color.FromVector4(new Vector4(r, g, b, a));
pixelRow[x] = color;
}
rBitReader.NextRow();
gBitReader.NextRow();
bBitReader.NextRow();
aBitReader.NextRow();
}
}
}
}

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

@ -0,0 +1,72 @@
// 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 'RGB' photometric interpretation with alpha channel (for all bit depths).
/// </summary>
internal class RgbaTiffColor<TPixel> : TiffBaseColorDecoder<TPixel>
where TPixel : unmanaged, IPixel<TPixel>
{
private readonly float rFactor;
private readonly float gFactor;
private readonly float bFactor;
private readonly float aFactor;
private readonly ushort bitsPerSampleR;
private readonly ushort bitsPerSampleG;
private readonly ushort bitsPerSampleB;
private readonly ushort bitsPerSampleA;
public RgbaTiffColor(TiffBitsPerSample bitsPerSample)
{
this.bitsPerSampleR = bitsPerSample.Channel0;
this.bitsPerSampleG = bitsPerSample.Channel1;
this.bitsPerSampleB = bitsPerSample.Channel2;
this.bitsPerSampleA = bitsPerSample.Channel3;
this.rFactor = (1 << this.bitsPerSampleR) - 1.0f;
this.gFactor = (1 << this.bitsPerSampleG) - 1.0f;
this.bFactor = (1 << this.bitsPerSampleB) - 1.0f;
this.aFactor = (1 << this.bitsPerSampleA) - 1.0f;
}
/// <inheritdoc/>
public override void Decode(ReadOnlySpan<byte> data, Buffer2D<TPixel> pixels, int left, int top, int width, int height)
{
var color = default(TPixel);
var bitReader = new BitReader(data);
for (int y = top; y < top + height; y++)
{
Span<TPixel> pixelRow = pixels.DangerousGetRowSpan(y).Slice(left, width);
for (int x = 0; x < pixelRow.Length; x++)
{
float r = bitReader.ReadBits(this.bitsPerSampleR) / this.rFactor;
float g = bitReader.ReadBits(this.bitsPerSampleG) / this.gFactor;
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;
}
bitReader.NextRow();
}
}
}
}

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

@ -116,6 +116,38 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
DebugGuard.IsTrue(colorMap == null, "colorMap");
return new RgbTiffColor<TPixel>(bitsPerSample);
case TiffColorType.Rgba2222:
DebugGuard.IsTrue(
bitsPerSample.Channels == 4
&& bitsPerSample.Channel3 == 2
&& bitsPerSample.Channel2 == 2
&& bitsPerSample.Channel1 == 2
&& bitsPerSample.Channel0 == 2,
"bitsPerSample");
DebugGuard.IsTrue(colorMap == null, "colorMap");
return new RgbaTiffColor<TPixel>(bitsPerSample);
case TiffColorType.Rgb333:
DebugGuard.IsTrue(
bitsPerSample.Channels == 3
&& bitsPerSample.Channel2 == 3
&& bitsPerSample.Channel1 == 3
&& bitsPerSample.Channel0 == 3,
"bitsPerSample");
DebugGuard.IsTrue(colorMap == null, "colorMap");
return new RgbTiffColor<TPixel>(bitsPerSample);
case TiffColorType.Rgba3333:
DebugGuard.IsTrue(
bitsPerSample.Channels == 4
&& bitsPerSample.Channel3 == 3
&& bitsPerSample.Channel2 == 3
&& bitsPerSample.Channel1 == 3
&& bitsPerSample.Channel0 == 3,
"bitsPerSample");
DebugGuard.IsTrue(colorMap == null, "colorMap");
return new RgbaTiffColor<TPixel>(bitsPerSample);
case TiffColorType.Rgb444:
DebugGuard.IsTrue(
bitsPerSample.Channels == 3
@ -126,6 +158,59 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
DebugGuard.IsTrue(colorMap == null, "colorMap");
return new Rgb444TiffColor<TPixel>();
case TiffColorType.Rgba4444:
DebugGuard.IsTrue(
bitsPerSample.Channels == 4
&& bitsPerSample.Channel3 == 4
&& bitsPerSample.Channel2 == 4
&& bitsPerSample.Channel1 == 4
&& bitsPerSample.Channel0 == 4,
"bitsPerSample");
DebugGuard.IsTrue(colorMap == null, "colorMap");
return new RgbaTiffColor<TPixel>(bitsPerSample);
case TiffColorType.Rgb555:
DebugGuard.IsTrue(
bitsPerSample.Channels == 3
&& bitsPerSample.Channel2 == 5
&& bitsPerSample.Channel1 == 5
&& bitsPerSample.Channel0 == 5,
"bitsPerSample");
DebugGuard.IsTrue(colorMap == null, "colorMap");
return new RgbTiffColor<TPixel>(bitsPerSample);
case TiffColorType.Rgba5555:
DebugGuard.IsTrue(
bitsPerSample.Channels == 4
&& bitsPerSample.Channel3 == 5
&& bitsPerSample.Channel2 == 5
&& bitsPerSample.Channel1 == 5
&& bitsPerSample.Channel0 == 5,
"bitsPerSample");
DebugGuard.IsTrue(colorMap == null, "colorMap");
return new RgbaTiffColor<TPixel>(bitsPerSample);
case TiffColorType.Rgb666:
DebugGuard.IsTrue(
bitsPerSample.Channels == 3
&& bitsPerSample.Channel2 == 6
&& bitsPerSample.Channel1 == 6
&& bitsPerSample.Channel0 == 6,
"bitsPerSample");
DebugGuard.IsTrue(colorMap == null, "colorMap");
return new RgbTiffColor<TPixel>(bitsPerSample);
case TiffColorType.Rgba6666:
DebugGuard.IsTrue(
bitsPerSample.Channels == 4
&& bitsPerSample.Channel3 == 6
&& bitsPerSample.Channel2 == 6
&& bitsPerSample.Channel1 == 6
&& bitsPerSample.Channel0 == 6,
"bitsPerSample");
DebugGuard.IsTrue(colorMap == null, "colorMap");
return new RgbaTiffColor<TPixel>(bitsPerSample);
case TiffColorType.Rgb888:
DebugGuard.IsTrue(
bitsPerSample.Channels == 3
@ -136,6 +221,17 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
DebugGuard.IsTrue(colorMap == null, "colorMap");
return new Rgb888TiffColor<TPixel>(configuration);
case TiffColorType.Rgba8888:
DebugGuard.IsTrue(
bitsPerSample.Channels == 4
&& bitsPerSample.Channel3 == 8
&& bitsPerSample.Channel2 == 8
&& bitsPerSample.Channel1 == 8
&& bitsPerSample.Channel0 == 8,
"bitsPerSample");
DebugGuard.IsTrue(colorMap == null, "colorMap");
return new Rgba8888TiffColor<TPixel>(configuration);
case TiffColorType.Rgb101010:
DebugGuard.IsTrue(
bitsPerSample.Channels == 3
@ -146,6 +242,17 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
DebugGuard.IsTrue(colorMap == null, "colorMap");
return new RgbTiffColor<TPixel>(bitsPerSample);
case TiffColorType.Rgba10101010:
DebugGuard.IsTrue(
bitsPerSample.Channels == 4
&& bitsPerSample.Channel3 == 10
&& bitsPerSample.Channel2 == 10
&& bitsPerSample.Channel1 == 10
&& bitsPerSample.Channel0 == 10,
"bitsPerSample");
DebugGuard.IsTrue(colorMap == null, "colorMap");
return new RgbaTiffColor<TPixel>(bitsPerSample);
case TiffColorType.Rgb121212:
DebugGuard.IsTrue(
bitsPerSample.Channels == 3
@ -156,6 +263,17 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
DebugGuard.IsTrue(colorMap == null, "colorMap");
return new RgbTiffColor<TPixel>(bitsPerSample);
case TiffColorType.Rgba12121212:
DebugGuard.IsTrue(
bitsPerSample.Channels == 4
&& bitsPerSample.Channel3 == 12
&& bitsPerSample.Channel2 == 12
&& bitsPerSample.Channel1 == 12
&& bitsPerSample.Channel0 == 12,
"bitsPerSample");
DebugGuard.IsTrue(colorMap == null, "colorMap");
return new RgbaTiffColor<TPixel>(bitsPerSample);
case TiffColorType.Rgb141414:
DebugGuard.IsTrue(
bitsPerSample.Channels == 3
@ -166,6 +284,17 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
DebugGuard.IsTrue(colorMap == null, "colorMap");
return new RgbTiffColor<TPixel>(bitsPerSample);
case TiffColorType.Rgba14141414:
DebugGuard.IsTrue(
bitsPerSample.Channels == 4
&& bitsPerSample.Channel3 == 14
&& bitsPerSample.Channel2 == 14
&& bitsPerSample.Channel1 == 14
&& bitsPerSample.Channel0 == 14,
"bitsPerSample");
DebugGuard.IsTrue(colorMap == null, "colorMap");
return new RgbaTiffColor<TPixel>(bitsPerSample);
case TiffColorType.Rgb161616:
DebugGuard.IsTrue(
bitsPerSample.Channels == 3
@ -176,6 +305,17 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
DebugGuard.IsTrue(colorMap == null, "colorMap");
return new Rgb161616TiffColor<TPixel>(configuration, isBigEndian: byteOrder == ByteOrder.BigEndian);
case TiffColorType.Rgba16161616:
DebugGuard.IsTrue(
bitsPerSample.Channels == 4
&& bitsPerSample.Channel3 == 16
&& bitsPerSample.Channel2 == 16
&& bitsPerSample.Channel1 == 16
&& bitsPerSample.Channel0 == 16,
"bitsPerSample");
DebugGuard.IsTrue(colorMap == null, "colorMap");
return new Rgba16161616TiffColor<TPixel>(configuration, isBigEndian: byteOrder == ByteOrder.BigEndian);
case TiffColorType.Rgb242424:
DebugGuard.IsTrue(
bitsPerSample.Channels == 3
@ -186,6 +326,17 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
DebugGuard.IsTrue(colorMap == null, "colorMap");
return new Rgb242424TiffColor<TPixel>(isBigEndian: byteOrder == ByteOrder.BigEndian);
case TiffColorType.Rgba24242424:
DebugGuard.IsTrue(
bitsPerSample.Channels == 4
&& bitsPerSample.Channel3 == 24
&& bitsPerSample.Channel2 == 24
&& bitsPerSample.Channel1 == 24
&& bitsPerSample.Channel0 == 24,
"bitsPerSample");
DebugGuard.IsTrue(colorMap == null, "colorMap");
return new Rgba24242424TiffColor<TPixel>(isBigEndian: byteOrder == ByteOrder.BigEndian);
case TiffColorType.Rgb323232:
DebugGuard.IsTrue(
bitsPerSample.Channels == 3
@ -196,6 +347,17 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
DebugGuard.IsTrue(colorMap == null, "colorMap");
return new Rgb323232TiffColor<TPixel>(isBigEndian: byteOrder == ByteOrder.BigEndian);
case TiffColorType.Rgba32323232:
DebugGuard.IsTrue(
bitsPerSample.Channels == 4
&& bitsPerSample.Channel3 == 32
&& bitsPerSample.Channel2 == 32
&& bitsPerSample.Channel1 == 32
&& bitsPerSample.Channel0 == 32,
"bitsPerSample");
DebugGuard.IsTrue(colorMap == null, "colorMap");
return new Rgba32323232TiffColor<TPixel>(isBigEndian: byteOrder == ByteOrder.BigEndian);
case TiffColorType.RgbFloat323232:
DebugGuard.IsTrue(
bitsPerSample.Channels == 3
@ -206,6 +368,17 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
DebugGuard.IsTrue(colorMap == null, "colorMap");
return new RgbFloat323232TiffColor<TPixel>(isBigEndian: byteOrder == ByteOrder.BigEndian);
case TiffColorType.RgbaFloat32323232:
DebugGuard.IsTrue(
bitsPerSample.Channels == 4
&& bitsPerSample.Channel3 == 32
&& bitsPerSample.Channel2 == 32
&& bitsPerSample.Channel1 == 32
&& bitsPerSample.Channel0 == 32,
"bitsPerSample");
DebugGuard.IsTrue(colorMap == null, "colorMap");
return new RgbaFloat32323232TiffColor<TPixel>(isBigEndian: byteOrder == ByteOrder.BigEndian);
case TiffColorType.PaletteColor:
DebugGuard.NotNull(colorMap, "colorMap");
return new PaletteTiffColor<TPixel>(bitsPerSample, colorMap);
@ -233,6 +406,10 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
DebugGuard.IsTrue(colorMap == null, "colorMap");
return new RgbPlanarTiffColor<TPixel>(bitsPerSample);
case TiffColorType.Rgba8888Planar:
DebugGuard.IsTrue(colorMap == null, "colorMap");
return new RgbaPlanarTiffColor<TPixel>(bitsPerSample);
case TiffColorType.YCbCrPlanar:
return new YCbCrPlanarTiffColor<TPixel>(referenceBlackAndWhite, ycbcrCoefficients, ycbcrSubSampling);
@ -240,14 +417,26 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
DebugGuard.IsTrue(colorMap == null, "colorMap");
return new Rgb16PlanarTiffColor<TPixel>(byteOrder == ByteOrder.BigEndian);
case TiffColorType.Rgba16161616Planar:
DebugGuard.IsTrue(colorMap == null, "colorMap");
return new Rgba16PlanarTiffColor<TPixel>(byteOrder == ByteOrder.BigEndian);
case TiffColorType.Rgb242424Planar:
DebugGuard.IsTrue(colorMap == null, "colorMap");
return new Rgb24PlanarTiffColor<TPixel>(byteOrder == ByteOrder.BigEndian);
case TiffColorType.Rgba24242424Planar:
DebugGuard.IsTrue(colorMap == null, "colorMap");
return new Rgba24PlanarTiffColor<TPixel>(byteOrder == ByteOrder.BigEndian);
case TiffColorType.Rgb323232Planar:
DebugGuard.IsTrue(colorMap == null, "colorMap");
return new Rgb32PlanarTiffColor<TPixel>(byteOrder == ByteOrder.BigEndian);
case TiffColorType.Rgba32323232Planar:
DebugGuard.IsTrue(colorMap == null, "colorMap");
return new Rgba32PlanarTiffColor<TPixel>(byteOrder == ByteOrder.BigEndian);
default:
throw TiffThrowHelper.InvalidColorType(colorType.ToString());
}

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

@ -103,71 +103,171 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
/// </summary>
Rgb222,
/// <summary>
/// RGBA color image with 2 bits for each channel.
/// </summary>
Rgba2222,
/// <summary>
/// RGB color image with 3 bits for each channel.
/// </summary>
Rgb333,
/// <summary>
/// RGBA color image with 3 bits for each channel.
/// </summary>
Rgba3333,
/// <summary>
/// RGB color image with 4 bits for each channel.
/// </summary>
Rgb444,
/// <summary>
/// RGBA color image with 4 bits for each channel.
/// </summary>
Rgba4444,
/// <summary>
/// RGB color image with 5 bits for each channel.
/// </summary>
Rgb555,
/// <summary>
/// RGBA color image with 5 bits for each channel.
/// </summary>
Rgba5555,
/// <summary>
/// RGB color image with 6 bits for each channel.
/// </summary>
Rgb666,
/// <summary>
/// RGBA color image with 6 bits for each channel.
/// </summary>
Rgba6666,
/// <summary>
/// RGB Full Color. Optimized implementation for 8-bit images.
/// </summary>
Rgb888,
/// <summary>
/// RGBA Full Color with 8-bit for each channel.
/// </summary>
Rgba8888,
/// <summary>
/// RGB color image with 10 bits for each channel.
/// </summary>
Rgb101010,
/// <summary>
/// RGBA color image with 10 bits for each channel.
/// </summary>
Rgba10101010,
/// <summary>
/// RGB color image with 12 bits for each channel.
/// </summary>
Rgb121212,
/// <summary>
/// RGBA color image with 12 bits for each channel.
/// </summary>
Rgba12121212,
/// <summary>
/// RGB color image with 14 bits for each channel.
/// </summary>
Rgb141414,
/// <summary>
/// RGBA color image with 14 bits for each channel.
/// </summary>
Rgba14141414,
/// <summary>
/// RGB color image with 16 bits for each channel.
/// </summary>
Rgb161616,
/// <summary>
/// RGBA color image with 16 bits for each channel.
/// </summary>
Rgba16161616,
/// <summary>
/// RGB color image with 24 bits for each channel.
/// </summary>
Rgb242424,
/// <summary>
/// RGBA color image with 24 bits for each channel.
/// </summary>
Rgba24242424,
/// <summary>
/// RGB color image with 32 bits for each channel.
/// </summary>
Rgb323232,
/// <summary>
/// RGBA color image with 32 bits for each channel.
/// </summary>
Rgba32323232,
/// <summary>
/// RGB color image with 32 bits floats for each channel.
/// </summary>
RgbFloat323232,
/// <summary>
/// RGBA color image with 32 bits floats for each channel.
/// </summary>
RgbaFloat32323232,
/// <summary>
/// RGB Full Color. Planar configuration of data. 8 Bit per color channel.
/// </summary>
Rgb888Planar,
/// <summary>
/// RGBA color image with an alpha channel. Planar configuration of data. 8 Bit per color channel.
/// </summary>
Rgba8888Planar,
/// <summary>
/// RGB Full Color. Planar configuration of data. 16 Bit per color channel.
/// </summary>
Rgb161616Planar,
/// <summary>
/// RGB Color with an alpha channel. Planar configuration of data. 16 Bit per color channel.
/// </summary>
Rgba16161616Planar,
/// <summary>
/// RGB Full Color. Planar configuration of data. 24 Bit per color channel.
/// </summary>
Rgb242424Planar,
/// <summary>
/// RGB Color with an alpha channel. Planar configuration of data. 24 Bit per color channel.
/// </summary>
Rgba24242424Planar,
/// <summary>
/// RGB Full Color. Planar configuration of data. 32 Bit per color channel.
/// </summary>
Rgb323232Planar,
/// <summary>
/// RGB Color with an alpha channel. Planar configuration of data. 32 Bit per color channel.
/// </summary>
Rgba32323232Planar,
/// <summary>
/// The pixels are stored in YCbCr format.
/// </summary>

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

@ -105,7 +105,7 @@
|Artist | Y | Y | |
|HostComputer | Y | Y | |
|ColorMap | Y | Y | |
|ExtraSamples | | - | |
|ExtraSamples | | (Y) | Only UnassociatedAlphaData is supported so far |
|Copyright | Y | Y | |
### Extension TIFF Tags

38
src/ImageSharp/Formats/Tiff/TiffBitsPerSample.cs

@ -25,6 +25,11 @@ namespace SixLabors.ImageSharp.Formats.Tiff
/// </summary>
public readonly ushort Channel2;
/// <summary>
/// The bits for the alpha channel.
/// </summary>
public readonly ushort Channel3;
/// <summary>
/// The number of channels.
/// </summary>
@ -36,16 +41,19 @@ namespace SixLabors.ImageSharp.Formats.Tiff
/// <param name="channel0">The bits for the channel 0.</param>
/// <param name="channel1">The bits for the channel 1.</param>
/// <param name="channel2">The bits for the channel 2.</param>
public TiffBitsPerSample(ushort channel0, ushort channel1, ushort channel2)
/// <param name="channel3">The bits for the channel 3.</param>
public TiffBitsPerSample(ushort channel0, ushort channel1, ushort channel2, ushort channel3 = 0)
{
this.Channel0 = (ushort)Numerics.Clamp(channel0, 0, 32);
this.Channel1 = (ushort)Numerics.Clamp(channel1, 0, 32);
this.Channel2 = (ushort)Numerics.Clamp(channel2, 0, 32);
this.Channel3 = (ushort)Numerics.Clamp(channel3, 0, 32);
this.Channels = 0;
this.Channels += (byte)(this.Channel0 != 0 ? 1 : 0);
this.Channels += (byte)(this.Channel1 != 0 ? 1 : 0);
this.Channels += (byte)(this.Channel2 != 0 ? 1 : 0);
this.Channels += (byte)(this.Channel3 != 0 ? 1 : 0);
}
/// <summary>
@ -62,11 +70,19 @@ namespace SixLabors.ImageSharp.Formats.Tiff
return false;
}
ushort c3 = 0;
ushort c2;
ushort c1;
ushort c0;
switch (value.Length)
{
case 4:
c3 = value[3];
c2 = value[2];
c1 = value[1];
c0 = value[0];
break;
case 3:
c2 = value[2];
c1 = value[1];
@ -84,7 +100,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff
break;
}
sample = new TiffBitsPerSample(c0, c1, c2);
sample = new TiffBitsPerSample(c0, c1, c2, c3);
return true;
}
@ -96,11 +112,12 @@ namespace SixLabors.ImageSharp.Formats.Tiff
public bool Equals(TiffBitsPerSample other)
=> this.Channel0 == other.Channel0
&& this.Channel1 == other.Channel1
&& this.Channel2 == other.Channel2;
&& this.Channel2 == other.Channel2
&& this.Channel3 == other.Channel3;
/// <inheritdoc/>
public override int GetHashCode()
=> HashCode.Combine(this.Channel0, this.Channel1, this.Channel2);
=> HashCode.Combine(this.Channel0, this.Channel1, this.Channel2, this.Channel3);
/// <summary>
/// Converts the bits per sample struct to an ushort array.
@ -118,7 +135,12 @@ namespace SixLabors.ImageSharp.Formats.Tiff
return new[] { this.Channel0, this.Channel1 };
}
return new[] { this.Channel0, this.Channel1, this.Channel2 };
if (this.Channel3 == 0)
{
return new[] { this.Channel0, this.Channel1, this.Channel2 };
}
return new[] { this.Channel0, this.Channel1, this.Channel2, this.Channel3 };
}
/// <summary>
@ -127,12 +149,14 @@ namespace SixLabors.ImageSharp.Formats.Tiff
/// <returns>Bits per pixel.</returns>
public TiffBitsPerPixel BitsPerPixel()
{
int bitsPerPixel = this.Channel0 + this.Channel1 + this.Channel2;
int bitsPerPixel = this.Channel0 + this.Channel1 + this.Channel2 + this.Channel3;
return (TiffBitsPerPixel)bitsPerPixel;
}
/// <inheritdoc/>
public override string ToString()
=> $"TiffBitsPerSample({this.Channel0}, {this.Channel1}, {this.Channel2})";
=> this.Channel3 is 0 ?
$"TiffBitsPerSample({this.Channel0}, {this.Channel1}, {this.Channel2})"
: $"TiffBitsPerSample({this.Channel0}, {this.Channel1}, {this.Channel2}, {this.Channel3})";
}
}

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

@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff
/// <summary>
/// Gets the decoding mode for multi-frame images
/// </summary>
private FrameDecodingMode decodingMode;
private readonly FrameDecodingMode decodingMode;
/// <summary>
/// The stream to decode from.
@ -117,6 +117,11 @@ namespace SixLabors.ImageSharp.Formats.Tiff
/// </summary>
public TiffFillOrder FillOrder { get; set; }
/// <summary>
/// Gets or sets the extra samples, which can contain the alpha channel data.
/// </summary>
public TiffExtraSampleType? ExtraSamples { get; set; }
/// <summary>
/// Gets or sets the JPEG tables when jpeg compression is used.
/// </summary>
@ -275,12 +280,10 @@ namespace SixLabors.ImageSharp.Formats.Tiff
return memory;
}
else
{
DebugGuard.IsTrue(array is ulong[], $"Expected {nameof(UInt64)} array.");
span = (ulong[])array;
return null;
}
DebugGuard.IsTrue(array is ulong[], $"Expected {nameof(UInt64)} array.");
span = (ulong[])array;
return null;
}
/// <summary>
@ -314,8 +317,11 @@ namespace SixLabors.ImageSharp.Formats.Tiff
case 2:
bitsPerPixel = this.BitsPerSample.Channel2;
break;
case 3:
bitsPerPixel = this.BitsPerSample.Channel2;
break;
default:
TiffThrowHelper.ThrowNotSupported("More then 3 color channels are not supported");
TiffThrowHelper.ThrowNotSupported("More then 4 color channels are not supported");
break;
}
}

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

@ -29,9 +29,21 @@ namespace SixLabors.ImageSharp.Formats.Tiff
TiffThrowHelper.ThrowNotSupported("Tiled images are not supported.");
}
if (exifProfile.GetValueInternal(ExifTag.ExtraSamples) is not null)
IExifValue extraSamplesExifValue = exifProfile.GetValueInternal(ExifTag.ExtraSamples);
if (extraSamplesExifValue is not null)
{
TiffThrowHelper.ThrowNotSupported("ExtraSamples is not supported.");
short[] extraSamples = (short[])extraSamplesExifValue.GetValue();
if (extraSamples.Length != 1)
{
TiffThrowHelper.ThrowNotSupported("ExtraSamples is only supported with one extra sample for alpha data.");
}
var extraSamplesType = (TiffExtraSampleType)extraSamples[0];
options.ExtraSamples = extraSamplesType;
if (extraSamplesType is not TiffExtraSampleType.UnassociatedAlphaData)
{
TiffThrowHelper.ThrowNotSupported("Decoding Tiff images with ExtraSamples is only supported with UnassociatedAlphaData.");
}
}
TiffFillOrder fillOrder = (TiffFillOrder?)exifProfile.GetValue(ExifTag.FillOrder)?.Value ?? TiffFillOrder.MostSignificantBitFirst;
@ -52,7 +64,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff
sampleFormat = sampleFormats[0];
foreach (TiffSampleFormat format in sampleFormats)
{
if (format != TiffSampleFormat.UnsignedInteger && format != TiffSampleFormat.Float)
if (format is not TiffSampleFormat.UnsignedInteger and not TiffSampleFormat.Float)
{
TiffThrowHelper.ThrowNotSupported("ImageSharp only supports the UnsignedInteger and Float SampleFormat.");
}
@ -252,12 +264,13 @@ namespace SixLabors.ImageSharp.Formats.Tiff
case TiffPhotometricInterpretation.Rgb:
{
TiffBitsPerSample bitsPerSample = options.BitsPerSample;
if (bitsPerSample.Channels != 3)
if (bitsPerSample.Channels is not (3 or 4))
{
TiffThrowHelper.ThrowNotSupported("The number of samples in the TIFF BitsPerSample entry is not supported.");
}
if (!(bitsPerSample.Channel0 == bitsPerSample.Channel1 && bitsPerSample.Channel1 == bitsPerSample.Channel2))
if ((bitsPerSample.Channels == 3 && !(bitsPerSample.Channel0 == bitsPerSample.Channel1 && bitsPerSample.Channel1 == bitsPerSample.Channel2)) ||
(bitsPerSample.Channels == 4 && !(bitsPerSample.Channel0 == bitsPerSample.Channel1 && bitsPerSample.Channel1 == bitsPerSample.Channel2 && bitsPerSample.Channel2 == bitsPerSample.Channel3)))
{
TiffThrowHelper.ThrowNotSupported("Only BitsPerSample with equal bits per channel are supported.");
}
@ -270,41 +283,50 @@ namespace SixLabors.ImageSharp.Formats.Tiff
case 32:
if (options.SampleFormat == TiffSampleFormat.Float)
{
options.ColorType = TiffColorType.RgbFloat323232;
options.ColorType = options.BitsPerSample.Channels is 3 ? TiffColorType.RgbFloat323232 : TiffColorType.RgbaFloat32323232;
return;
}
options.ColorType = TiffColorType.Rgb323232;
options.ColorType = options.BitsPerSample.Channels is 3 ? TiffColorType.Rgb323232 : TiffColorType.Rgba32323232;
break;
case 24:
options.ColorType = TiffColorType.Rgb242424;
options.ColorType = options.BitsPerSample.Channels is 3 ? TiffColorType.Rgb242424 : TiffColorType.Rgba24242424;
break;
case 16:
options.ColorType = TiffColorType.Rgb161616;
options.ColorType = options.BitsPerSample.Channels is 3 ? TiffColorType.Rgb161616 : TiffColorType.Rgba16161616;
break;
case 14:
options.ColorType = TiffColorType.Rgb141414;
options.ColorType = options.BitsPerSample.Channels is 3 ? TiffColorType.Rgb141414 : TiffColorType.Rgba14141414;
break;
case 12:
options.ColorType = TiffColorType.Rgb121212;
options.ColorType = options.BitsPerSample.Channels is 3 ? TiffColorType.Rgb121212 : TiffColorType.Rgba12121212;
break;
case 10:
options.ColorType = TiffColorType.Rgb101010;
options.ColorType = options.BitsPerSample.Channels is 3 ? TiffColorType.Rgb101010 : TiffColorType.Rgba10101010;
break;
case 8:
options.ColorType = TiffColorType.Rgb888;
options.ColorType = options.BitsPerSample.Channels is 3 ? TiffColorType.Rgb888 : TiffColorType.Rgba8888;
break;
case 6:
options.ColorType = options.BitsPerSample.Channels is 3 ? TiffColorType.Rgb666 : TiffColorType.Rgba6666;
break;
case 5:
options.ColorType = options.BitsPerSample.Channels is 3 ? TiffColorType.Rgb555 : TiffColorType.Rgba5555;
break;
case 4:
options.ColorType = TiffColorType.Rgb444;
options.ColorType = options.BitsPerSample.Channels is 3 ? TiffColorType.Rgb444 : TiffColorType.Rgba4444;
break;
case 3:
options.ColorType = options.BitsPerSample.Channels is 3 ? TiffColorType.Rgb333 : TiffColorType.Rgba3333;
break;
case 2:
options.ColorType = TiffColorType.Rgb222;
options.ColorType = options.BitsPerSample.Channels is 3 ? TiffColorType.Rgb222 : TiffColorType.Rgba2222;
break;
default:
TiffThrowHelper.ThrowNotSupported("Bits per sample is not supported.");
@ -317,16 +339,16 @@ namespace SixLabors.ImageSharp.Formats.Tiff
switch (bitsPerChannel)
{
case 32:
options.ColorType = TiffColorType.Rgb323232Planar;
options.ColorType = options.BitsPerSample.Channels is 3 ? TiffColorType.Rgb323232Planar : TiffColorType.Rgba32323232Planar;
break;
case 24:
options.ColorType = TiffColorType.Rgb242424Planar;
options.ColorType = options.BitsPerSample.Channels is 3 ? TiffColorType.Rgb242424Planar : TiffColorType.Rgba24242424Planar;
break;
case 16:
options.ColorType = TiffColorType.Rgb161616Planar;
options.ColorType = options.BitsPerSample.Channels is 3 ? TiffColorType.Rgb161616Planar : TiffColorType.Rgba16161616Planar;
break;
default:
options.ColorType = TiffColorType.Rgb888Planar;
options.ColorType = options.BitsPerSample.Channels is 3 ? TiffColorType.Rgb888Planar : TiffColorType.Rgba8888Planar;
break;
}
}

27
src/ImageSharp/Formats/Tiff/TiffExtraSampleType.cs

@ -0,0 +1,27 @@
// Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0.
namespace SixLabors.ImageSharp.Formats.Tiff
{
/// <summary>
/// Description of extra components.
/// </summary>
internal enum TiffExtraSampleType
{
/// <summary>
/// The data is unspecified, not supported.
/// </summary>
UnspecifiedData = 0,
/// <summary>
/// The extra data is associated alpha data (with pre-multiplied color).
/// </summary>
AssociatedAlphaData = 1,
/// <summary>
/// The extra data is unassociated alpha data is transparency information that logically exists independent of an image;
/// it is commonly called a soft matte.
/// </summary>
UnassociatedAlphaData = 2
}
}

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

@ -18,11 +18,11 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Utils
private const float Scale32Bit = 1.0f / 0xFFFFFFFF;
public static Vector4 Vector4Default { get; } = new Vector4(0.0f, 0.0f, 0.0f, 0.0f);
public static Vector4 Vector4Default { get; } = new(0.0f, 0.0f, 0.0f, 0.0f);
public static Rgba64 Rgba64Default { get; } = new Rgba64(0, 0, 0, 0);
public static Rgba64 Rgba64Default { get; } = new(0, 0, 0, 0);
public static L16 L16Default { get; } = new L16(0);
public static L16 L16Default { get; } = new(0);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ushort ConvertToUShortBigEndian(ReadOnlySpan<byte> buffer) => BinaryPrimitives.ReadUInt16BigEndian(buffer);
@ -54,6 +54,15 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Utils
return color;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static TPixel ColorFromRgba64<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);
color.FromRgba64(rgba);
return color;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static TPixel ColorScaleTo24Bit<TPixel>(ulong r, ulong g, ulong b, TPixel color)
where TPixel : unmanaged, IPixel<TPixel>
@ -63,6 +72,15 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Utils
return color;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static TPixel ColorScaleTo24Bit<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);
color.FromVector4(colorVector);
return color;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static TPixel ColorScaleTo32Bit<TPixel>(ulong r, ulong g, ulong b, TPixel color)
where TPixel : unmanaged, IPixel<TPixel>
@ -72,6 +90,15 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Utils
return color;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static TPixel ColorScaleTo32Bit<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);
color.FromVector4(colorVector);
return color;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static TPixel ColorFromL16<TPixel>(L16 l16, ushort intensity, TPixel color)
where TPixel : unmanaged, IPixel<TPixel>

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

@ -78,9 +78,42 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff
[Theory]
[WithFile(FlowerRgb888Planar6Strips, PixelTypes.Rgba32)]
[WithFile(FlowerRgb888Planar15Strips, PixelTypes.Rgba32)]
public void TiffDecoder_Planar<TPixel>(TestImageProvider<TPixel> provider)
public void TiffDecoder_CanDecode_Planar<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel> => TestTiffDecoder(provider);
[Theory]
[WithFile(Rgba8BitPlanarUnassociatedAlpha, PixelTypes.Rgba32)]
public void TiffDecoder_CanDecode_Planar_32Bit<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel> => TestTiffDecoder(provider);
[Theory]
[WithFile(Rgba16BitPlanarUnassociatedAlphaLittleEndian, PixelTypes.Rgba32)]
[WithFile(Rgba16BitPlanarUnassociatedAlphaBigEndian, PixelTypes.Rgba32)]
public void TiffDecoder_CanDecode_Planar_64Bit<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel> => TestTiffDecoder(provider);
[Theory]
[WithFile(Rgba24BitPlanarUnassociatedAlphaLittleEndian, PixelTypes.Rgba32)]
[WithFile(Rgba24BitPlanarUnassociatedAlphaBigEndian, PixelTypes.Rgba32)]
public void TiffDecoder_CanDecode_Planar_96Bit<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(Rgba32BitPlanarUnassociatedAlphaLittleEndian, PixelTypes.Rgba32)]
[WithFile(Rgba32BitPlanarUnassociatedAlphaBigEndian, PixelTypes.Rgba32)]
public void TiffDecoder_CanDecode_Planar_128Bit<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(Calliphora_PaletteUncompressed, PixelTypes.Rgba32)]
[WithFile(PaletteDeflateMultistrip, PixelTypes.Rgba32)]
@ -123,6 +156,16 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff
public void TiffDecoder_CanDecode_8Bit_Gray<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel> => TestTiffDecoder(provider);
[Theory]
[WithFile(Rgba2BitUnassociatedAlpha, PixelTypes.Rgba32)]
public void TiffDecoder_CanDecode_8Bit_WithUnassociatedAlpha<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel> => TestTiffDecoder(provider);
[Theory]
[WithFile(FLowerRgb3Bit, PixelTypes.Rgba32)]
public void TiffDecoder_CanDecode_9Bit_WithUnassociatedAlpha<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel> => TestTiffDecoder(provider);
[Theory]
[WithFile(Flower10BitGray, PixelTypes.Rgba32)]
public void TiffDecoder_CanDecode_10Bit_Gray<TPixel>(TestImageProvider<TPixel> provider)
@ -139,11 +182,21 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff
public void TiffDecoder_CanDecode_12Bit_Gray<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel> => TestTiffDecoder(provider);
[Theory]
[WithFile(Rgba3BitUnassociatedAlpha, PixelTypes.Rgba32)]
public void TiffDecoder_CanDecode_12Bit_WithUnassociatedAlpha<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel> => TestTiffDecoder(provider);
[Theory]
[WithFile(Flower14BitGray, PixelTypes.Rgba32)]
public void TiffDecoder_CanDecode_14Bit_Gray<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel> => TestTiffDecoder(provider);
[Theory]
[WithFile(FLowerRgb5Bit, PixelTypes.Rgba32)]
public void TiffDecoder_CanDecode_15Bit<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel> => TestTiffDecoder(provider);
[Theory]
[WithFile(Flower16BitGrayLittleEndian, PixelTypes.Rgba32)]
[WithFile(Flower16BitGray, PixelTypes.Rgba32)]
@ -158,6 +211,31 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff
public void TiffDecoder_CanDecode_16Bit_Gray_WithPredictor<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel> => TestTiffDecoder(provider);
[Theory]
[WithFile(Rgba4BitUnassociatedAlpha, PixelTypes.Rgba32)]
public void TiffDecoder_CanDecode_16Bit_WithUnassociatedAlpha<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel> => TestTiffDecoder(provider);
[Theory]
[WithFile(FLowerRgb6Bit, PixelTypes.Rgba32)]
public void TiffDecoder_CanDecode_18Bit<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel> => TestTiffDecoder(provider);
[Theory]
[WithFile(Rgba5BitUnassociatedAlpha, PixelTypes.Rgba32)]
public void TiffDecoder_CanDecode_20Bit_WithUnassociatedAlpha<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel> => TestTiffDecoder(provider);
[Theory]
[WithFile(FlowerRgb888Contiguous, PixelTypes.Rgba32)]
public void TiffDecoder_CanDecode_24Bit<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel> => TestTiffDecoder(provider);
[Theory]
[WithFile(Rgba6BitUnassociatedAlpha, PixelTypes.Rgba32)]
public void TiffDecoder_CanDecode_24Bit_WithUnassociatedAlpha<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel> => TestTiffDecoder(provider);
[Theory]
[WithFile(Flower24BitGray, PixelTypes.Rgba32)]
[WithFile(Flower24BitGrayLittleEndian, PixelTypes.Rgba32)]
@ -207,6 +285,16 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff
image.DebugSave(provider);
}
[Theory]
[WithFile(Rgba8BitUnassociatedAlpha, PixelTypes.Rgba32)]
public void TiffDecoder_CanDecode_32Bit_WithUnassociatedAlpha<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(Flower32BitGrayPredictorBigEndian, PixelTypes.Rgba32)]
[WithFile(Flower32BitGrayPredictorLittleEndian, PixelTypes.Rgba32)]
@ -223,6 +311,12 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff
public void TiffDecoder_CanDecode_36Bit<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel> => TestTiffDecoder(provider);
[Theory]
[WithFile(Rgba10BitUnassociatedAlphaBigEndian, PixelTypes.Rgba32)]
[WithFile(Rgba10BitUnassociatedAlphaLittleEndian, PixelTypes.Rgba32)]
public void TiffDecoder_CanDecode_40Bit_WithUnassociatedAlpha<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel> => TestTiffDecoder(provider);
[Theory]
[WithFile(FlowerRgb141414Contiguous, PixelTypes.Rgba32)]
[WithFile(FlowerRgb141414Planar, PixelTypes.Rgba32)]
@ -238,12 +332,24 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff
public void TiffDecoder_CanDecode_48Bit<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel> => TestTiffDecoder(provider);
[Theory]
[WithFile(Rgba12BitUnassociatedAlphaBigEndian, PixelTypes.Rgba32)]
[WithFile(Rgba12BitUnassociatedAlphaLittleEndian, PixelTypes.Rgba32)]
public void TiffDecoder_CanDecode_48Bit_WithUnassociatedAlpha<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel> => TestTiffDecoder(provider);
[Theory]
[WithFile(FlowerRgb161616PredictorBigEndian, PixelTypes.Rgba32)]
[WithFile(FlowerRgb161616PredictorLittleEndian, PixelTypes.Rgba32)]
public void TiffDecoder_CanDecode_48Bit_WithPredictor<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel> => TestTiffDecoder(provider);
[Theory]
[WithFile(Rgba14BitUnassociatedAlphaBigEndian, PixelTypes.Rgba32)]
[WithFile(Rgba14BitUnassociatedAlphaLittleEndian, PixelTypes.Rgba32)]
public void TiffDecoder_CanDecode_56Bit_WithUnassociatedAlpha<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel> => TestTiffDecoder(provider);
[Theory]
[WithFile(FlowerRgb242424Contiguous, PixelTypes.Rgba32)]
[WithFile(FlowerRgb242424ContiguousLittleEndian, PixelTypes.Rgba32)]
@ -270,6 +376,17 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff
image.DebugSave(provider);
}
[Theory]
[WithFile(Rgba24BitUnassociatedAlphaBigEndian, PixelTypes.Rgba32)]
[WithFile(Rgba24BitUnassociatedAlphaLittleEndian, PixelTypes.Rgba32)]
public void TiffDecoder_CanDecode_96Bit_WithUnassociatedAlpha<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(FlowerRgbFloat323232, PixelTypes.Rgba32)]
[WithFile(FlowerRgbFloat323232LittleEndian, PixelTypes.Rgba32)]
@ -305,6 +422,23 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff
image.DebugSave(provider);
}
[Theory]
[WithFile(Rgba16BitUnassociatedAlphaBigEndian, PixelTypes.Rgba32)]
[WithFile(Rgba16BitUnassociatedAlphaLittleEndian, PixelTypes.Rgba32)]
public void TiffDecoder_CanDecode_128Bit_UnassociatedAlpha<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel> => TestTiffDecoder(provider);
[Theory]
[WithFile(Rgba32BitUnassociatedAlphaBigEndian, PixelTypes.Rgba32)]
[WithFile(Rgba32BitUnassociatedAlphaLittleEndian, PixelTypes.Rgba32)]
public void TiffDecoder_CanDecode_128Bit_WithUnassociatedAlpha<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)]

30
tests/ImageSharp.Tests/TestImages.cs

@ -831,6 +831,9 @@ namespace SixLabors.ImageSharp.Tests
public const string Flower2BitPalette = "Tiff/flower-palette-02.tiff";
public const string Flower4BitPalette = "Tiff/flower-palette-04.tiff";
public const string Flower4BitPaletteGray = "Tiff/flower-minisblack-04.tiff";
public const string FLowerRgb3Bit = "Tiff/flower-rgb-3bit.tiff";
public const string FLowerRgb5Bit = "Tiff/flower-rgb-5bit.tiff";
public const string FLowerRgb6Bit = "Tiff/flower-rgb-6bit.tiff";
public const string Flower6BitGray = "Tiff/flower-minisblack-06.tiff";
public const string Flower8BitGray = "Tiff/flower-minisblack-08.tiff";
public const string Flower10BitGray = "Tiff/flower-minisblack-10.tiff";
@ -855,6 +858,33 @@ namespace SixLabors.ImageSharp.Tests
public const string Flower32BitGrayPredictorBigEndian = "Tiff/flower-minisblack-32_msb_deflate_predictor.tiff";
public const string Flower32BitGrayPredictorLittleEndian = "Tiff/flower-minisblack-32_lsb_deflate_predictor.tiff";
// Images with alpha channel.
public const string Rgba2BitUnassociatedAlpha = "Tiff/RgbaUnassociatedAlpha2bit.tiff";
public const string Rgba3BitUnassociatedAlpha = "Tiff/RgbaUnassociatedAlpha3bit.tiff";
public const string Rgba4BitUnassociatedAlpha = "Tiff/RgbaUnassociatedAlpha4bit.tiff";
public const string Rgba5BitUnassociatedAlpha = "Tiff/RgbaUnassociatedAlpha5bit.tiff";
public const string Rgba6BitUnassociatedAlpha = "Tiff/RgbaUnassociatedAlpha6bit.tiff";
public const string Rgba8BitUnassociatedAlpha = "Tiff/RgbaUnassociatedAlpha8bit.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 Rgba12BitUnassociatedAlphaBigEndian = "Tiff/RgbaUnassociatedAlpha12bit_msb.tiff";
public const string Rgba12BitUnassociatedAlphaLittleEndian = "Tiff/RgbaUnassociatedAlpha12bit_lsb.tiff";
public const string Rgba14BitUnassociatedAlphaBigEndian = "Tiff/RgbaUnassociatedAlpha14bit_msb.tiff";
public const string Rgba14BitUnassociatedAlphaLittleEndian = "Tiff/RgbaUnassociatedAlpha14bit_lsb.tiff";
public const string Rgba16BitUnassociatedAlphaBigEndian = "Tiff/RgbaUnassociatedAlpha16bit_msb.tiff";
public const string Rgba16BitUnassociatedAlphaLittleEndian = "Tiff/RgbaUnassociatedAlpha16bit_lsb.tiff";
public const string Rgba16BitPlanarUnassociatedAlphaBigEndian = "Tiff/RgbaUnassociatedAlphaPlanar16bit_msb.tiff";
public const string Rgba16BitPlanarUnassociatedAlphaLittleEndian = "Tiff/RgbaUnassociatedAlphaPlanar16bit_lsb.tiff";
public const string Rgba24BitUnassociatedAlphaBigEndian = "Tiff/RgbaUnassociatedAlpha24bit_msb.tiff";
public const string Rgba24BitUnassociatedAlphaLittleEndian = "Tiff/RgbaUnassociatedAlpha24bit_lsb.tiff";
public const string Rgba24BitPlanarUnassociatedAlphaBigEndian = "Tiff/RgbaUnassociatedAlphaPlanar24bit_msb.tiff";
public const string Rgba24BitPlanarUnassociatedAlphaLittleEndian = "Tiff/RgbaUnassociatedAlphaPlanar24bit_lsb.tiff";
public const string Rgba32BitUnassociatedAlphaBigEndian = "Tiff/RgbaUnassociatedAlpha32bit_msb.tiff";
public const string Rgba32BitUnassociatedAlphaLittleEndian = "Tiff/RgbaUnassociatedAlpha32bit_lsb.tiff";
public const string Rgba32BitPlanarUnassociatedAlphaBigEndian = "Tiff/RgbaUnassociatedAlphaPlanar32bit_msb.tiff";
public const string Rgba32BitPlanarUnassociatedAlphaLittleEndian = "Tiff/RgbaUnassociatedAlphaPlanar32bit_lsb.tiff";
public const string Issues1716Rgb161616BitLittleEndian = "Tiff/Issues/Issue1716.tiff";
public const string Issues1891 = "Tiff/Issues/Issue1891.tiff";

4
tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/MagickReferenceDecoder.cs

@ -84,13 +84,13 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ReferenceCodecs
MemoryGroup<TPixel> framePixels = frame.PixelBuffer.FastMemoryGroup;
using IUnsafePixelCollection<ushort> pixels = magicFrame.GetPixelsUnsafe();
if (magicFrame.Depth == 8 || magicFrame.Depth == 6 || magicFrame.Depth == 4 || magicFrame.Depth == 2 || magicFrame.Depth == 1 || magicFrame.Depth == 10 || magicFrame.Depth == 12)
if (magicFrame.Depth is 12 or 10 or 8 or 6 or 5 or 4 or 3 or 2 or 1)
{
byte[] data = pixels.ToByteArray(PixelMapping.RGBA);
FromRgba32Bytes(configuration, data, framePixels);
}
else if (magicFrame.Depth == 16 || magicFrame.Depth == 14)
else if (magicFrame.Depth is 16 or 14)
{
ushort[] data = pixels.ToShortArray(PixelMapping.RGBA);
Span<byte> bytes = MemoryMarshal.Cast<ushort, byte>(data.AsSpan());

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

3
tests/Images/Input/Tiff/flower-rgb-3bit.tiff

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

3
tests/Images/Input/Tiff/flower-rgb-5bit.tiff

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

3
tests/Images/Input/Tiff/flower-rgb-6bit.tiff

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