mirror of https://github.com/SixLabors/ImageSharp
17 changed files with 437 additions and 18 deletions
@ -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); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -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); |
|||
byte[] buffer = new 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.AsSpan(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.ColorScaleTo32Bit(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.ColorScaleTo32Bit(r, g, b, a, color); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -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); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -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(); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,3 @@ |
|||
version https://git-lfs.github.com/spec/v1 |
|||
oid sha256:6bc4325ce7be8a16d23c559300c79c3228c2f5a4c266844ba49763a32d29f10e |
|||
size 470710 |
|||
@ -0,0 +1,3 @@ |
|||
version https://git-lfs.github.com/spec/v1 |
|||
oid sha256:08f8c284f7a9a6f362c09a418d85a94a1fe09bfc3f4cfe6859a82d6814718091 |
|||
size 470710 |
|||
@ -0,0 +1,3 @@ |
|||
version https://git-lfs.github.com/spec/v1 |
|||
oid sha256:8ba4da7d63931f4462113e00bdee9e66e333ca42a47a33f62057c248bf4696ef |
|||
size 705910 |
|||
@ -0,0 +1,3 @@ |
|||
version https://git-lfs.github.com/spec/v1 |
|||
oid sha256:862ec9153cc755aa3ece8965a9d001a630ff756dfb018a9474661730482964cb |
|||
size 705910 |
|||
@ -0,0 +1,3 @@ |
|||
version https://git-lfs.github.com/spec/v1 |
|||
oid sha256:dc4f67dacd3262418769831aeabf99c9a88a9674fabf9a08c8b3d3e47ac6d07a |
|||
size 941110 |
|||
@ -0,0 +1,3 @@ |
|||
version https://git-lfs.github.com/spec/v1 |
|||
oid sha256:a98a0176f5db7af5b22c74f4a518c2df1055b5ca7e732f63426b3df8090fc313 |
|||
size 941110 |
|||
@ -0,0 +1,3 @@ |
|||
version https://git-lfs.github.com/spec/v1 |
|||
oid sha256:2185ef9a84701bcff104d4f2fe40171ed853e5d02a2049b209ee2a4c65105ea9 |
|||
size 235502 |
|||
Loading…
Reference in new issue