diff --git a/src/ImageSharp/Formats/Tiff/Constants/TiffCompression.cs b/src/ImageSharp/Formats/Tiff/Constants/TiffCompression.cs
index 0baf4c89c..765f2c237 100644
--- a/src/ImageSharp/Formats/Tiff/Constants/TiffCompression.cs
+++ b/src/ImageSharp/Formats/Tiff/Constants/TiffCompression.cs
@@ -23,11 +23,6 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Constants
///
Ccitt1D = 2,
- ///
- /// PackBits compression
- ///
- PackBits = 32773,
-
///
/// T4-encoding: CCITT T.4 bi-level encoding (see Section 11 of the TIFF 6.0 specification).
///
@@ -65,27 +60,48 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Constants
Deflate = 8,
///
- /// 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.
///
- OldDeflate = 32946,
+ ItuTRecT82 = 9,
///
- /// 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.
///
- ItuTRecT82 = 9,
+ ItuTRecT43 = 10,
///
- /// 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.
+ ///
+ NeXT = 32766,
+
+ ///
+ /// PackBits compression.
+ ///
+ PackBits = 32773,
+
+ ///
+ /// 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.
///
- ItuTRecT43 = 10
+ ThunderScan = 32809,
+
+ ///
+ /// Deflate compression - old.
+ ///
+ /// Note: The TIFF encoder does not support this compression and will default to use no compression instead,
+ /// if this is chosen.
+ ///
+ OldDeflate = 32946,
}
}
diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgb161616TiffColor{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgb161616TiffColor{TPixel}.cs
index a4d725bcf..bc7cd317c 100644
--- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgb161616TiffColor{TPixel}.cs
+++ b/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
diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgb16PlanarTiffColor{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgb16PlanarTiffColor{TPixel}.cs
index 1c61b0991..a415395a5 100644
--- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgb16PlanarTiffColor{TPixel}.cs
+++ b/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);
}
}
}
diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba16161616TiffColor{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba16161616TiffColor{TPixel}.cs
index 7fd8d9879..d0a80bf0d 100644
--- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba16161616TiffColor{TPixel}.cs
+++ b/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;
+
///
/// Initializes a new instance of the class.
///
/// The configuration.
+ /// The memory allocator.
/// if set to true decodes the pixel data as big endian, otherwise as little endian.
- public Rgba16161616TiffColor(Configuration configuration, bool isBigEndian)
+ /// The type of the extra samples.
+ public Rgba16161616TiffColor(Configuration configuration, MemoryAllocator memoryAllocator, TiffExtraSampleType? extraSamplesType, bool isBigEndian)
{
this.configuration = configuration;
this.isBigEndian = isBigEndian;
+ this.memoryAllocator = memoryAllocator;
+ this.extraSamplesType = extraSamplesType;
}
///
@@ -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 vectors = hasAssociatedAlpha ? this.memoryAllocator.Allocate(width) : null;
+ Span vectorsSpan = hasAssociatedAlpha ? vectors.GetSpan() : Span.Empty;
for (int y = top; y < top + height; y++)
{
Span 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.Instance.ToVector4(this.configuration, pixelRow, vectorsSpan);
+ TiffUtils.UnPremultiplyRow(vectorsSpan, pixelRow, color);
+ }
+
offset += byteCount;
}
}
diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba16PlanarTiffColor{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba16PlanarTiffColor{TPixel}.cs
index 705010ce9..a9d38a4be 100644
--- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba16PlanarTiffColor{TPixel}.cs
+++ b/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;
+
///
/// Initializes a new instance of the class.
///
- /// if set to true decodes the pixel data as big endian, otherwise as little endian.
- public Rgba16PlanarTiffColor(bool isBigEndian) => this.isBigEndian = isBigEndian;
+ /// The extra samples type.
+ /// If set to true decodes the pixel data as big endian, otherwise as little endian.
+ public Rgba16PlanarTiffColor(TiffExtraSampleType? extraSamplesType, bool isBigEndian)
+ {
+ this.extraSamplesType = extraSamplesType;
+ this.isBigEndian = isBigEndian;
+ }
///
public override void Decode(IMemoryOwner[] data, Buffer2D pixels, int left, int top, int width, int height)
@@ -37,6 +44,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
Span blueData = data[2].GetSpan();
Span 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);
}
}
}
diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba24242424TiffColor{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba24242424TiffColor{TPixel}.cs
index 71e1f7abd..7f754d7f5 100644
--- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba24242424TiffColor{TPixel}.cs
+++ b/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;
+
///
/// Initializes a new instance of the class.
///
+ /// The type of the extra samples.
/// if set to true decodes the pixel data as big endian, otherwise as little endian.
- public Rgba24242424TiffColor(bool isBigEndian) => this.isBigEndian = isBigEndian;
+ public Rgba24242424TiffColor(TiffExtraSampleType? extraSamplesType, bool isBigEndian)
+ {
+ this.extraSamplesType = extraSamplesType;
+ this.isBigEndian = isBigEndian;
+ }
///
public override void Decode(ReadOnlySpan data, Buffer2D 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 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);
}
}
}
diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba24PlanarTiffColor{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba24PlanarTiffColor{TPixel}.cs
index 03b78c3f8..a3cdd2432 100644
--- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba24PlanarTiffColor{TPixel}.cs
+++ b/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;
+
///
/// Initializes a new instance of the class.
///
+ /// The extra samples type.
/// if set to true decodes the pixel data as big endian, otherwise as little endian.
- public Rgba24PlanarTiffColor(bool isBigEndian) => this.isBigEndian = isBigEndian;
+ public Rgba24PlanarTiffColor(TiffExtraSampleType? extraSamplesType, bool isBigEndian)
+ {
+ this.extraSamplesType = extraSamplesType;
+ this.isBigEndian = isBigEndian;
+ }
///
public override void Decode(IMemoryOwner[] data, Buffer2D pixels, int left, int top, int width, int height)
@@ -39,6 +46,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
Span alphaData = data[3].GetSpan();
Span 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);
}
}
}
diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba32323232TiffColor{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba32323232TiffColor{TPixel}.cs
index fbd18ca3e..96ff32308 100644
--- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba32323232TiffColor{TPixel}.cs
+++ b/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;
+
///
/// Initializes a new instance of the class.
///
+ /// The type of the extra samples.
/// if set to true decodes the pixel data as big endian, otherwise as little endian.
- public Rgba32323232TiffColor(bool isBigEndian) => this.isBigEndian = isBigEndian;
+ public Rgba32323232TiffColor(TiffExtraSampleType? extraSamplesType, bool isBigEndian)
+ {
+ this.extraSamplesType = extraSamplesType;
+ this.isBigEndian = isBigEndian;
+ }
///
public override void Decode(ReadOnlySpan data, Buffer2D 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);
}
}
}
diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba32PlanarTiffColor{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba32PlanarTiffColor{TPixel}.cs
index e23111159..3f7567fc7 100644
--- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba32PlanarTiffColor{TPixel}.cs
+++ b/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;
+
///
/// Initializes a new instance of the class.
///
+ /// The extra samples type.
/// if set to true decodes the pixel data as big endian, otherwise as little endian.
- public Rgba32PlanarTiffColor(bool isBigEndian) => this.isBigEndian = isBigEndian;
+ public Rgba32PlanarTiffColor(TiffExtraSampleType? extraSamplesType, bool isBigEndian)
+ {
+ this.extraSamplesType = extraSamplesType;
+ this.isBigEndian = isBigEndian;
+ }
///
public override void Decode(IMemoryOwner[] data, Buffer2D pixels, int left, int top, int width, int height)
@@ -36,6 +43,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
Span blueData = data[2].GetSpan();
Span 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);
}
}
}
diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba8888TiffColor{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba8888TiffColor{TPixel}.cs
index 491a42fb7..e43222090 100644
--- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba8888TiffColor{TPixel}.cs
+++ b/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;
+ }
///
public override void Decode(ReadOnlySpan data, Buffer2D 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 vectors = hasAssociatedAlpha ? this.memoryAllocator.Allocate(width) : null;
+ Span vectorsSpan = hasAssociatedAlpha ? vectors.GetSpan() : Span.Empty;
for (int y = top; y < top + height; y++)
{
Span pixelRow = pixels.DangerousGetRowSpan(y).Slice(left, width);
@@ -32,6 +48,12 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
pixelRow,
pixelRow.Length);
+ if (hasAssociatedAlpha)
+ {
+ PixelOperations.Instance.ToVector4(this.configuration, pixelRow, vectorsSpan);
+ TiffUtils.UnPremultiplyRow(vectorsSpan, pixelRow, color);
+ }
+
offset += byteCount;
}
}
diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/RgbaPlanarTiffColor{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/RgbaPlanarTiffColor{TPixel}.cs
index f2ccf2ec8..ecf957eab 100644
--- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/RgbaPlanarTiffColor{TPixel}.cs
+++ b/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;
}
///
@@ -57,6 +61,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
public override void Decode(IMemoryOwner[] data, Buffer2D 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;
}
diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/RgbaTiffColor{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/RgbaTiffColor{TPixel}.cs
index 8bec7da89..c00557b10 100644
--- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/RgbaTiffColor{TPixel}.cs
+++ b/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;
}
///
@@ -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 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();
diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/TiffColorDecoderFactory{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/TiffColorDecoderFactory{TPixel}.cs
index 1c608e303..c95d03946 100644
--- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/TiffColorDecoderFactory{TPixel}.cs
+++ b/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(bitsPerSample);
+ return new RgbaTiffColor(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(bitsPerSample);
+ return new RgbaTiffColor(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(bitsPerSample);
+ return new RgbaTiffColor(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(bitsPerSample);
+ return new RgbaTiffColor(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(bitsPerSample);
+ return new RgbaTiffColor(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(configuration);
+ return new Rgba8888TiffColor(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(bitsPerSample);
+ return new RgbaTiffColor(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(bitsPerSample);
+ return new RgbaTiffColor(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(bitsPerSample);
+ return new RgbaTiffColor(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(configuration, isBigEndian: byteOrder == ByteOrder.BigEndian);
+ return new Rgba16161616TiffColor(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(isBigEndian: byteOrder == ByteOrder.BigEndian);
+ return new Rgba24242424TiffColor(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(isBigEndian: byteOrder == ByteOrder.BigEndian);
+ return new Rgba32323232TiffColor(extraSampleType, isBigEndian: byteOrder == ByteOrder.BigEndian);
case TiffColorType.RgbFloat323232:
DebugGuard.IsTrue(
@@ -394,6 +395,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
public static TiffBasePlanarColorDecoder 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(bitsPerSample);
+ return new RgbaPlanarTiffColor(extraSampleType, bitsPerSample);
case TiffColorType.YCbCrPlanar:
return new YCbCrPlanarTiffColor(referenceBlackAndWhite, ycbcrCoefficients, ycbcrSubSampling);
@@ -419,7 +421,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
case TiffColorType.Rgba16161616Planar:
DebugGuard.IsTrue(colorMap == null, "colorMap");
- return new Rgba16PlanarTiffColor(byteOrder == ByteOrder.BigEndian);
+ return new Rgba16PlanarTiffColor(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(byteOrder == ByteOrder.BigEndian);
+ return new Rgba24PlanarTiffColor(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(byteOrder == ByteOrder.BigEndian);
+ return new Rgba32PlanarTiffColor(extraSampleType, byteOrder == ByteOrder.BigEndian);
default:
throw TiffThrowHelper.InvalidColorType(colorType.ToString());
diff --git a/src/ImageSharp/Formats/Tiff/README.md b/src/ImageSharp/Formats/Tiff/README.md
index aa960b373..8cb327a7b 100644
--- a/src/ImageSharp/Formats/Tiff/README.md
+++ b/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
diff --git a/src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs b/src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs
index e5b810738..1198c519a 100644
--- a/src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs
+++ b/src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs
@@ -118,9 +118,9 @@ namespace SixLabors.ImageSharp.Formats.Tiff
public TiffFillOrder FillOrder { get; set; }
///
- /// Gets or sets the extra samples, which can contain the alpha channel data.
+ /// Gets or sets the extra samples type.
///
- public TiffExtraSampleType? ExtraSamples { get; set; }
+ public TiffExtraSampleType? ExtraSamplesType { get; set; }
///
/// Gets or sets the JPEG tables when jpeg compression is used.
@@ -375,6 +375,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff
TiffBasePlanarColorDecoder colorDecoder = TiffColorDecoderFactory.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,
diff --git a/src/ImageSharp/Formats/Tiff/TiffDecoderOptionsParser.cs b/src/ImageSharp/Formats/Tiff/TiffDecoderOptionsParser.cs
index 23bc5f15f..6baf71466 100644
--- a/src/ImageSharp/Formats/Tiff/TiffDecoderOptionsParser.cs
+++ b/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.");
}
}
diff --git a/src/ImageSharp/Formats/Tiff/Utils/TiffUtils.cs b/src/ImageSharp/Formats/Tiff/Utils/TiffUtils.cs
index b7d4b6e7c..13b63dedc 100644
--- a/src/ImageSharp/Formats/Tiff/Utils/TiffUtils.cs
+++ b/src/ImageSharp/Formats/Tiff/Utils/TiffUtils.cs
@@ -46,7 +46,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Utils
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static TPixel ColorFromRgba64(Rgba64 rgba, ulong r, ulong g, ulong b, TPixel color)
+ public static TPixel ColorFromRgb64(Rgba64 rgba, ulong r, ulong g, ulong b, TPixel color)
where TPixel : unmanaged, IPixel
{
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(Rgba64 rgba, ulong r, ulong g, ulong b, ulong a, TPixel color)
+ where TPixel : unmanaged, IPixel
+ {
+ rgba.PackedValue = r | (g << 16) | (b << 32) | (a << 48);
+ var vec = rgba.ToVector4();
+ return UnPremultiply(vec, color);
+ }
+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static TPixel ColorScaleTo24Bit(ulong r, ulong g, ulong b, TPixel color)
where TPixel : unmanaged, IPixel
@@ -81,6 +90,14 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Utils
return color;
}
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static TPixel ColorScaleTo24BitPremultiplied(ulong r, ulong g, ulong b, ulong a, TPixel color)
+ where TPixel : unmanaged, IPixel
+ {
+ var colorVector = new Vector4(r * Scale24Bit, g * Scale24Bit, b * Scale24Bit, a * Scale24Bit);
+ return UnPremultiply(colorVector, color);
+ }
+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static TPixel ColorScaleTo32Bit(ulong r, ulong g, ulong b, TPixel color)
where TPixel : unmanaged, IPixel
@@ -99,6 +116,14 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Utils
return color;
}
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static TPixel ColorScaleTo32BitPremultiplied(ulong r, ulong g, ulong b, ulong a, TPixel color)
+ where TPixel : unmanaged, IPixel
+ {
+ var colorVector = new Vector4(r * Scale32Bit, g * Scale32Bit, b * Scale32Bit, a * Scale32Bit);
+ return UnPremultiply(colorVector, color);
+ }
+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static TPixel ColorFromL16(L16 l16, ushort intensity, TPixel color)
where TPixel : unmanaged, IPixel
@@ -126,6 +151,27 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Utils
return color;
}
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static void UnPremultiplyRow(Span vectors, Span pixelRow, TPixel color)
+ where TPixel : unmanaged, IPixel
+ {
+ for (int x = 0; x < vectors.Length; x++)
+ {
+ Vector4 vec = vectors[x];
+ pixelRow[x] = UnPremultiply(vec, color);
+ }
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static TPixel UnPremultiply(Vector4 vec, TPixel color)
+ where TPixel : unmanaged, IPixel
+ {
+ float invW = 1.0f / vec.W;
+ color.FromVector4(new Vector4(vec.X * invW, vec.Y * invW, vec.Z * invW, vec.W));
+
+ return color;
+ }
+
///
/// Finds the padding needed to round 'valueToRoundUp' to the next integer multiple of subSampling value.
///
diff --git a/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs
index bd300f799..2f06c997a 100644
--- a/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs
+++ b/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs
@@ -187,6 +187,13 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff
public void TiffDecoder_CanDecode_12Bit_WithUnassociatedAlpha(TestImageProvider provider)
where TPixel : unmanaged, IPixel => TestTiffDecoder(provider);
+ [Theory]
+ [WithFile(Rgba3BitAssociatedAlpha, PixelTypes.Rgba32)]
+ public void TiffDecoder_CanDecode_12Bit_WithAssociatedAlpha(TestImageProvider 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 => TestTiffDecoder(provider, useExactComparer: false);
+
[Theory]
[WithFile(Flower14BitGray, PixelTypes.Rgba32)]
public void TiffDecoder_CanDecode_14Bit_Gray(TestImageProvider provider)
@@ -226,6 +233,13 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff
public void TiffDecoder_CanDecode_20Bit_WithUnassociatedAlpha(TestImageProvider provider)
where TPixel : unmanaged, IPixel => TestTiffDecoder(provider);
+ [Theory]
+ [WithFile(Rgba5BitAssociatedAlpha, PixelTypes.Rgba32)]
+ public void TiffDecoder_CanDecode_20Bit_WithAssociatedAlpha(TestImageProvider 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 => TestTiffDecoder(provider, useExactComparer: false);
+
[Theory]
[WithFile(FlowerRgb888Contiguous, PixelTypes.Rgba32)]
public void TiffDecoder_CanDecode_24Bit(TestImageProvider provider)
@@ -236,6 +250,13 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff
public void TiffDecoder_CanDecode_24Bit_WithUnassociatedAlpha(TestImageProvider provider)
where TPixel : unmanaged, IPixel => TestTiffDecoder(provider);
+ [Theory]
+ [WithFile(Rgba6BitAssociatedAlpha, PixelTypes.Rgba32)]
+ public void TiffDecoder_CanDecode_24Bit_WithAssociatedAlpha(TestImageProvider 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 => 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(TestImageProvider 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 => 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(TestImageProvider provider)
where TPixel : unmanaged, IPixel => TestTiffDecoder(provider);
+ [Theory]
+ [WithFile(Rgba10BitAssociatedAlphaBigEndian, PixelTypes.Rgba32)]
+ [WithFile(Rgba10BitAssociatedAlphaLittleEndian, PixelTypes.Rgba32)]
+ public void TiffDecoder_CanDecode_40Bit_WithAssociatedAlpha(TestImageProvider provider)
+ where TPixel : unmanaged, IPixel => 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(TestImageProvider provider)
where TPixel : unmanaged, IPixel => TestTiffDecoder(provider);
+ [Theory]
+ [WithFile(Rgba12BitAssociatedAlphaBigEndian, PixelTypes.Rgba32)]
+ [WithFile(Rgba12BitAssociatedAlphaLittleEndian, PixelTypes.Rgba32)]
+ public void TiffDecoder_CanDecode_48Bit_WithAssociatedAlpha(TestImageProvider provider)
+ where TPixel : unmanaged, IPixel => 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(TestImageProvider provider)
where TPixel : unmanaged, IPixel => TestTiffDecoder(provider);
+ [Theory]
+ [WithFile(Rgba14BitAssociatedAlphaBigEndian, PixelTypes.Rgba32)]
+ [WithFile(Rgba14BitAssociatedAlphaLittleEndian, PixelTypes.Rgba32)]
+ public void TiffDecoder_CanDecode_56Bit_WithAssociatedAlpha(TestImageProvider provider)
+ where TPixel : unmanaged, IPixel => TestTiffDecoder(provider, useExactComparer: false, compareTolerance: 0.0002f);
+
[Theory]
[WithFile(FlowerRgb242424Contiguous, PixelTypes.Rgba32)]
[WithFile(FlowerRgb242424ContiguousLittleEndian, PixelTypes.Rgba32)]
diff --git a/tests/ImageSharp.Tests/TestImages.cs b/tests/ImageSharp.Tests/TestImages.cs
index 5ed0a12f7..0172f7c2c 100644
--- a/tests/ImageSharp.Tests/TestImages.cs
+++ b/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";
diff --git a/tests/Images/Input/Tiff/RgbaAlpha8bit.tiff b/tests/Images/Input/Tiff/RgbaAlpha8bit.tiff
new file mode 100644
index 000000000..d0d9f2d1e
--- /dev/null
+++ b/tests/Images/Input/Tiff/RgbaAlpha8bit.tiff
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:f8bc77670ea12cd163fbf21fa7dd6d6c10e3b8c1afc83f26618f92303d0cbfcf
+size 235478
diff --git a/tests/Images/Input/Tiff/RgbaAssociatedAlpha10bit_lsb.tiff b/tests/Images/Input/Tiff/RgbaAssociatedAlpha10bit_lsb.tiff
new file mode 100644
index 000000000..01ff24afc
--- /dev/null
+++ b/tests/Images/Input/Tiff/RgbaAssociatedAlpha10bit_lsb.tiff
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:1a9878183ebe84506810ea2edc6dc95cd76780f3847ac3a614ce2dcfb355ea9f
+size 294278
diff --git a/tests/Images/Input/Tiff/RgbaAssociatedAlpha10bit_msb.tiff b/tests/Images/Input/Tiff/RgbaAssociatedAlpha10bit_msb.tiff
new file mode 100644
index 000000000..a0eabbea2
--- /dev/null
+++ b/tests/Images/Input/Tiff/RgbaAssociatedAlpha10bit_msb.tiff
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:4b95334e1e4b78f5106cacd66d6dc9ad15d023c5449e9562b7489982c5336715
+size 294278
diff --git a/tests/Images/Input/Tiff/RgbaAssociatedAlpha12bit_lsb.tiff b/tests/Images/Input/Tiff/RgbaAssociatedAlpha12bit_lsb.tiff
new file mode 100644
index 000000000..934895707
--- /dev/null
+++ b/tests/Images/Input/Tiff/RgbaAssociatedAlpha12bit_lsb.tiff
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:4b1aa42b51bd5474cbf333d9a0b89634198250d3eb5de4cf3af2a8d846395bf0
+size 353078
diff --git a/tests/Images/Input/Tiff/RgbaAssociatedAlpha12bit_msb.tiff b/tests/Images/Input/Tiff/RgbaAssociatedAlpha12bit_msb.tiff
new file mode 100644
index 000000000..50e9d9c83
--- /dev/null
+++ b/tests/Images/Input/Tiff/RgbaAssociatedAlpha12bit_msb.tiff
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:9a146f0bfcac158dfda1ba307737b39d472a95926ff172bc8c798557f2dd1e1b
+size 353078
diff --git a/tests/Images/Input/Tiff/RgbaAssociatedAlpha14bit_lsb.tiff b/tests/Images/Input/Tiff/RgbaAssociatedAlpha14bit_lsb.tiff
new file mode 100644
index 000000000..b58f097c1
--- /dev/null
+++ b/tests/Images/Input/Tiff/RgbaAssociatedAlpha14bit_lsb.tiff
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:3190269edb721175e8f3788528bd84aee3a12b2c7fb970c02c98822452fc81b0
+size 411878
diff --git a/tests/Images/Input/Tiff/RgbaAssociatedAlpha14bit_msb.tiff b/tests/Images/Input/Tiff/RgbaAssociatedAlpha14bit_msb.tiff
new file mode 100644
index 000000000..cfe66071d
--- /dev/null
+++ b/tests/Images/Input/Tiff/RgbaAssociatedAlpha14bit_msb.tiff
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:4d65b9b1172d125fece197c2bf332bff9074db2b443e74d1973a14dbe45865e8
+size 411878
diff --git a/tests/Images/Input/Tiff/RgbaAssociatedAlpha16bit_lsb.tiff b/tests/Images/Input/Tiff/RgbaAssociatedAlpha16bit_lsb.tiff
new file mode 100644
index 000000000..a6199845a
--- /dev/null
+++ b/tests/Images/Input/Tiff/RgbaAssociatedAlpha16bit_lsb.tiff
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:5ee223455c3e2f748d4dc9a1446047adb3c547878b815504c785497d8c059d34
+size 470678
diff --git a/tests/Images/Input/Tiff/RgbaAssociatedAlpha16bit_msb.tiff b/tests/Images/Input/Tiff/RgbaAssociatedAlpha16bit_msb.tiff
new file mode 100644
index 000000000..3bc030c50
--- /dev/null
+++ b/tests/Images/Input/Tiff/RgbaAssociatedAlpha16bit_msb.tiff
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:9ea0206508fe23dfb8653ac1706894e54a4ad980b3bf75b68e5deb9f2838a1de
+size 470678
diff --git a/tests/Images/Input/Tiff/RgbaAssociatedAlpha3bit.tiff b/tests/Images/Input/Tiff/RgbaAssociatedAlpha3bit.tiff
new file mode 100644
index 000000000..7a87e5ef8
--- /dev/null
+++ b/tests/Images/Input/Tiff/RgbaAssociatedAlpha3bit.tiff
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:03d1050a606b6fa9e909f54991ed12b1aa96b739e5f69f4b1bae7c903b1236ef
+size 88478
diff --git a/tests/Images/Input/Tiff/RgbaAssociatedAlpha4bit.tiff b/tests/Images/Input/Tiff/RgbaAssociatedAlpha4bit.tiff
new file mode 100644
index 000000000..2679e5829
--- /dev/null
+++ b/tests/Images/Input/Tiff/RgbaAssociatedAlpha4bit.tiff
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:41481c59d9b63ca946d9d2cf2ccc599d1e48ef6fdfa00926c1e6d5cdfd35eb47
+size 117878
diff --git a/tests/Images/Input/Tiff/RgbaAssociatedAlpha5bit.tiff b/tests/Images/Input/Tiff/RgbaAssociatedAlpha5bit.tiff
new file mode 100644
index 000000000..1cdb3d475
--- /dev/null
+++ b/tests/Images/Input/Tiff/RgbaAssociatedAlpha5bit.tiff
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:4bc3b2b8031593ff9a79d7caccd2ed614cf8d788dedbefbd27d0a4f88399be4e
+size 147278
diff --git a/tests/Images/Input/Tiff/RgbaAssociatedAlpha6bit.tiff b/tests/Images/Input/Tiff/RgbaAssociatedAlpha6bit.tiff
new file mode 100644
index 000000000..3184bd90b
--- /dev/null
+++ b/tests/Images/Input/Tiff/RgbaAssociatedAlpha6bit.tiff
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:a9c1c64ce9a002337c3f6d332b4a5bb3016718b672f9c95d8792b013545553c2
+size 176678