Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for decoding Tiff images with associated alpha data #2062

Merged
merged 8 commits into from
Mar 15, 2022
10 changes: 5 additions & 5 deletions src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs
Original file line number Diff line number Diff line change
Expand Up @@ -323,12 +323,12 @@ private void ReadRle<TPixel>(BmpCompression compression, Buffer2D<TPixel> pixels
color.FromBgr24(Unsafe.As<byte, Bgr24>(ref colors[colorIdx * 4]));
break;
case RleSkippedPixelHandling.Transparent:
color.FromVector4(Vector4.Zero);
color.FromScaledVector4(Vector4.Zero);
break;

// Default handling for skipped pixels is black (which is what System.Drawing is also doing).
default:
color.FromVector4(new Vector4(0.0f, 0.0f, 0.0f, 1.0f));
color.FromScaledVector4(new Vector4(0.0f, 0.0f, 0.0f, 1.0f));
break;
}
}
Expand Down Expand Up @@ -395,12 +395,12 @@ private void ReadRle24<TPixel>(Buffer2D<TPixel> pixels, int width, int height, b
color.FromBgr24(Unsafe.As<byte, Bgr24>(ref bufferSpan[idx]));
break;
case RleSkippedPixelHandling.Transparent:
color.FromVector4(Vector4.Zero);
color.FromScaledVector4(Vector4.Zero);
break;

// Default handling for skipped pixels is black (which is what System.Drawing is also doing).
default:
color.FromVector4(new Vector4(0.0f, 0.0f, 0.0f, 1.0f));
color.FromScaledVector4(new Vector4(0.0f, 0.0f, 0.0f, 1.0f));
break;
}
}
Expand Down Expand Up @@ -1127,7 +1127,7 @@ private void ReadRgb32BitFields<TPixel>(Buffer2D<TPixel> pixels, int width, int
g * invMaxValueGreen,
b * invMaxValueBlue,
alpha);
color.FromVector4(vector4);
color.FromScaledVector4(vector4);
}
else
{
Expand Down
42 changes: 29 additions & 13 deletions src/ImageSharp/Formats/Tiff/Constants/TiffCompression.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,6 @@ public enum TiffCompression : ushort
/// </summary>
Ccitt1D = 2,

/// <summary>
/// PackBits compression
/// </summary>
PackBits = 32773,

/// <summary>
/// T4-encoding: CCITT T.4 bi-level encoding (see Section 11 of the TIFF 6.0 specification).
/// </summary>
Expand Down Expand Up @@ -65,27 +60,48 @@ public enum TiffCompression : ushort
Deflate = 8,

/// <summary>
/// Deflate compression - old.
/// ITU-T Rec. T.82 coding, applying ITU-T Rec. T.85 (JBIG) (see RFC2301).
///
/// Note: The TIFF encoder does not support this compression and will default to use no compression instead,
/// Note: The TIFF encoder does not yet support this compression and will default to use no compression instead,
/// if this is chosen.
/// </summary>
OldDeflate = 32946,
ItuTRecT82 = 9,

/// <summary>
/// ITU-T Rec. T.82 coding, applying ITU-T Rec. T.85 (JBIG) (see RFC2301).
/// ITU-T Rec. T.43 representation, using ITU-T Rec. T.82 (JBIG) (see RFC2301).
///
/// Note: The TIFF encoder does not yet support this compression and will default to use no compression instead,
/// if this is chosen.
/// </summary>
ItuTRecT82 = 9,
ItuTRecT43 = 10,

/// <summary>
/// ITU-T Rec. T.43 representation, using ITU-T Rec. T.82 (JBIG) (see RFC2301).
/// NeXT 2-bit Grey Scale compression algorithm.
///
/// Note: The TIFF encoder does not yet support this compression and will default to use no compression instead,
/// Note: The TIFF encoder does not support this compression and will default to use no compression instead,
/// if this is chosen.
/// </summary>
NeXT = 32766,

/// <summary>
/// PackBits compression.
/// </summary>
PackBits = 32773,

/// <summary>
/// ThunderScan 4-bit compression.
///
/// Note: The TIFF encoder does not support this compression and will default to use no compression instead,
/// if this is chosen.
/// </summary>
ItuTRecT43 = 10
ThunderScan = 32809,

/// <summary>
/// Deflate compression - old.
///
/// Note: The TIFF encoder does not support this compression and will default to use no compression instead,
/// if this is chosen.
/// </summary>
OldDeflate = 32946,
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ public override void Decode(ReadOnlySpan<byte> data, Buffer2D<TPixel> pixels, in
// we define our own defaults as a workaround. See: https://github.com/dotnet/runtime/issues/55623
L16 l16 = TiffUtils.L16Default;
var color = default(TPixel);
color.FromVector4(TiffUtils.Vector4Default);
color.FromScaledVector4(TiffUtils.Vector4Default);

int offset = 0;
for (int y = top; y < top + height; y++)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ public override void Decode(ReadOnlySpan<byte> data, Buffer2D<TPixel> pixels, in
// 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);
color.FromScaledVector4(TiffUtils.Vector4Default);
byte[] buffer = new byte[4];
int bufferStartIdx = this.isBigEndian ? 1 : 0;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ public override void Decode(ReadOnlySpan<byte> data, Buffer2D<TPixel> pixels, in
// 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);
color.FromScaledVector4(TiffUtils.Vector4Default);
byte[] buffer = new byte[4];

int offset = 0;
Expand All @@ -46,7 +46,7 @@ public override void Decode(ReadOnlySpan<byte> data, Buffer2D<TPixel> pixels, in
offset += 4;

var colorVector = new Vector4(intensity, intensity, intensity, 1.0f);
color.FromVector4(colorVector);
color.FromScaledVector4(colorVector);
pixelRow[x] = color;
}
}
Expand All @@ -59,7 +59,7 @@ public override void Decode(ReadOnlySpan<byte> data, Buffer2D<TPixel> pixels, in
offset += 4;

var colorVector = new Vector4(intensity, intensity, intensity, 1.0f);
color.FromVector4(colorVector);
color.FromScaledVector4(colorVector);
pixelRow[x] = color;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ public override void Decode(ReadOnlySpan<byte> data, Buffer2D<TPixel> pixels, in
// 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);
color.FromScaledVector4(TiffUtils.Vector4Default);

int offset = 0;
for (int y = top; y < top + height; y++)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ public override void Decode(ReadOnlySpan<byte> data, Buffer2D<TPixel> pixels, in
int value = bitReader.ReadBits(this.bitsPerSample0);
float intensity = value / this.factor;

color.FromVector4(new Vector4(intensity, intensity, intensity, 1.0f));
color.FromScaledVector4(new Vector4(intensity, intensity, intensity, 1.0f));
pixelRow[x] = color;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ private static TPixel[] GeneratePalette(ushort[] colorMap, int colorCount)
float r = colorMap[rOffset + i] / 65535F;
float g = colorMap[gOffset + i] / 65535F;
float b = colorMap[bOffset + i] / 65535F;
palette[i].FromVector4(new Vector4(r, g, b, 1.0f));
palette[i].FromScaledVector4(new Vector4(r, g, b, 1.0f));
}

return palette;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ public override void Decode(ReadOnlySpan<byte> data, Buffer2D<TPixel> pixels, in
// 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);
color.FromScaledVector4(TiffUtils.Vector4Default);

int offset = 0;

Expand All @@ -55,7 +55,7 @@ public override void Decode(ReadOnlySpan<byte> data, Buffer2D<TPixel> pixels, in
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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ public override void Decode(IMemoryOwner<byte>[] data, Buffer2D<TPixel> pixels,
// 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);
color.FromScaledVector4(TiffUtils.Vector4Default);

Span<byte> redData = data[0].GetSpan();
Span<byte> greenData = data[1].GetSpan();
Expand All @@ -50,7 +50,7 @@ public override void Decode(IMemoryOwner<byte>[] data, Buffer2D<TPixel> pixels,

offset += 2;

pixelRow[x] = TiffUtils.ColorFromRgba64(rgba, r, g, b, color);
pixelRow[x] = TiffUtils.ColorFromRgb64(rgba, r, g, b, color);
}
}
else
Expand All @@ -63,7 +63,7 @@ public override void Decode(IMemoryOwner<byte>[] data, Buffer2D<TPixel> pixels,

offset += 2;

pixelRow[x] = TiffUtils.ColorFromRgba64(rgba, r, g, b, color);
pixelRow[x] = TiffUtils.ColorFromRgb64(rgba, r, g, b, color);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ public override void Decode(ReadOnlySpan<byte> data, Buffer2D<TPixel> pixels, in
// 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);
color.FromScaledVector4(TiffUtils.Vector4Default);
int offset = 0;
Span<byte> buffer = stackalloc byte[4];
int bufferStartIdx = this.isBigEndian ? 1 : 0;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ public override void Decode(IMemoryOwner<byte>[] data, Buffer2D<TPixel> pixels,
// 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);
color.FromScaledVector4(TiffUtils.Vector4Default);
Span<byte> buffer = stackalloc byte[4];
int bufferStartIdx = this.isBigEndian ? 1 : 0;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ public override void Decode(ReadOnlySpan<byte> data, Buffer2D<TPixel> pixels, in
// 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);
color.FromScaledVector4(TiffUtils.Vector4Default);
int offset = 0;

for (int y = top; y < top + height; y++)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ public override void Decode(IMemoryOwner<byte>[] data, Buffer2D<TPixel> pixels,
// 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);
color.FromScaledVector4(TiffUtils.Vector4Default);

Span<byte> redData = data[0].GetSpan();
Span<byte> greenData = data[1].GetSpan();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ public override void Decode(ReadOnlySpan<byte> data, Buffer2D<TPixel> pixels, in
// 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);
color.FromScaledVector4(TiffUtils.Vector4Default);
int offset = 0;
byte[] buffer = new byte[4];

Expand Down Expand Up @@ -57,7 +57,7 @@ public override void Decode(ReadOnlySpan<byte> data, Buffer2D<TPixel> pixels, in
offset += 4;

var colorVector = new Vector4(r, g, b, 1.0f);
color.FromVector4(colorVector);
color.FromScaledVector4(colorVector);
pixelRow[x] = color;
}
}
Expand All @@ -78,7 +78,7 @@ public override void Decode(ReadOnlySpan<byte> data, Buffer2D<TPixel> pixels, in
offset += 4;

var colorVector = new Vector4(r, g, b, 1.0f);
color.FromVector4(colorVector);
color.FromScaledVector4(colorVector);
pixelRow[x] = color;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ public override void Decode(IMemoryOwner<byte>[] data, Buffer2D<TPixel> pixels,
float g = gBitReader.ReadBits(this.bitsPerSampleG) / this.gFactor;
float b = bBitReader.ReadBits(this.bitsPerSampleB) / this.bFactor;

color.FromVector4(new Vector4(r, g, b, 1.0f));
color.FromScaledVector4(new Vector4(r, g, b, 1.0f));
pixelRow[x] = color;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ public override void Decode(ReadOnlySpan<byte> data, Buffer2D<TPixel> pixels, in
float g = bitReader.ReadBits(this.bitsPerSampleG) / this.gFactor;
float b = bitReader.ReadBits(this.bitsPerSampleB) / this.bFactor;

color.FromVector4(new Vector4(r, g, b, 1.0f));
color.FromScaledVector4(new Vector4(r, g, b, 1.0f));
pixelRow[x] = color;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
// 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;
Expand All @@ -18,15 +20,23 @@ internal class Rgba16161616TiffColor<TPixel> : TiffBaseColorDecoder<TPixel>

private readonly Configuration configuration;

private readonly MemoryAllocator memoryAllocator;

private readonly TiffExtraSampleType? extraSamplesType;

/// <summary>
/// Initializes a new instance of the <see cref="Rgba16161616TiffColor{TPixel}" /> class.
/// </summary>
/// <param name="configuration">The configuration.</param>
/// <param name="memoryAllocator">The memory allocator.</param>
/// <param name="isBigEndian">if set to <c>true</c> decodes the pixel data as big endian, otherwise as little endian.</param>
public Rgba16161616TiffColor(Configuration configuration, bool isBigEndian)
/// <param name="extraSamplesType">The type of the extra samples.</param>
public Rgba16161616TiffColor(Configuration configuration, MemoryAllocator memoryAllocator, TiffExtraSampleType? extraSamplesType, bool isBigEndian)
{
this.configuration = configuration;
this.isBigEndian = isBigEndian;
this.memoryAllocator = memoryAllocator;
this.extraSamplesType = extraSamplesType;
}

/// <inheritdoc/>
Expand All @@ -36,10 +46,13 @@ public override void Decode(ReadOnlySpan<byte> data, Buffer2D<TPixel> pixels, in
// 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);
color.FromScaledVector4(TiffUtils.Vector4Default);

bool hasAssociatedAlpha = this.extraSamplesType.HasValue && this.extraSamplesType == TiffExtraSampleType.AssociatedAlphaData;
int offset = 0;

using IMemoryOwner<Vector4> vectors = hasAssociatedAlpha ? this.memoryAllocator.Allocate<Vector4>(width) : null;
Span<Vector4> vectorsSpan = hasAssociatedAlpha ? vectors.GetSpan() : Span<Vector4>.Empty;
for (int y = top; y < top + height; y++)
{
Span<TPixel> pixelRow = pixels.DangerousGetRowSpan(y).Slice(left, width);
Expand All @@ -57,7 +70,9 @@ public override void Decode(ReadOnlySpan<byte> data, Buffer2D<TPixel> pixels, in
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
Expand All @@ -69,6 +84,12 @@ public override void Decode(ReadOnlySpan<byte> data, Buffer2D<TPixel> pixels, in
pixelRow,
pixelRow.Length);

if (hasAssociatedAlpha)
{
PixelOperations<TPixel>.Instance.ToVector4(this.configuration, pixelRow, vectorsSpan);
JimBobSquarePants marked this conversation as resolved.
Show resolved Hide resolved
PixelOperations<TPixel>.Instance.FromVector4Destructive(this.configuration, vectorsSpan, pixelRow, PixelConversionModifiers.Premultiply | PixelConversionModifiers.Scale);
}

offset += byteCount;
}
}
Expand Down
Loading