mirror of https://github.com/SixLabors/ImageSharp
Browse Source
# Conflicts: # src/ImageSharp/Formats/Bmp/BmpFormat.cs # src/ImageSharp/Formats/ImageDecoderUtilities.cs # src/ImageSharp/Formats/ImageExtensions.Save.cs # src/ImageSharp/Formats/OpenExr/ExrDecoderCore.cspull/3096/head
49 changed files with 2316 additions and 2202 deletions
@ -1,24 +0,0 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
using System; |
|||
using SixLabors.ImageSharp.IO; |
|||
using SixLabors.ImageSharp.Memory; |
|||
|
|||
namespace SixLabors.ImageSharp.Formats.OpenExr.Compression.Compressors |
|||
{ |
|||
internal class NoneExrCompression : ExrBaseDecompressor |
|||
{ |
|||
public NoneExrCompression(MemoryAllocator allocator, uint uncompressedBytes) |
|||
: base(allocator, uncompressedBytes) |
|||
{ |
|||
} |
|||
|
|||
public override void Decompress(BufferedReadStream stream, uint compressedBytes, Span<byte> buffer) |
|||
=> stream.Read(buffer, 0, Math.Min(buffer.Length, (int)this.UncompressedBytes)); |
|||
|
|||
protected override void Dispose(bool disposing) |
|||
{ |
|||
} |
|||
} |
|||
} |
|||
@ -1,94 +0,0 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
using System; |
|||
using System.Buffers; |
|||
using SixLabors.ImageSharp.IO; |
|||
using SixLabors.ImageSharp.Memory; |
|||
|
|||
namespace SixLabors.ImageSharp.Formats.OpenExr.Compression.Compressors |
|||
{ |
|||
internal class RunLengthCompression : ExrBaseDecompressor |
|||
{ |
|||
private readonly IMemoryOwner<byte> tmpBuffer; |
|||
|
|||
public RunLengthCompression(MemoryAllocator allocator, uint uncompressedBytes) |
|||
: base(allocator, uncompressedBytes) => this.tmpBuffer = allocator.Allocate<byte>((int)uncompressedBytes); |
|||
|
|||
public override void Decompress(BufferedReadStream stream, uint compressedBytes, Span<byte> buffer) |
|||
{ |
|||
Span<byte> uncompressed = this.tmpBuffer.GetSpan(); |
|||
int maxLength = (int)this.UncompressedBytes; |
|||
int offset = 0; |
|||
while (compressedBytes > 0) |
|||
{ |
|||
byte nextByte = ReadNextByte(stream); |
|||
|
|||
sbyte input = (sbyte)nextByte; |
|||
if (input < 0) |
|||
{ |
|||
int count = -input; |
|||
compressedBytes -= (uint)(count + 1); |
|||
|
|||
if ((maxLength -= count) < 0) |
|||
{ |
|||
return; |
|||
} |
|||
|
|||
// Check the input buffer is big enough to contain 'count' bytes of remaining data.
|
|||
if (compressedBytes < 0) |
|||
{ |
|||
return; |
|||
} |
|||
|
|||
for (int i = 0; i < count; i++) |
|||
{ |
|||
uncompressed[offset + i] = ReadNextByte(stream); |
|||
} |
|||
|
|||
offset += count; |
|||
} |
|||
else |
|||
{ |
|||
int count = input; |
|||
byte value = ReadNextByte(stream); |
|||
compressedBytes -= 2; |
|||
|
|||
if ((maxLength -= count + 1) < 0) |
|||
{ |
|||
return; |
|||
} |
|||
|
|||
// Check the input buffer is big enough to contain byte to be duplicated.
|
|||
if (compressedBytes < 0) |
|||
{ |
|||
return; |
|||
} |
|||
|
|||
for (int i = 0; i < count + 1; i++) |
|||
{ |
|||
uncompressed[offset + i] = value; |
|||
} |
|||
|
|||
offset += count + 1; |
|||
} |
|||
} |
|||
|
|||
Reconstruct(uncompressed, this.UncompressedBytes); |
|||
Interleave(uncompressed, this.UncompressedBytes, buffer); |
|||
} |
|||
|
|||
private static byte ReadNextByte(BufferedReadStream stream) |
|||
{ |
|||
int nextByte = stream.ReadByte(); |
|||
if (nextByte == -1) |
|||
{ |
|||
ExrThrowHelper.ThrowInvalidImageContentException("Not enough data to decompress RLE image!"); |
|||
} |
|||
|
|||
return (byte)nextByte; |
|||
} |
|||
|
|||
protected override void Dispose(bool disposing) => this.tmpBuffer.Dispose(); |
|||
} |
|||
} |
|||
@ -1,58 +0,0 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
using System; |
|||
using System.Buffers; |
|||
using System.IO.Compression; |
|||
using SixLabors.ImageSharp.Compression.Zlib; |
|||
using SixLabors.ImageSharp.IO; |
|||
using SixLabors.ImageSharp.Memory; |
|||
|
|||
namespace SixLabors.ImageSharp.Formats.OpenExr.Compression.Compressors |
|||
{ |
|||
internal class ZipExrCompression : ExrBaseDecompressor |
|||
{ |
|||
private readonly IMemoryOwner<byte> tmpBuffer; |
|||
|
|||
public ZipExrCompression(MemoryAllocator allocator, uint uncompressedBytes) |
|||
: base(allocator, uncompressedBytes) => this.tmpBuffer = allocator.Allocate<byte>((int)uncompressedBytes); |
|||
|
|||
public override void Decompress(BufferedReadStream stream, uint compressedBytes, Span<byte> buffer) |
|||
{ |
|||
Span<byte> uncompressed = this.tmpBuffer.GetSpan(); |
|||
|
|||
long pos = stream.Position; |
|||
using var deframeStream = new ZlibInflateStream( |
|||
stream, |
|||
() => |
|||
{ |
|||
int left = (int)(compressedBytes - (stream.Position - pos)); |
|||
return left > 0 ? left : 0; |
|||
}); |
|||
deframeStream.AllocateNewBytes((int)this.UncompressedBytes, true); |
|||
DeflateStream dataStream = deframeStream.CompressedStream; |
|||
|
|||
int totalRead = 0; |
|||
while (totalRead < buffer.Length) |
|||
{ |
|||
int bytesRead = dataStream.Read(uncompressed, totalRead, buffer.Length - totalRead); |
|||
if (bytesRead <= 0) |
|||
{ |
|||
break; |
|||
} |
|||
|
|||
totalRead += bytesRead; |
|||
} |
|||
|
|||
if (totalRead == 0) |
|||
{ |
|||
ExrThrowHelper.ThrowInvalidImageContentException("Could not read zip compressed image data!"); |
|||
} |
|||
|
|||
Reconstruct(uncompressed, (uint)totalRead); |
|||
Interleave(uncompressed, (uint)totalRead, buffer); |
|||
} |
|||
|
|||
protected override void Dispose(bool disposing) => this.tmpBuffer.Dispose(); |
|||
} |
|||
} |
|||
@ -0,0 +1,191 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Six Labors Split License.
|
|||
|
|||
using System.Buffers; |
|||
using System.Runtime.InteropServices; |
|||
using SixLabors.ImageSharp.IO; |
|||
using SixLabors.ImageSharp.Memory; |
|||
|
|||
namespace SixLabors.ImageSharp.Formats.OpenExr.Compression.Decompressors; |
|||
|
|||
internal class B44Compression : ExrBaseDecompressor |
|||
{ |
|||
private readonly int width; |
|||
|
|||
private readonly int height; |
|||
|
|||
private readonly uint rowsPerBlock; |
|||
|
|||
private readonly int channelCount; |
|||
|
|||
private byte[] scratch = new byte[14]; |
|||
|
|||
private ushort[] s = new ushort[16]; |
|||
|
|||
private IMemoryOwner<ushort> tmpBuffer; |
|||
|
|||
public B44Compression(MemoryAllocator allocator, uint uncompressedBytes, int width, int height, uint rowsPerBlock, int channelCount) |
|||
: base(allocator, uncompressedBytes) |
|||
{ |
|||
this.width = width; |
|||
this.height = height; |
|||
this.rowsPerBlock = rowsPerBlock; |
|||
this.channelCount = channelCount; |
|||
this.tmpBuffer = allocator.Allocate<ushort>((int)(width * rowsPerBlock * channelCount)); |
|||
} |
|||
|
|||
public override void Decompress(BufferedReadStream stream, uint compressedBytes, Span<byte> buffer) |
|||
{ |
|||
Span<ushort> outputBuffer = MemoryMarshal.Cast<byte, ushort>(buffer); |
|||
Span<ushort> decompressed = this.tmpBuffer.GetSpan(); |
|||
int outputOffset = 0; |
|||
int bytesLeft = (int)compressedBytes; |
|||
for (int i = 0; i < this.channelCount && bytesLeft > 0; i++) |
|||
{ |
|||
for (int y = 0; y < this.rowsPerBlock; y += 4) |
|||
{ |
|||
Span<ushort> row0 = decompressed.Slice(outputOffset, this.width); |
|||
outputOffset += this.width; |
|||
Span<ushort> row1 = decompressed.Slice(outputOffset, this.width); |
|||
outputOffset += this.width; |
|||
Span<ushort> row2 = decompressed.Slice(outputOffset, this.width); |
|||
outputOffset += this.width; |
|||
Span<ushort> row3 = decompressed.Slice(outputOffset, this.width); |
|||
outputOffset += this.width; |
|||
|
|||
int rowOffset = 0; |
|||
for (int x = 0; x < this.width && bytesLeft > 0; x += 4) |
|||
{ |
|||
int bytesRead = stream.Read(this.scratch, 0, 3); |
|||
if (bytesRead == 0) |
|||
{ |
|||
ExrThrowHelper.ThrowInvalidImageContentException("Could not read enough data from the stream"); |
|||
} |
|||
|
|||
if (this.scratch[2] >= 13 << 2) |
|||
{ |
|||
Unpack3(this.scratch, this.s); |
|||
bytesLeft -= 3; |
|||
} |
|||
else |
|||
{ |
|||
bytesRead = stream.Read(this.scratch, 3, 11); |
|||
if (bytesRead == 0) |
|||
{ |
|||
ExrThrowHelper.ThrowInvalidImageContentException("Could not read enough data from the stream"); |
|||
} |
|||
|
|||
Unpack14(this.scratch, this.s); |
|||
bytesLeft -= 14; |
|||
} |
|||
|
|||
int n = x + 3 < this.width ? 4 : this.width - x; |
|||
if (y + 3 < this.rowsPerBlock) |
|||
{ |
|||
this.s.AsSpan(0, n).CopyTo(row0.Slice(rowOffset)); |
|||
this.s.AsSpan(4, n).CopyTo(row1.Slice(rowOffset)); |
|||
this.s.AsSpan(8, n).CopyTo(row2.Slice(rowOffset)); |
|||
this.s.AsSpan(12, n).CopyTo(row3.Slice(rowOffset)); |
|||
} |
|||
else |
|||
{ |
|||
this.s.AsSpan(0, n).CopyTo(row0.Slice(rowOffset)); |
|||
if (y + 1 < this.rowsPerBlock) |
|||
{ |
|||
this.s.AsSpan(4, n).CopyTo(row1.Slice(rowOffset)); |
|||
} |
|||
|
|||
if (y + 2 < this.rowsPerBlock) |
|||
{ |
|||
this.s.AsSpan(8, n).CopyTo(row2.Slice(rowOffset)); |
|||
} |
|||
} |
|||
|
|||
rowOffset += 4; |
|||
} |
|||
|
|||
if (bytesLeft <= 0) |
|||
{ |
|||
break; |
|||
} |
|||
} |
|||
} |
|||
|
|||
// Rearrange the decompressed data such that the data for each scan line form a contiguous block.
|
|||
int offsetDecompressed = 0; |
|||
int offsetOutput = 0; |
|||
int blockSize = (int)(this.width * this.rowsPerBlock); |
|||
for (int y = 0; y < this.rowsPerBlock; y++) |
|||
{ |
|||
for (int i = 0; i < this.channelCount; i++) |
|||
{ |
|||
decompressed.Slice(offsetDecompressed + (i * blockSize), this.width).CopyTo(outputBuffer.Slice(offsetOutput)); |
|||
offsetOutput += this.width; |
|||
} |
|||
|
|||
offsetDecompressed += this.width; |
|||
} |
|||
} |
|||
|
|||
// Unpack a 14-byte block into 4 by 4 16-bit pixels.
|
|||
private static void Unpack14(Span<byte> b, Span<ushort> s) |
|||
{ |
|||
s[0] = (ushort)((b[0] << 8) | b[1]); |
|||
|
|||
ushort shift = (ushort)(b[2] >> 2); |
|||
ushort bias = (ushort)(0x20u << shift); |
|||
|
|||
s[4] = (ushort)(s[0] + ((((b[2] << 4) | (b[3] >> 4)) & 0x3fu) << shift) - bias); |
|||
s[8] = (ushort)(s[4] + ((((b[3] << 2) | (b[4] >> 6)) & 0x3fu) << shift) - bias); |
|||
s[12] = (ushort)(s[8] + ((b[4] & 0x3fu) << shift) - bias); |
|||
|
|||
s[1] = (ushort)(s[0] + ((uint)(b[5] >> 2) << shift) - bias); |
|||
s[5] = (ushort)(s[4] + ((((b[5] << 4) | (b[6] >> 4)) & 0x3fu) << shift) - bias); |
|||
s[9] = (ushort)(s[8] + ((((b[6] << 2) | (b[7] >> 6)) & 0x3fu) << shift) - bias); |
|||
s[13] = (ushort)(s[12] + ((b[7] & 0x3fu) << shift) - bias); |
|||
|
|||
s[2] = (ushort)(s[1] + ((uint)(b[8] >> 2) << shift) - bias); |
|||
s[6] = (ushort)(s[5] + ((((b[8] << 4) | (b[9] >> 4)) & 0x3fu) << shift) - bias); |
|||
s[10] = (ushort)(s[9] + ((((b[9] << 2) | (b[10] >> 6)) & 0x3fu) << shift) - bias); |
|||
s[14] = (ushort)(s[13] + ((b[10] & 0x3fu) << shift) - bias); |
|||
|
|||
s[3] = (ushort)(s[2] + ((uint)(b[11] >> 2) << shift) - bias); |
|||
s[7] = (ushort)(s[6] + ((((b[11] << 4) | (b[12] >> 4)) & 0x3fu) << shift) - bias); |
|||
s[11] = (ushort)(s[10] + ((((b[12] << 2) | (b[13] >> 6)) & 0x3fu) << shift) - bias); |
|||
s[15] = (ushort)(s[14] + ((b[13] & 0x3fu) << shift) - bias); |
|||
|
|||
for (int i = 0; i < 16; ++i) |
|||
{ |
|||
if ((s[i] & 0x8000) != 0) |
|||
{ |
|||
s[i] &= 0x7fff; |
|||
} |
|||
else |
|||
{ |
|||
s[i] = (ushort)~s[i]; |
|||
} |
|||
} |
|||
} |
|||
|
|||
// Unpack a 3-byte block into 4 by 4 identical 16-bit pixels.
|
|||
private static void Unpack3(Span<byte> b, Span<ushort> s) |
|||
{ |
|||
s[0] = (ushort)((b[0] << 8) | b[1]); |
|||
|
|||
if ((s[0] & 0x8000) != 0) |
|||
{ |
|||
s[0] &= 0x7fff; |
|||
} |
|||
else |
|||
{ |
|||
s[0] = (ushort)~s[0]; |
|||
} |
|||
|
|||
for (int i = 1; i < 16; ++i) |
|||
{ |
|||
s[i] = s[0]; |
|||
} |
|||
} |
|||
|
|||
protected override void Dispose(bool disposing) => this.tmpBuffer.Dispose(); |
|||
} |
|||
@ -0,0 +1,22 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Six Labors Split License.
|
|||
|
|||
using SixLabors.ImageSharp.IO; |
|||
using SixLabors.ImageSharp.Memory; |
|||
|
|||
namespace SixLabors.ImageSharp.Formats.OpenExr.Compression.Decompressors; |
|||
|
|||
internal class NoneExrCompression : ExrBaseDecompressor |
|||
{ |
|||
public NoneExrCompression(MemoryAllocator allocator, uint uncompressedBytes) |
|||
: base(allocator, uncompressedBytes) |
|||
{ |
|||
} |
|||
|
|||
public override void Decompress(BufferedReadStream stream, uint compressedBytes, Span<byte> buffer) |
|||
=> stream.Read(buffer, 0, Math.Min(buffer.Length, (int)this.UncompressedBytes)); |
|||
|
|||
protected override void Dispose(bool disposing) |
|||
{ |
|||
} |
|||
} |
|||
@ -0,0 +1,82 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Six Labors Split License.
|
|||
|
|||
using System.Buffers; |
|||
using SixLabors.ImageSharp.IO; |
|||
using SixLabors.ImageSharp.Memory; |
|||
|
|||
namespace SixLabors.ImageSharp.Formats.OpenExr.Compression.Decompressors; |
|||
|
|||
internal class RunLengthCompression : ExrBaseDecompressor |
|||
{ |
|||
private readonly IMemoryOwner<byte> tmpBuffer; |
|||
|
|||
private readonly ushort[] s = new ushort[16]; |
|||
|
|||
public RunLengthCompression(MemoryAllocator allocator, uint uncompressedBytes) |
|||
: base(allocator, uncompressedBytes) => this.tmpBuffer = allocator.Allocate<byte>((int)uncompressedBytes); |
|||
|
|||
public override void Decompress(BufferedReadStream stream, uint compressedBytes, Span<byte> buffer) |
|||
{ |
|||
Span<byte> uncompressed = this.tmpBuffer.GetSpan(); |
|||
int maxLength = (int)this.UncompressedBytes; |
|||
int offset = 0; |
|||
while (compressedBytes > 0) |
|||
{ |
|||
byte nextByte = ReadNextByte(stream); |
|||
|
|||
sbyte input = (sbyte)nextByte; |
|||
if (input < 0) |
|||
{ |
|||
int count = -input; |
|||
compressedBytes -= (uint)(count + 1); |
|||
|
|||
if ((maxLength -= count) < 0) |
|||
{ |
|||
return; |
|||
} |
|||
|
|||
for (int i = 0; i < count; i++) |
|||
{ |
|||
uncompressed[offset + i] = ReadNextByte(stream); |
|||
} |
|||
|
|||
offset += count; |
|||
} |
|||
else |
|||
{ |
|||
int count = input; |
|||
byte value = ReadNextByte(stream); |
|||
compressedBytes -= 2; |
|||
|
|||
if ((maxLength -= count + 1) < 0) |
|||
{ |
|||
return; |
|||
} |
|||
|
|||
for (int i = 0; i < count + 1; i++) |
|||
{ |
|||
uncompressed[offset + i] = value; |
|||
} |
|||
|
|||
offset += count + 1; |
|||
} |
|||
} |
|||
|
|||
Reconstruct(uncompressed, this.UncompressedBytes); |
|||
Interleave(uncompressed, this.UncompressedBytes, buffer); |
|||
} |
|||
|
|||
private static byte ReadNextByte(BufferedReadStream stream) |
|||
{ |
|||
int nextByte = stream.ReadByte(); |
|||
if (nextByte == -1) |
|||
{ |
|||
ExrThrowHelper.ThrowInvalidImageContentException("Not enough data to decompress RLE image!"); |
|||
} |
|||
|
|||
return (byte)nextByte; |
|||
} |
|||
|
|||
protected override void Dispose(bool disposing) => this.tmpBuffer.Dispose(); |
|||
} |
|||
@ -0,0 +1,56 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Six Labors Split License.
|
|||
|
|||
using System.Buffers; |
|||
using System.IO.Compression; |
|||
using SixLabors.ImageSharp.Compression.Zlib; |
|||
using SixLabors.ImageSharp.IO; |
|||
using SixLabors.ImageSharp.Memory; |
|||
|
|||
namespace SixLabors.ImageSharp.Formats.OpenExr.Compression.Decompressors; |
|||
|
|||
internal class ZipExrCompression : ExrBaseDecompressor |
|||
{ |
|||
private readonly IMemoryOwner<byte> tmpBuffer; |
|||
|
|||
public ZipExrCompression(MemoryAllocator allocator, uint uncompressedBytes) |
|||
: base(allocator, uncompressedBytes) => this.tmpBuffer = allocator.Allocate<byte>((int)uncompressedBytes); |
|||
|
|||
public override void Decompress(BufferedReadStream stream, uint compressedBytes, Span<byte> buffer) |
|||
{ |
|||
Span<byte> uncompressed = this.tmpBuffer.GetSpan(); |
|||
|
|||
long pos = stream.Position; |
|||
using ZlibInflateStream inflateStream = new( |
|||
stream, |
|||
() => |
|||
{ |
|||
int left = (int)(compressedBytes - (stream.Position - pos)); |
|||
return left > 0 ? left : 0; |
|||
}); |
|||
inflateStream.AllocateNewBytes((int)this.UncompressedBytes, true); |
|||
DeflateStream dataStream = inflateStream.CompressedStream; |
|||
|
|||
int totalRead = 0; |
|||
while (totalRead < buffer.Length) |
|||
{ |
|||
int bytesRead = dataStream.Read(uncompressed, totalRead, buffer.Length - totalRead); |
|||
if (bytesRead <= 0) |
|||
{ |
|||
break; |
|||
} |
|||
|
|||
totalRead += bytesRead; |
|||
} |
|||
|
|||
if (totalRead == 0) |
|||
{ |
|||
ExrThrowHelper.ThrowInvalidImageContentException("Could not read zip compressed image data!"); |
|||
} |
|||
|
|||
Reconstruct(uncompressed, (uint)totalRead); |
|||
Interleave(uncompressed, (uint)totalRead, buffer); |
|||
} |
|||
|
|||
protected override void Dispose(bool disposing) => this.tmpBuffer.Dispose(); |
|||
} |
|||
@ -1,43 +1,41 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// Licensed under the Six Labors Split License.
|
|||
|
|||
using System; |
|||
using SixLabors.ImageSharp.Memory; |
|||
|
|||
namespace SixLabors.ImageSharp.Formats.OpenExr.Compression |
|||
namespace SixLabors.ImageSharp.Formats.OpenExr.Compression; |
|||
|
|||
internal abstract class ExrBaseCompression : IDisposable |
|||
{ |
|||
internal abstract class ExrBaseCompression : IDisposable |
|||
{ |
|||
private bool isDisposed; |
|||
private bool isDisposed; |
|||
|
|||
protected ExrBaseCompression(MemoryAllocator allocator, uint bytePerRow) |
|||
{ |
|||
this.Allocator = allocator; |
|||
this.UncompressedBytes = bytePerRow; |
|||
} |
|||
protected ExrBaseCompression(MemoryAllocator allocator, uint bytePerRow) |
|||
{ |
|||
this.Allocator = allocator; |
|||
this.UncompressedBytes = bytePerRow; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets the memory allocator.
|
|||
/// </summary>
|
|||
protected MemoryAllocator Allocator { get; } |
|||
/// <summary>
|
|||
/// Gets the memory allocator.
|
|||
/// </summary>
|
|||
protected MemoryAllocator Allocator { get; } |
|||
|
|||
/// <summary>
|
|||
/// Gets the uncompressed bytes.
|
|||
/// </summary>
|
|||
public uint UncompressedBytes { get; } |
|||
/// <summary>
|
|||
/// Gets the uncompressed bytes.
|
|||
/// </summary>
|
|||
public uint UncompressedBytes { get; } |
|||
|
|||
/// <inheritdoc />
|
|||
public void Dispose() |
|||
/// <inheritdoc />
|
|||
public void Dispose() |
|||
{ |
|||
if (this.isDisposed) |
|||
{ |
|||
if (this.isDisposed) |
|||
{ |
|||
return; |
|||
} |
|||
|
|||
this.isDisposed = true; |
|||
this.Dispose(true); |
|||
return; |
|||
} |
|||
|
|||
protected abstract void Dispose(bool disposing); |
|||
this.isDisposed = true; |
|||
this.Dispose(true); |
|||
} |
|||
|
|||
protected abstract void Dispose(bool disposing); |
|||
} |
|||
|
|||
@ -1,42 +1,40 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// Licensed under the Six Labors Split License.
|
|||
|
|||
using System; |
|||
using SixLabors.ImageSharp.IO; |
|||
using SixLabors.ImageSharp.Memory; |
|||
|
|||
namespace SixLabors.ImageSharp.Formats.OpenExr.Compression |
|||
namespace SixLabors.ImageSharp.Formats.OpenExr.Compression; |
|||
|
|||
internal abstract class ExrBaseDecompressor : ExrBaseCompression |
|||
{ |
|||
internal abstract class ExrBaseDecompressor : ExrBaseCompression |
|||
protected ExrBaseDecompressor(MemoryAllocator allocator, uint bytePerRow) |
|||
: base(allocator, bytePerRow) |
|||
{ |
|||
protected ExrBaseDecompressor(MemoryAllocator allocator, uint bytePerRow) |
|||
: base(allocator, bytePerRow) |
|||
{ |
|||
} |
|||
} |
|||
|
|||
public abstract void Decompress(BufferedReadStream stream, uint compressedBytes, Span<byte> buffer); |
|||
public abstract void Decompress(BufferedReadStream stream, uint compressedBytes, Span<byte> buffer); |
|||
|
|||
protected static void Reconstruct(Span<byte> buffer, uint unCompressedBytes) |
|||
protected static void Reconstruct(Span<byte> buffer, uint unCompressedBytes) |
|||
{ |
|||
int offset = 0; |
|||
for (int i = 0; i < unCompressedBytes - 1; i++) |
|||
{ |
|||
int offset = 0; |
|||
for (int i = 0; i < unCompressedBytes - 1; i++) |
|||
{ |
|||
byte d = (byte)(buffer[offset] + (buffer[offset + 1] - 128)); |
|||
buffer[offset + 1] = d; |
|||
offset++; |
|||
} |
|||
byte d = (byte)(buffer[offset] + (buffer[offset + 1] - 128)); |
|||
buffer[offset + 1] = d; |
|||
offset++; |
|||
} |
|||
} |
|||
|
|||
protected static void Interleave(Span<byte> source, uint unCompressedBytes, Span<byte> output) |
|||
protected static void Interleave(Span<byte> source, uint unCompressedBytes, Span<byte> output) |
|||
{ |
|||
int sourceOffset = 0; |
|||
int offset0 = 0; |
|||
int offset1 = (int)((unCompressedBytes + 1) / 2); |
|||
while (sourceOffset < unCompressedBytes) |
|||
{ |
|||
int sourceOffset = 0; |
|||
int offset0 = 0; |
|||
int offset1 = (int)((unCompressedBytes + 1) / 2); |
|||
while (sourceOffset < unCompressedBytes) |
|||
{ |
|||
output[sourceOffset++] = source[offset0++]; |
|||
output[sourceOffset++] = source[offset1++]; |
|||
} |
|||
output[sourceOffset++] = source[offset0++]; |
|||
output[sourceOffset++] = source[offset1++]; |
|||
} |
|||
} |
|||
} |
|||
|
|||
@ -1,61 +1,60 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// Licensed under the Six Labors Split License.
|
|||
|
|||
namespace SixLabors.ImageSharp.Formats.OpenExr.Compression |
|||
namespace SixLabors.ImageSharp.Formats.OpenExr.Compression; |
|||
|
|||
internal enum ExrCompressionType |
|||
{ |
|||
internal enum ExrCompressionType |
|||
{ |
|||
/// <summary>
|
|||
/// Pixel data is not compressed.
|
|||
/// </summary>
|
|||
None = 0, |
|||
|
|||
/// <summary>
|
|||
/// Differences between horizontally adjacent pixels are run-length encoded.
|
|||
/// This method is fast, and works well for images with large flat areas, but for photographic images,
|
|||
/// the compressed file size is usually between 60 and 75 percent of the uncompressed size.
|
|||
/// Compression is lossless.
|
|||
/// </summary>
|
|||
RunLengthEncoded = 1, |
|||
|
|||
/// <summary>
|
|||
/// Uses the open source zlib library for compression. Unlike ZIP compression, this operates one scan line at a time.
|
|||
/// Compression is lossless.
|
|||
/// </summary>
|
|||
Zips = 2, |
|||
|
|||
/// <summary>
|
|||
/// Differences between horizontally adjacent pixels are compressed using the open source zlib library.
|
|||
/// Unlike ZIPS compression, this operates in in blocks of 16 scan lines.
|
|||
/// Compression is lossless.
|
|||
/// </summary>
|
|||
Zip = 3, |
|||
|
|||
/// <summary>
|
|||
/// A wavelet transform is applied to the pixel data, and the result is Huffman-encoded.
|
|||
/// Compression is lossless.
|
|||
/// </summary>
|
|||
Piz = 4, |
|||
|
|||
/// <summary>
|
|||
/// After reducing 32-bit floating-point data to 24 bits by rounding, differences between horizontally adjacent pixels are compressed with zlib,
|
|||
/// similar to ZIP. PXR24 compression preserves image channels of type HALF and UINT exactly, but the relative error of FLOAT data increases to about 3×10-5.
|
|||
/// Compression is lossy.
|
|||
/// </summary>
|
|||
Pxr24 = 5, |
|||
|
|||
/// <summary>
|
|||
/// Channels of type HALF are split into blocks of four by four pixels or 32 bytes. Each block is then packed into 14 bytes,
|
|||
/// reducing the data to 44 percent of their uncompressed size.
|
|||
/// Compression is lossy.
|
|||
/// </summary>
|
|||
B44 = 6, |
|||
|
|||
/// <summary>
|
|||
/// Like B44, except for blocks of four by four pixels where all pixels have the same value, which are packed into 3 instead of 14 bytes.
|
|||
/// For images with large uniform areas, B44A produces smaller files than B44 compression.
|
|||
/// Compression is lossy.
|
|||
/// </summary>
|
|||
B44A = 7 |
|||
} |
|||
/// <summary>
|
|||
/// Pixel data is not compressed.
|
|||
/// </summary>
|
|||
None = 0, |
|||
|
|||
/// <summary>
|
|||
/// Differences between horizontally adjacent pixels are run-length encoded.
|
|||
/// This method is fast, and works well for images with large flat areas, but for photographic images,
|
|||
/// the compressed file size is usually between 60 and 75 percent of the uncompressed size.
|
|||
/// Compression is lossless.
|
|||
/// </summary>
|
|||
RunLengthEncoded = 1, |
|||
|
|||
/// <summary>
|
|||
/// Uses the open source zlib library for compression. Unlike ZIP compression, this operates one scan line at a time.
|
|||
/// Compression is lossless.
|
|||
/// </summary>
|
|||
Zips = 2, |
|||
|
|||
/// <summary>
|
|||
/// Differences between horizontally adjacent pixels are compressed using the open source zlib library.
|
|||
/// Unlike ZIPS compression, this operates in in blocks of 16 scan lines.
|
|||
/// Compression is lossless.
|
|||
/// </summary>
|
|||
Zip = 3, |
|||
|
|||
/// <summary>
|
|||
/// A wavelet transform is applied to the pixel data, and the result is Huffman-encoded.
|
|||
/// Compression is lossless.
|
|||
/// </summary>
|
|||
Piz = 4, |
|||
|
|||
/// <summary>
|
|||
/// After reducing 32-bit floating-point data to 24 bits by rounding, differences between horizontally adjacent pixels are compressed with zlib,
|
|||
/// similar to ZIP. PXR24 compression preserves image channels of type HALF and UINT exactly, but the relative error of FLOAT data increases to about 3×10-5.
|
|||
/// Compression is lossy.
|
|||
/// </summary>
|
|||
Pxr24 = 5, |
|||
|
|||
/// <summary>
|
|||
/// Channels of type HALF are split into blocks of four by four pixels or 32 bytes. Each block is then packed into 14 bytes,
|
|||
/// reducing the data to 44 percent of their uncompressed size.
|
|||
/// Compression is lossy.
|
|||
/// </summary>
|
|||
B44 = 6, |
|||
|
|||
/// <summary>
|
|||
/// Like B44, except for blocks of four by four pixels where all pixels have the same value, which are packed into 3 instead of 14 bytes.
|
|||
/// For images with large uniform areas, B44A produces smaller files than B44 compression.
|
|||
/// Compression is lossy.
|
|||
/// </summary>
|
|||
B44A = 7 |
|||
} |
|||
|
|||
@ -1,28 +1,29 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// Licensed under the Six Labors Split License.
|
|||
|
|||
using SixLabors.ImageSharp.Formats.OpenExr.Compression.Compressors; |
|||
using SixLabors.ImageSharp.Formats.OpenExr.Compression.Decompressors; |
|||
using SixLabors.ImageSharp.Memory; |
|||
|
|||
namespace SixLabors.ImageSharp.Formats.OpenExr.Compression |
|||
namespace SixLabors.ImageSharp.Formats.OpenExr.Compression; |
|||
|
|||
internal static class ExrDecompressorFactory |
|||
{ |
|||
internal static class ExrDecompressorFactory |
|||
public static ExrBaseDecompressor Create(ExrCompressionType method, MemoryAllocator memoryAllocator, uint uncompressedBytes, int width, int height, uint rowsPerBlock, int channelCount) |
|||
{ |
|||
public static ExrBaseDecompressor Create(ExrCompressionType method, MemoryAllocator memoryAllocator, uint uncompressedBytes) |
|||
switch (method) |
|||
{ |
|||
switch (method) |
|||
{ |
|||
case ExrCompressionType.None: |
|||
return new NoneExrCompression(memoryAllocator, uncompressedBytes); |
|||
case ExrCompressionType.Zips: |
|||
return new ZipExrCompression(memoryAllocator, uncompressedBytes); |
|||
case ExrCompressionType.Zip: |
|||
return new ZipExrCompression(memoryAllocator, uncompressedBytes); |
|||
case ExrCompressionType.RunLengthEncoded: |
|||
return new RunLengthCompression(memoryAllocator, uncompressedBytes); |
|||
default: |
|||
throw ExrThrowHelper.NotSupportedDecompressor(nameof(method)); |
|||
} |
|||
case ExrCompressionType.None: |
|||
return new NoneExrCompression(memoryAllocator, uncompressedBytes); |
|||
case ExrCompressionType.Zips: |
|||
return new ZipExrCompression(memoryAllocator, uncompressedBytes); |
|||
case ExrCompressionType.Zip: |
|||
return new ZipExrCompression(memoryAllocator, uncompressedBytes); |
|||
case ExrCompressionType.RunLengthEncoded: |
|||
return new RunLengthCompression(memoryAllocator, uncompressedBytes); |
|||
case ExrCompressionType.B44: |
|||
return new B44Compression(memoryAllocator, uncompressedBytes, width, height, rowsPerBlock, channelCount); |
|||
default: |
|||
throw ExrThrowHelper.NotSupportedDecompressor(nameof(method)); |
|||
} |
|||
} |
|||
} |
|||
|
|||
@ -1,26 +1,25 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// Licensed under the Six Labors Split License.
|
|||
|
|||
using System.Diagnostics; |
|||
|
|||
namespace SixLabors.ImageSharp.Formats.OpenExr |
|||
namespace SixLabors.ImageSharp.Formats.OpenExr; |
|||
|
|||
[DebuggerDisplay("Name: {Name}, Type: {Type}, Length: {Length}")] |
|||
internal class ExrAttribute |
|||
{ |
|||
[DebuggerDisplay("Name: {Name}, Type: {Type}, Length: {Length}")] |
|||
internal class ExrAttribute |
|||
{ |
|||
public static readonly ExrAttribute EmptyAttribute = new(string.Empty, string.Empty, 0); |
|||
public static readonly ExrAttribute EmptyAttribute = new(string.Empty, string.Empty, 0); |
|||
|
|||
public ExrAttribute(string name, string type, int length) |
|||
{ |
|||
this.Name = name; |
|||
this.Type = type; |
|||
this.Length = length; |
|||
} |
|||
public ExrAttribute(string name, string type, int length) |
|||
{ |
|||
this.Name = name; |
|||
this.Type = type; |
|||
this.Length = length; |
|||
} |
|||
|
|||
public string Name { get; } |
|||
public string Name { get; } |
|||
|
|||
public string Type { get; } |
|||
public string Type { get; } |
|||
|
|||
public int Length { get; } |
|||
} |
|||
public int Length { get; } |
|||
} |
|||
|
|||
@ -1,27 +1,26 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// Licensed under the Six Labors Split License.
|
|||
|
|||
using System.Diagnostics; |
|||
|
|||
namespace SixLabors.ImageSharp.Formats.OpenExr |
|||
namespace SixLabors.ImageSharp.Formats.OpenExr; |
|||
|
|||
[DebuggerDisplay("xMin: {XMin}, yMin: {YMin}, xMax: {XMax}, yMax: {YMax}")] |
|||
internal struct ExrBox2i |
|||
{ |
|||
[DebuggerDisplay("xMin: {XMin}, yMin: {YMin}, xMax: {XMax}, yMax: {YMax}")] |
|||
internal struct ExrBox2i |
|||
public ExrBox2i(int xMin, int yMin, int xMax, int yMax) |
|||
{ |
|||
public ExrBox2i(int xMin, int yMin, int xMax, int yMax) |
|||
{ |
|||
this.XMin = xMin; |
|||
this.YMin = yMin; |
|||
this.XMax = xMax; |
|||
this.YMax = yMax; |
|||
} |
|||
this.XMin = xMin; |
|||
this.YMin = yMin; |
|||
this.XMax = xMax; |
|||
this.YMax = yMax; |
|||
} |
|||
|
|||
public int XMin { get; } |
|||
public int XMin { get; } |
|||
|
|||
public int YMin { get; } |
|||
public int YMin { get; } |
|||
|
|||
public int XMax { get; } |
|||
public int XMax { get; } |
|||
|
|||
public int YMax { get; } |
|||
} |
|||
public int YMax { get; } |
|||
} |
|||
|
|||
@ -1,32 +1,31 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// Licensed under the Six Labors Split License.
|
|||
|
|||
using System.Diagnostics; |
|||
using System.Runtime.InteropServices; |
|||
|
|||
namespace SixLabors.ImageSharp.Formats.OpenExr |
|||
namespace SixLabors.ImageSharp.Formats.OpenExr; |
|||
|
|||
[DebuggerDisplay("Name: {ChannelName}, PixelType: {PixelType}")] |
|||
[StructLayout(LayoutKind.Sequential, Pack = 1)] |
|||
internal readonly struct ExrChannelInfo |
|||
{ |
|||
[DebuggerDisplay("Name: {ChannelName}, PixelType: {PixelType}")] |
|||
[StructLayout(LayoutKind.Sequential, Pack = 1)] |
|||
internal readonly struct ExrChannelInfo |
|||
public ExrChannelInfo(string channelName, ExrPixelType pixelType, byte pLinear, int xSampling, int ySampling) |
|||
{ |
|||
public ExrChannelInfo(string channelName, ExrPixelType pixelType, byte pLinear, int xSampling, int ySampling) |
|||
{ |
|||
this.ChannelName = channelName; |
|||
this.PixelType = pixelType; |
|||
this.PLinear = pLinear; |
|||
this.XSampling = xSampling; |
|||
this.YSampling = ySampling; |
|||
} |
|||
this.ChannelName = channelName; |
|||
this.PixelType = pixelType; |
|||
this.PLinear = pLinear; |
|||
this.XSampling = xSampling; |
|||
this.YSampling = ySampling; |
|||
} |
|||
|
|||
public string ChannelName { get; } |
|||
public string ChannelName { get; } |
|||
|
|||
public ExrPixelType PixelType { get; } |
|||
public ExrPixelType PixelType { get; } |
|||
|
|||
public byte PLinear { get; } |
|||
public byte PLinear { get; } |
|||
|
|||
public int XSampling { get; } |
|||
public int XSampling { get; } |
|||
|
|||
public int YSampling { get; } |
|||
} |
|||
public int YSampling { get; } |
|||
} |
|||
|
|||
@ -1,19 +1,18 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// Licensed under the Six Labors Split License.
|
|||
|
|||
namespace SixLabors.ImageSharp.Formats.OpenExr |
|||
namespace SixLabors.ImageSharp.Formats.OpenExr; |
|||
|
|||
/// <summary>
|
|||
/// Registers the image encoders, decoders and mime type detectors for the OpenExr format.
|
|||
/// </summary>
|
|||
public sealed class ExrConfigurationModule : IConfigurationModule |
|||
{ |
|||
/// <summary>
|
|||
/// Registers the image encoders, decoders and mime type detectors for the OpenExr format.
|
|||
/// </summary>
|
|||
public sealed class ExrConfigurationModule : IConfigurationModule |
|||
/// <inheritdoc/>
|
|||
public void Configure(Configuration configuration) |
|||
{ |
|||
/// <inheritdoc/>
|
|||
public void Configure(Configuration configuration) |
|||
{ |
|||
configuration.ImageFormatsManager.SetEncoder(ExrFormat.Instance, new ExrEncoder()); |
|||
configuration.ImageFormatsManager.SetDecoder(ExrFormat.Instance, new ExrDecoder()); |
|||
configuration.ImageFormatsManager.AddImageFormatDetector(new ExrImageFormatDetector()); |
|||
} |
|||
configuration.ImageFormatsManager.SetEncoder(ExrFormat.Instance, new ExrEncoder()); |
|||
configuration.ImageFormatsManager.SetDecoder(ExrFormat.Instance, new ExrDecoder()); |
|||
configuration.ImageFormatsManager.AddImageFormatDetector(new ExrImageFormatDetector()); |
|||
} |
|||
} |
|||
|
|||
@ -1,85 +1,82 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// Licensed under the Six Labors Split License.
|
|||
|
|||
using System.Collections.Generic; |
|||
namespace SixLabors.ImageSharp.Formats.OpenExr; |
|||
|
|||
namespace SixLabors.ImageSharp.Formats.OpenExr |
|||
/// <summary>
|
|||
/// Defines constants relating to OpenExr images.
|
|||
/// </summary>
|
|||
internal static class ExrConstants |
|||
{ |
|||
/// <summary>
|
|||
/// Defines constants relating to OpenExr images.
|
|||
/// The list of mimetypes that equate to a OpenExr image.
|
|||
/// </summary>
|
|||
internal static class ExrConstants |
|||
{ |
|||
/// <summary>
|
|||
/// The list of mimetypes that equate to a OpenExr image.
|
|||
/// </summary>
|
|||
public static readonly IEnumerable<string> MimeTypes = new[] { "image/x-exr" }; |
|||
public static readonly IEnumerable<string> MimeTypes = new[] { "image/x-exr" }; |
|||
|
|||
/// <summary>
|
|||
/// The list of file extensions that equate to a OpenExr image.
|
|||
/// </summary>
|
|||
public static readonly IEnumerable<string> FileExtensions = new[] { "exr" }; |
|||
/// <summary>
|
|||
/// The list of file extensions that equate to a OpenExr image.
|
|||
/// </summary>
|
|||
public static readonly IEnumerable<string> FileExtensions = new[] { "exr" }; |
|||
|
|||
/// <summary>
|
|||
/// The magick bytes identifying an OpenExr image.
|
|||
/// </summary>
|
|||
public static readonly int MagickBytes = 20000630; |
|||
/// <summary>
|
|||
/// The magick bytes identifying an OpenExr image.
|
|||
/// </summary>
|
|||
public static readonly int MagickBytes = 20000630; |
|||
|
|||
/// <summary>
|
|||
/// EXR attribute names.
|
|||
/// </summary>
|
|||
internal static class AttributeNames |
|||
{ |
|||
public const string Channels = "channels"; |
|||
/// <summary>
|
|||
/// EXR attribute names.
|
|||
/// </summary>
|
|||
internal static class AttributeNames |
|||
{ |
|||
public const string Channels = "channels"; |
|||
|
|||
public const string Compression = "compression"; |
|||
public const string Compression = "compression"; |
|||
|
|||
public const string DataWindow = "dataWindow"; |
|||
public const string DataWindow = "dataWindow"; |
|||
|
|||
public const string DisplayWindow = "displayWindow"; |
|||
public const string DisplayWindow = "displayWindow"; |
|||
|
|||
public const string LineOrder = "lineOrder"; |
|||
public const string LineOrder = "lineOrder"; |
|||
|
|||
public const string PixelAspectRatio = "pixelAspectRatio"; |
|||
public const string PixelAspectRatio = "pixelAspectRatio"; |
|||
|
|||
public const string ScreenWindowCenter = "screenWindowCenter"; |
|||
public const string ScreenWindowCenter = "screenWindowCenter"; |
|||
|
|||
public const string ScreenWindowWidth = "screenWindowWidth"; |
|||
public const string ScreenWindowWidth = "screenWindowWidth"; |
|||
|
|||
public const string Tiles = "tiles"; |
|||
public const string Tiles = "tiles"; |
|||
|
|||
public const string ChunkCount = "chunkCount"; |
|||
} |
|||
public const string ChunkCount = "chunkCount"; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// EXR attribute types.
|
|||
/// </summary>
|
|||
internal static class AttibuteTypes |
|||
{ |
|||
public const string ChannelList = "chlist"; |
|||
/// <summary>
|
|||
/// EXR attribute types.
|
|||
/// </summary>
|
|||
internal static class AttibuteTypes |
|||
{ |
|||
public const string ChannelList = "chlist"; |
|||
|
|||
public const string Compression = "compression"; |
|||
public const string Compression = "compression"; |
|||
|
|||
public const string Float = "float"; |
|||
public const string Float = "float"; |
|||
|
|||
public const string LineOrder = "lineOrder"; |
|||
public const string LineOrder = "lineOrder"; |
|||
|
|||
public const string TwoFloat = "v2f"; |
|||
public const string TwoFloat = "v2f"; |
|||
|
|||
public const string BoxInt = "box2i"; |
|||
} |
|||
public const string BoxInt = "box2i"; |
|||
} |
|||
|
|||
internal static class ChannelNames |
|||
{ |
|||
public const string Red = "R"; |
|||
internal static class ChannelNames |
|||
{ |
|||
public const string Red = "R"; |
|||
|
|||
public const string Green = "G"; |
|||
public const string Green = "G"; |
|||
|
|||
public const string Blue = "B"; |
|||
public const string Blue = "B"; |
|||
|
|||
public const string Alpha = "A"; |
|||
public const string Alpha = "A"; |
|||
|
|||
public const string Luminance = "Y"; |
|||
} |
|||
public const string Luminance = "Y"; |
|||
} |
|||
} |
|||
|
|||
@ -1,61 +1,46 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// Licensed under the Six Labors Split License.
|
|||
|
|||
using System.IO; |
|||
using System.Threading; |
|||
using System.Threading.Tasks; |
|||
using SixLabors.ImageSharp.PixelFormats; |
|||
|
|||
namespace SixLabors.ImageSharp.Formats.OpenExr |
|||
namespace SixLabors.ImageSharp.Formats.OpenExr; |
|||
|
|||
/// <summary>
|
|||
/// Image decoder for generating an image out of a OpenExr stream.
|
|||
/// </summary>
|
|||
public class ExrDecoder : IImageDecoderSpecialized<ExrDecoderOptions> |
|||
{ |
|||
/// <summary>
|
|||
/// Image decoder for generating an image out of a OpenExr stream.
|
|||
/// </summary>
|
|||
public sealed class ExrDecoder : IImageDecoder, IExrDecoderOptions, IImageInfoDetector |
|||
/// <inheritdoc/>
|
|||
IImageInfo IImageInfoDetector.Identify(DecoderOptions options, Stream stream, CancellationToken cancellationToken) |
|||
{ |
|||
/// <inheritdoc/>
|
|||
public Image<TPixel> Decode<TPixel>(Configuration configuration, Stream stream) |
|||
where TPixel : unmanaged, IPixel<TPixel> |
|||
{ |
|||
Guard.NotNull(stream, nameof(stream)); |
|||
|
|||
var decoder = new ExrDecoderCore(configuration, this); |
|||
return decoder.Decode<TPixel>(configuration, stream); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public Image Decode(Configuration configuration, Stream stream) |
|||
=> this.Decode<Rgba32>(configuration, stream); |
|||
|
|||
/// <inheritdoc/>
|
|||
public Task<Image<TPixel>> DecodeAsync<TPixel>(Configuration configuration, Stream stream, CancellationToken cancellationToken) |
|||
where TPixel : unmanaged, IPixel<TPixel> |
|||
{ |
|||
Guard.NotNull(stream, nameof(stream)); |
|||
|
|||
var decoder = new ExrDecoderCore(configuration, this); |
|||
return decoder.DecodeAsync<TPixel>(configuration, stream, cancellationToken); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public async Task<Image> DecodeAsync(Configuration configuration, Stream stream, CancellationToken cancellationToken) |
|||
=> await this.DecodeAsync<Rgba32>(configuration, stream, cancellationToken) |
|||
.ConfigureAwait(false); |
|||
|
|||
/// <inheritdoc/>
|
|||
public IImageInfo Identify(Configuration configuration, Stream stream) |
|||
{ |
|||
Guard.NotNull(stream, nameof(stream)); |
|||
|
|||
return new ExrDecoderCore(configuration, this).Identify(configuration, stream); |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
public Task<IImageInfo> IdentifyAsync(Configuration configuration, Stream stream, CancellationToken cancellationToken) |
|||
{ |
|||
Guard.NotNull(stream, nameof(stream)); |
|||
|
|||
return new ExrDecoderCore(configuration, this).IdentifyAsync(configuration, stream, cancellationToken); |
|||
} |
|||
Guard.NotNull(options, nameof(options)); |
|||
Guard.NotNull(stream, nameof(stream)); |
|||
|
|||
return new ExrDecoderCore(new() { GeneralOptions = options }).Identify(options.Configuration, stream, cancellationToken); |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
Image<TPixel> IImageDecoder.Decode<TPixel>(DecoderOptions options, Stream stream, CancellationToken cancellationToken) |
|||
=> ((IImageDecoderSpecialized<ExrDecoderOptions>)this).Decode<TPixel>(new() { GeneralOptions = options }, stream, cancellationToken); |
|||
|
|||
/// <inheritdoc/>
|
|||
Image IImageDecoder.Decode(DecoderOptions options, Stream stream, CancellationToken cancellationToken) |
|||
=> ((IImageDecoderSpecialized<ExrDecoderOptions>)this).Decode(new() { GeneralOptions = options }, stream, cancellationToken); |
|||
|
|||
/// <inheritdoc/>
|
|||
Image<TPixel> IImageDecoderSpecialized<ExrDecoderOptions>.Decode<TPixel>(ExrDecoderOptions options, Stream stream, CancellationToken cancellationToken) |
|||
{ |
|||
Guard.NotNull(options, nameof(options)); |
|||
Guard.NotNull(stream, nameof(stream)); |
|||
|
|||
Image<TPixel> image = new ExrDecoderCore(options).Decode<TPixel>(options.GeneralOptions.Configuration, stream, cancellationToken); |
|||
|
|||
ImageDecoderUtilities.Resize(options.GeneralOptions, image); |
|||
|
|||
return image; |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
Image IImageDecoderSpecialized<ExrDecoderOptions>.Decode(ExrDecoderOptions options, Stream stream, CancellationToken cancellationToken) |
|||
=> ((IImageDecoderSpecialized<ExrDecoderOptions>)this).Decode<Rgba32>(options, stream, cancellationToken); |
|||
} |
|||
|
|||
File diff suppressed because it is too large
@ -0,0 +1,13 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Six Labors Split License.
|
|||
|
|||
namespace SixLabors.ImageSharp.Formats.OpenExr; |
|||
|
|||
/// <summary>
|
|||
/// Image decoder options for decoding OpenExr streams.
|
|||
/// </summary>
|
|||
public sealed class ExrDecoderOptions : ISpecializedDecoderOptions |
|||
{ |
|||
/// <inheritdoc/>
|
|||
public DecoderOptions GeneralOptions { get; set; } = new(); |
|||
} |
|||
@ -1,38 +1,34 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// Licensed under the Six Labors Split License.
|
|||
|
|||
using System.IO; |
|||
using System.Threading; |
|||
using System.Threading.Tasks; |
|||
using SixLabors.ImageSharp.Advanced; |
|||
using SixLabors.ImageSharp.PixelFormats; |
|||
|
|||
namespace SixLabors.ImageSharp.Formats.OpenExr |
|||
namespace SixLabors.ImageSharp.Formats.OpenExr; |
|||
|
|||
/// <summary>
|
|||
/// Image encoder for writing an image to a stream in the OpenExr Format.
|
|||
/// </summary>
|
|||
public sealed class ExrEncoder : IImageEncoder, IExrEncoderOptions |
|||
{ |
|||
/// <summary>
|
|||
/// Image encoder for writing an image to a stream in the OpenExr Format.
|
|||
/// Gets or sets the pixel type of the image.
|
|||
/// </summary>
|
|||
public sealed class ExrEncoder : IImageEncoder, IExrEncoderOptions |
|||
{ |
|||
/// <summary>
|
|||
/// Gets or sets the pixel type of the image.
|
|||
/// </summary>
|
|||
public ExrPixelType? PixelType { get; set; } |
|||
public ExrPixelType? PixelType { get; set; } |
|||
|
|||
/// <inheritdoc/>
|
|||
public void Encode<TPixel>(Image<TPixel> image, Stream stream) |
|||
where TPixel : unmanaged, IPixel<TPixel> |
|||
{ |
|||
var encoder = new ExrEncoderCore(this, image.GetMemoryAllocator()); |
|||
encoder.Encode(image, stream); |
|||
} |
|||
/// <inheritdoc/>
|
|||
public void Encode<TPixel>(Image<TPixel> image, Stream stream) |
|||
where TPixel : unmanaged, IPixel<TPixel> |
|||
{ |
|||
ExrEncoderCore encoder = new(this, image.GetMemoryAllocator()); |
|||
encoder.Encode(image, stream); |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
public Task EncodeAsync<TPixel>(Image<TPixel> image, Stream stream, CancellationToken cancellationToken) |
|||
where TPixel : unmanaged, IPixel<TPixel> |
|||
{ |
|||
var encoder = new ExrEncoderCore(this, image.GetMemoryAllocator()); |
|||
return encoder.EncodeAsync(image, stream, cancellationToken); |
|||
} |
|||
/// <inheritdoc/>
|
|||
public Task EncodeAsync<TPixel>(Image<TPixel> image, Stream stream, CancellationToken cancellationToken) |
|||
where TPixel : unmanaged, IPixel<TPixel> |
|||
{ |
|||
ExrEncoderCore encoder = new(this, image.GetMemoryAllocator()); |
|||
return encoder.EncodeAsync(image, stream, cancellationToken); |
|||
} |
|||
} |
|||
|
|||
@ -1,422 +1,418 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// Licensed under the Six Labors Split License.
|
|||
|
|||
using System; |
|||
using System.Buffers; |
|||
using System.Buffers.Binary; |
|||
using System.Collections.Generic; |
|||
using System.IO; |
|||
using System.Numerics; |
|||
using System.Runtime.CompilerServices; |
|||
using System.Threading; |
|||
using SixLabors.ImageSharp.Formats.OpenExr.Compression; |
|||
using SixLabors.ImageSharp.Memory; |
|||
using SixLabors.ImageSharp.Metadata; |
|||
using SixLabors.ImageSharp.PixelFormats; |
|||
|
|||
namespace SixLabors.ImageSharp.Formats.OpenExr |
|||
namespace SixLabors.ImageSharp.Formats.OpenExr; |
|||
|
|||
/// <summary>
|
|||
/// Image encoder for writing an image to a stream in the OpenExr format.
|
|||
/// </summary>
|
|||
internal sealed class ExrEncoderCore : IImageEncoderInternals |
|||
{ |
|||
/// <summary>
|
|||
/// Image encoder for writing an image to a stream in the OpenExr format.
|
|||
/// Reusable buffer.
|
|||
/// </summary>
|
|||
internal sealed class ExrEncoderCore : IImageEncoderInternals |
|||
{ |
|||
/// <summary>
|
|||
/// Reusable buffer.
|
|||
/// </summary>
|
|||
private readonly byte[] buffer = new byte[8]; |
|||
|
|||
/// <summary>
|
|||
/// Used for allocating memory during processing operations.
|
|||
/// </summary>
|
|||
private readonly MemoryAllocator memoryAllocator; |
|||
|
|||
/// <summary>
|
|||
/// The pixel type of the image.
|
|||
/// </summary>
|
|||
private ExrPixelType? pixelType; |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="ExrEncoderCore"/> class.
|
|||
/// </summary>
|
|||
/// <param name="options">The encoder options.</param>
|
|||
/// <param name="memoryAllocator">The memory manager.</param>
|
|||
public ExrEncoderCore(IExrEncoderOptions options, MemoryAllocator memoryAllocator) |
|||
{ |
|||
this.memoryAllocator = memoryAllocator; |
|||
this.pixelType = options.PixelType; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Encodes the image to the specified stream from the <see cref="ImageFrame{TPixel}"/>.
|
|||
/// </summary>
|
|||
/// <typeparam name="TPixel">The pixel format.</typeparam>
|
|||
/// <param name="image">The <see cref="ImageFrame{TPixel}"/> to encode from.</param>
|
|||
/// <param name="stream">The <see cref="Stream"/> to encode the image data to.</param>
|
|||
/// <param name="cancellationToken">The token to request cancellation.</param>
|
|||
public void Encode<TPixel>(Image<TPixel> image, Stream stream, CancellationToken cancellationToken) |
|||
where TPixel : unmanaged, IPixel<TPixel> |
|||
{ |
|||
Guard.NotNull(image, nameof(image)); |
|||
Guard.NotNull(stream, nameof(stream)); |
|||
private readonly byte[] buffer = new byte[8]; |
|||
|
|||
Buffer2D<TPixel> pixels = image.Frames.RootFrame.PixelBuffer; |
|||
|
|||
ImageMetadata metadata = image.Metadata; |
|||
ExrMetadata exrMetadata = metadata.GetExrMetadata(); |
|||
this.pixelType ??= exrMetadata.PixelType; |
|||
int width = image.Width; |
|||
int height = image.Height; |
|||
var header = new ExrHeaderAttributes() |
|||
{ |
|||
Compression = ExrCompressionType.None, |
|||
AspectRatio = 1.0f, |
|||
DataWindow = new ExrBox2i(0, 0, width - 1, height - 1), |
|||
DisplayWindow = new ExrBox2i(0, 0, width - 1, height - 1), |
|||
LineOrder = ExrLineOrder.IncreasingY, |
|||
ScreenWindowCenter = new PointF(0.0f, 0.0f), |
|||
ScreenWindowWidth = 1, |
|||
Channels = new List<ExrChannelInfo>() |
|||
{ |
|||
new(ExrConstants.ChannelNames.Blue, this.pixelType.Value, 0, 1, 1), |
|||
new(ExrConstants.ChannelNames.Green, this.pixelType.Value, 0, 1, 1), |
|||
new(ExrConstants.ChannelNames.Red, this.pixelType.Value, 0, 1, 1), |
|||
} |
|||
}; |
|||
|
|||
// Write magick bytes.
|
|||
BinaryPrimitives.WriteInt32LittleEndian(this.buffer, ExrConstants.MagickBytes); |
|||
stream.Write(this.buffer.AsSpan(0, 4)); |
|||
|
|||
// Version number.
|
|||
this.buffer[0] = 2; |
|||
/// <summary>
|
|||
/// Used for allocating memory during processing operations.
|
|||
/// </summary>
|
|||
private readonly MemoryAllocator memoryAllocator; |
|||
|
|||
// Second, third and fourth bytes store info about the image, set all to default: zero.
|
|||
this.buffer[1] = 0; |
|||
this.buffer[2] = 0; |
|||
this.buffer[3] = 0; |
|||
stream.Write(this.buffer.AsSpan(0, 4)); |
|||
/// <summary>
|
|||
/// The pixel type of the image.
|
|||
/// </summary>
|
|||
private ExrPixelType? pixelType; |
|||
|
|||
// Write EXR header.
|
|||
this.WriteHeader(stream, header); |
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="ExrEncoderCore"/> class.
|
|||
/// </summary>
|
|||
/// <param name="options">The encoder options.</param>
|
|||
/// <param name="memoryAllocator">The memory manager.</param>
|
|||
public ExrEncoderCore(IExrEncoderOptions options, MemoryAllocator memoryAllocator) |
|||
{ |
|||
this.memoryAllocator = memoryAllocator; |
|||
this.pixelType = options.PixelType; |
|||
} |
|||
|
|||
// Write offsets to each pixel row.
|
|||
int bytesPerChannel = this.pixelType == ExrPixelType.Half ? 2 : 4; |
|||
int numberOfChannels = 3; |
|||
uint rowSizeBytes = (uint)(width * numberOfChannels * bytesPerChannel); |
|||
this.WriteRowOffsets(stream, height, rowSizeBytes); |
|||
/// <summary>
|
|||
/// Encodes the image to the specified stream from the <see cref="ImageFrame{TPixel}"/>.
|
|||
/// </summary>
|
|||
/// <typeparam name="TPixel">The pixel format.</typeparam>
|
|||
/// <param name="image">The <see cref="ImageFrame{TPixel}"/> to encode from.</param>
|
|||
/// <param name="stream">The <see cref="Stream"/> to encode the image data to.</param>
|
|||
/// <param name="cancellationToken">The token to request cancellation.</param>
|
|||
public void Encode<TPixel>(Image<TPixel> image, Stream stream, CancellationToken cancellationToken) |
|||
where TPixel : unmanaged, IPixel<TPixel> |
|||
{ |
|||
Guard.NotNull(image, nameof(image)); |
|||
Guard.NotNull(stream, nameof(stream)); |
|||
|
|||
// Write pixel data.
|
|||
switch (this.pixelType) |
|||
{ |
|||
case ExrPixelType.Half: |
|||
case ExrPixelType.Float: |
|||
this.EncodeFloatingPointPixelData(stream, pixels, width, height, rowSizeBytes); |
|||
break; |
|||
case ExrPixelType.UnsignedInt: |
|||
this.EncodeUnsignedIntPixelData(stream, pixels, width, height, rowSizeBytes); |
|||
break; |
|||
} |
|||
} |
|||
Buffer2D<TPixel> pixels = image.Frames.RootFrame.PixelBuffer; |
|||
|
|||
private void EncodeFloatingPointPixelData<TPixel>(Stream stream, Buffer2D<TPixel> pixels, int width, int height, uint rowSizeBytes) |
|||
where TPixel : unmanaged, IPixel<TPixel> |
|||
ImageMetadata metadata = image.Metadata; |
|||
ExrMetadata exrMetadata = metadata.GetExrMetadata(); |
|||
this.pixelType ??= exrMetadata.PixelType; |
|||
int width = image.Width; |
|||
int height = image.Height; |
|||
var header = new ExrHeaderAttributes() |
|||
{ |
|||
using IMemoryOwner<float> rgbBuffer = this.memoryAllocator.Allocate<float>(width * 3); |
|||
Span<float> redBuffer = rgbBuffer.GetSpan().Slice(0, width); |
|||
Span<float> greenBuffer = rgbBuffer.GetSpan().Slice(width, width); |
|||
Span<float> blueBuffer = rgbBuffer.GetSpan().Slice(width * 2, width); |
|||
|
|||
for (int y = 0; y < height; y++) |
|||
Compression = ExrCompressionType.None, |
|||
AspectRatio = 1.0f, |
|||
DataWindow = new ExrBox2i(0, 0, width - 1, height - 1), |
|||
DisplayWindow = new ExrBox2i(0, 0, width - 1, height - 1), |
|||
LineOrder = ExrLineOrder.IncreasingY, |
|||
ScreenWindowCenter = new PointF(0.0f, 0.0f), |
|||
ScreenWindowWidth = 1, |
|||
Channels = new List<ExrChannelInfo>() |
|||
{ |
|||
Span<TPixel> pixelRowSpan = pixels.DangerousGetRowSpan(y); |
|||
|
|||
for (int x = 0; x < width; x++) |
|||
{ |
|||
var vector4 = pixelRowSpan[x].ToVector4(); |
|||
redBuffer[x] = vector4.X; |
|||
greenBuffer[x] = vector4.Y; |
|||
blueBuffer[x] = vector4.Z; |
|||
} |
|||
|
|||
// Write row index.
|
|||
BinaryPrimitives.WriteUInt32LittleEndian(this.buffer, (uint)y); |
|||
stream.Write(this.buffer.AsSpan(0, 4)); |
|||
|
|||
// Write pixel row data size.
|
|||
BinaryPrimitives.WriteUInt32LittleEndian(this.buffer, rowSizeBytes); |
|||
stream.Write(this.buffer.AsSpan(0, 4)); |
|||
|
|||
switch (this.pixelType) |
|||
{ |
|||
case ExrPixelType.Float: |
|||
this.WriteSingleRow(stream, width, blueBuffer, greenBuffer, redBuffer); |
|||
break; |
|||
case ExrPixelType.Half: |
|||
this.WriteHalfSingleRow(stream, width, blueBuffer, greenBuffer, redBuffer); |
|||
break; |
|||
} |
|||
new(ExrConstants.ChannelNames.Blue, this.pixelType.Value, 0, 1, 1), |
|||
new(ExrConstants.ChannelNames.Green, this.pixelType.Value, 0, 1, 1), |
|||
new(ExrConstants.ChannelNames.Red, this.pixelType.Value, 0, 1, 1), |
|||
} |
|||
} |
|||
|
|||
private void EncodeUnsignedIntPixelData<TPixel>(Stream stream, Buffer2D<TPixel> pixels, int width, int height, uint rowSizeBytes) |
|||
where TPixel : unmanaged, IPixel<TPixel> |
|||
{ |
|||
using IMemoryOwner<uint> rgbBuffer = this.memoryAllocator.Allocate<uint>(width * 3); |
|||
Span<uint> redBuffer = rgbBuffer.GetSpan().Slice(0, width); |
|||
Span<uint> greenBuffer = rgbBuffer.GetSpan().Slice(width, width); |
|||
Span<uint> blueBuffer = rgbBuffer.GetSpan().Slice(width * 2, width); |
|||
|
|||
var rgb = default(Rgb96); |
|||
for (int y = 0; y < height; y++) |
|||
{ |
|||
Span<TPixel> pixelRowSpan = pixels.DangerousGetRowSpan(y); |
|||
}; |
|||
|
|||
for (int x = 0; x < width; x++) |
|||
{ |
|||
var vector4 = pixelRowSpan[x].ToVector4(); |
|||
rgb.FromVector4(vector4); |
|||
// Write magick bytes.
|
|||
BinaryPrimitives.WriteInt32LittleEndian(this.buffer, ExrConstants.MagickBytes); |
|||
stream.Write(this.buffer.AsSpan(0, 4)); |
|||
|
|||
redBuffer[x] = rgb.R; |
|||
greenBuffer[x] = rgb.G; |
|||
blueBuffer[x] = rgb.B; |
|||
} |
|||
// Version number.
|
|||
this.buffer[0] = 2; |
|||
|
|||
// Write row index.
|
|||
BinaryPrimitives.WriteUInt32LittleEndian(this.buffer, (uint)y); |
|||
stream.Write(this.buffer.AsSpan(0, 4)); |
|||
// Second, third and fourth bytes store info about the image, set all to default: zero.
|
|||
this.buffer[1] = 0; |
|||
this.buffer[2] = 0; |
|||
this.buffer[3] = 0; |
|||
stream.Write(this.buffer.AsSpan(0, 4)); |
|||
|
|||
// Write pixel row data size.
|
|||
BinaryPrimitives.WriteUInt32LittleEndian(this.buffer, rowSizeBytes); |
|||
stream.Write(this.buffer.AsSpan(0, 4)); |
|||
// Write EXR header.
|
|||
this.WriteHeader(stream, header); |
|||
|
|||
this.WriteUnsignedIntRow(stream, width, blueBuffer, greenBuffer, redBuffer); |
|||
} |
|||
} |
|||
// Write offsets to each pixel row.
|
|||
int bytesPerChannel = this.pixelType == ExrPixelType.Half ? 2 : 4; |
|||
int numberOfChannels = 3; |
|||
uint rowSizeBytes = (uint)(width * numberOfChannels * bytesPerChannel); |
|||
this.WriteRowOffsets(stream, height, rowSizeBytes); |
|||
|
|||
private void WriteHeader(Stream stream, ExrHeaderAttributes header) |
|||
// Write pixel data.
|
|||
switch (this.pixelType) |
|||
{ |
|||
this.WriteChannels(stream, header.Channels); |
|||
this.WriteCompression(stream, header.Compression.Value); |
|||
this.WriteDataWindow(stream, header.DataWindow.Value); |
|||
this.WriteDisplayWindow(stream, header.DisplayWindow.Value); |
|||
this.WritePixelAspectRatio(stream, header.AspectRatio.Value); |
|||
this.WriteLineOrder(stream, header.LineOrder.Value); |
|||
this.WriteScreenWindowCenter(stream, header.ScreenWindowCenter.Value); |
|||
this.WriteScreenWindowWidth(stream, header.ScreenWindowWidth.Value); |
|||
stream.WriteByte(0); |
|||
case ExrPixelType.Half: |
|||
case ExrPixelType.Float: |
|||
this.EncodeFloatingPointPixelData(stream, pixels, width, height, rowSizeBytes); |
|||
break; |
|||
case ExrPixelType.UnsignedInt: |
|||
this.EncodeUnsignedIntPixelData(stream, pixels, width, height, rowSizeBytes); |
|||
break; |
|||
} |
|||
} |
|||
|
|||
private void EncodeFloatingPointPixelData<TPixel>(Stream stream, Buffer2D<TPixel> pixels, int width, int height, uint rowSizeBytes) |
|||
where TPixel : unmanaged, IPixel<TPixel> |
|||
{ |
|||
using IMemoryOwner<float> rgbBuffer = this.memoryAllocator.Allocate<float>(width * 3); |
|||
Span<float> redBuffer = rgbBuffer.GetSpan().Slice(0, width); |
|||
Span<float> greenBuffer = rgbBuffer.GetSpan().Slice(width, width); |
|||
Span<float> blueBuffer = rgbBuffer.GetSpan().Slice(width * 2, width); |
|||
|
|||
private void WriteSingleRow(Stream stream, int width, Span<float> blueBuffer, Span<float> greenBuffer, Span<float> redBuffer) |
|||
for (int y = 0; y < height; y++) |
|||
{ |
|||
for (int x = 0; x < width; x++) |
|||
{ |
|||
this.WriteSingle(stream, blueBuffer[x]); |
|||
} |
|||
Span<TPixel> pixelRowSpan = pixels.DangerousGetRowSpan(y); |
|||
|
|||
for (int x = 0; x < width; x++) |
|||
{ |
|||
this.WriteSingle(stream, greenBuffer[x]); |
|||
var vector4 = pixelRowSpan[x].ToVector4(); |
|||
redBuffer[x] = vector4.X; |
|||
greenBuffer[x] = vector4.Y; |
|||
blueBuffer[x] = vector4.Z; |
|||
} |
|||
|
|||
for (int x = 0; x < width; x++) |
|||
// Write row index.
|
|||
BinaryPrimitives.WriteUInt32LittleEndian(this.buffer, (uint)y); |
|||
stream.Write(this.buffer.AsSpan(0, 4)); |
|||
|
|||
// Write pixel row data size.
|
|||
BinaryPrimitives.WriteUInt32LittleEndian(this.buffer, rowSizeBytes); |
|||
stream.Write(this.buffer.AsSpan(0, 4)); |
|||
|
|||
switch (this.pixelType) |
|||
{ |
|||
this.WriteSingle(stream, redBuffer[x]); |
|||
case ExrPixelType.Float: |
|||
this.WriteSingleRow(stream, width, blueBuffer, greenBuffer, redBuffer); |
|||
break; |
|||
case ExrPixelType.Half: |
|||
this.WriteHalfSingleRow(stream, width, blueBuffer, greenBuffer, redBuffer); |
|||
break; |
|||
} |
|||
} |
|||
} |
|||
|
|||
private void EncodeUnsignedIntPixelData<TPixel>(Stream stream, Buffer2D<TPixel> pixels, int width, int height, uint rowSizeBytes) |
|||
where TPixel : unmanaged, IPixel<TPixel> |
|||
{ |
|||
using IMemoryOwner<uint> rgbBuffer = this.memoryAllocator.Allocate<uint>(width * 3); |
|||
Span<uint> redBuffer = rgbBuffer.GetSpan().Slice(0, width); |
|||
Span<uint> greenBuffer = rgbBuffer.GetSpan().Slice(width, width); |
|||
Span<uint> blueBuffer = rgbBuffer.GetSpan().Slice(width * 2, width); |
|||
|
|||
private void WriteHalfSingleRow(Stream stream, int width, Span<float> blueBuffer, Span<float> greenBuffer, Span<float> redBuffer) |
|||
Rgb96 rgb = default; |
|||
for (int y = 0; y < height; y++) |
|||
{ |
|||
for (int x = 0; x < width; x++) |
|||
{ |
|||
this.WriteHalfSingle(stream, blueBuffer[x]); |
|||
} |
|||
Span<TPixel> pixelRowSpan = pixels.DangerousGetRowSpan(y); |
|||
|
|||
for (int x = 0; x < width; x++) |
|||
{ |
|||
this.WriteHalfSingle(stream, greenBuffer[x]); |
|||
} |
|||
Vector4 vector4 = pixelRowSpan[x].ToVector4(); |
|||
rgb.FromVector4(vector4); |
|||
|
|||
for (int x = 0; x < width; x++) |
|||
{ |
|||
this.WriteHalfSingle(stream, redBuffer[x]); |
|||
redBuffer[x] = rgb.R; |
|||
greenBuffer[x] = rgb.G; |
|||
blueBuffer[x] = rgb.B; |
|||
} |
|||
} |
|||
|
|||
private void WriteUnsignedIntRow(Stream stream, int width, Span<uint> blueBuffer, Span<uint> greenBuffer, Span<uint> redBuffer) |
|||
{ |
|||
for (int x = 0; x < width; x++) |
|||
{ |
|||
this.WriteUnsignedInt(stream, blueBuffer[x]); |
|||
} |
|||
// Write row index.
|
|||
BinaryPrimitives.WriteUInt32LittleEndian(this.buffer, (uint)y); |
|||
stream.Write(this.buffer.AsSpan(0, 4)); |
|||
|
|||
for (int x = 0; x < width; x++) |
|||
{ |
|||
this.WriteUnsignedInt(stream, greenBuffer[x]); |
|||
} |
|||
// Write pixel row data size.
|
|||
BinaryPrimitives.WriteUInt32LittleEndian(this.buffer, rowSizeBytes); |
|||
stream.Write(this.buffer.AsSpan(0, 4)); |
|||
|
|||
for (int x = 0; x < width; x++) |
|||
{ |
|||
this.WriteUnsignedInt(stream, redBuffer[x]); |
|||
} |
|||
this.WriteUnsignedIntRow(stream, width, blueBuffer, greenBuffer, redBuffer); |
|||
} |
|||
} |
|||
|
|||
private void WriteRowOffsets(Stream stream, int height, uint rowSizeBytes) |
|||
private void WriteHeader(Stream stream, ExrHeaderAttributes header) |
|||
{ |
|||
this.WriteChannels(stream, header.Channels); |
|||
this.WriteCompression(stream, header.Compression.Value); |
|||
this.WriteDataWindow(stream, header.DataWindow.Value); |
|||
this.WriteDisplayWindow(stream, header.DisplayWindow.Value); |
|||
this.WritePixelAspectRatio(stream, header.AspectRatio.Value); |
|||
this.WriteLineOrder(stream, header.LineOrder.Value); |
|||
this.WriteScreenWindowCenter(stream, header.ScreenWindowCenter.Value); |
|||
this.WriteScreenWindowWidth(stream, header.ScreenWindowWidth.Value); |
|||
stream.WriteByte(0); |
|||
} |
|||
|
|||
private void WriteSingleRow(Stream stream, int width, Span<float> blueBuffer, Span<float> greenBuffer, Span<float> redBuffer) |
|||
{ |
|||
for (int x = 0; x < width; x++) |
|||
{ |
|||
ulong startOfPixelData = (ulong)stream.Position + (8 * (ulong)height); |
|||
ulong offset = startOfPixelData; |
|||
for (int i = 0; i < height; i++) |
|||
{ |
|||
BinaryPrimitives.WriteUInt64LittleEndian(this.buffer, offset); |
|||
stream.Write(this.buffer); |
|||
offset += 4 + 4 + rowSizeBytes; |
|||
} |
|||
this.WriteSingle(stream, blueBuffer[x]); |
|||
} |
|||
|
|||
private void WriteChannels(Stream stream, IList<ExrChannelInfo> channels) |
|||
for (int x = 0; x < width; x++) |
|||
{ |
|||
int attributeSize = 0; |
|||
foreach (ExrChannelInfo channelInfo in channels) |
|||
{ |
|||
attributeSize += channelInfo.ChannelName.Length + 1; |
|||
attributeSize += 16; |
|||
} |
|||
|
|||
// Last zero byte.
|
|||
attributeSize++; |
|||
this.WriteAttributeInformation(stream, ExrConstants.AttributeNames.Channels, ExrConstants.AttibuteTypes.ChannelList, attributeSize); |
|||
|
|||
foreach (ExrChannelInfo channelInfo in channels) |
|||
{ |
|||
this.WriteChannelInfo(stream, channelInfo); |
|||
} |
|||
this.WriteSingle(stream, greenBuffer[x]); |
|||
} |
|||
|
|||
// Last byte should be zero.
|
|||
stream.WriteByte(0); |
|||
for (int x = 0; x < width; x++) |
|||
{ |
|||
this.WriteSingle(stream, redBuffer[x]); |
|||
} |
|||
} |
|||
|
|||
private void WriteCompression(Stream stream, ExrCompressionType compression) |
|||
private void WriteHalfSingleRow(Stream stream, int width, Span<float> blueBuffer, Span<float> greenBuffer, Span<float> redBuffer) |
|||
{ |
|||
for (int x = 0; x < width; x++) |
|||
{ |
|||
this.WriteAttributeInformation(stream, ExrConstants.AttributeNames.Compression, ExrConstants.AttibuteTypes.Compression, 1); |
|||
stream.WriteByte((byte)compression); |
|||
this.WriteHalfSingle(stream, blueBuffer[x]); |
|||
} |
|||
|
|||
private void WritePixelAspectRatio(Stream stream, float aspectRatio) |
|||
for (int x = 0; x < width; x++) |
|||
{ |
|||
this.WriteAttributeInformation(stream, ExrConstants.AttributeNames.PixelAspectRatio, ExrConstants.AttibuteTypes.Float, 4); |
|||
this.WriteSingle(stream, aspectRatio); |
|||
this.WriteHalfSingle(stream, greenBuffer[x]); |
|||
} |
|||
|
|||
private void WriteLineOrder(Stream stream, ExrLineOrder lineOrder) |
|||
for (int x = 0; x < width; x++) |
|||
{ |
|||
this.WriteAttributeInformation(stream, ExrConstants.AttributeNames.LineOrder, ExrConstants.AttibuteTypes.LineOrder, 1); |
|||
stream.WriteByte((byte)lineOrder); |
|||
this.WriteHalfSingle(stream, redBuffer[x]); |
|||
} |
|||
} |
|||
|
|||
private void WriteScreenWindowCenter(Stream stream, PointF screenWindowCenter) |
|||
private void WriteUnsignedIntRow(Stream stream, int width, Span<uint> blueBuffer, Span<uint> greenBuffer, Span<uint> redBuffer) |
|||
{ |
|||
for (int x = 0; x < width; x++) |
|||
{ |
|||
this.WriteAttributeInformation(stream, ExrConstants.AttributeNames.ScreenWindowCenter, ExrConstants.AttibuteTypes.TwoFloat, 8); |
|||
this.WriteSingle(stream, screenWindowCenter.X); |
|||
this.WriteSingle(stream, screenWindowCenter.Y); |
|||
this.WriteUnsignedInt(stream, blueBuffer[x]); |
|||
} |
|||
|
|||
private void WriteScreenWindowWidth(Stream stream, float screenWindowWidth) |
|||
for (int x = 0; x < width; x++) |
|||
{ |
|||
this.WriteAttributeInformation(stream, ExrConstants.AttributeNames.ScreenWindowWidth, ExrConstants.AttibuteTypes.Float, 4); |
|||
this.WriteSingle(stream, screenWindowWidth); |
|||
this.WriteUnsignedInt(stream, greenBuffer[x]); |
|||
} |
|||
|
|||
private void WriteDataWindow(Stream stream, ExrBox2i dataWindow) |
|||
for (int x = 0; x < width; x++) |
|||
{ |
|||
this.WriteAttributeInformation(stream, ExrConstants.AttributeNames.DataWindow, ExrConstants.AttibuteTypes.BoxInt, 16); |
|||
this.WriteBoxInteger(stream, dataWindow); |
|||
this.WriteUnsignedInt(stream, redBuffer[x]); |
|||
} |
|||
} |
|||
|
|||
private void WriteDisplayWindow(Stream stream, ExrBox2i displayWindow) |
|||
private void WriteRowOffsets(Stream stream, int height, uint rowSizeBytes) |
|||
{ |
|||
ulong startOfPixelData = (ulong)stream.Position + (8 * (ulong)height); |
|||
ulong offset = startOfPixelData; |
|||
for (int i = 0; i < height; i++) |
|||
{ |
|||
this.WriteAttributeInformation(stream, ExrConstants.AttributeNames.DisplayWindow, ExrConstants.AttibuteTypes.BoxInt, 16); |
|||
this.WriteBoxInteger(stream, displayWindow); |
|||
BinaryPrimitives.WriteUInt64LittleEndian(this.buffer, offset); |
|||
stream.Write(this.buffer); |
|||
offset += 4 + 4 + rowSizeBytes; |
|||
} |
|||
} |
|||
|
|||
private void WriteAttributeInformation(Stream stream, string name, string type, int size) |
|||
private void WriteChannels(Stream stream, IList<ExrChannelInfo> channels) |
|||
{ |
|||
int attributeSize = 0; |
|||
foreach (ExrChannelInfo channelInfo in channels) |
|||
{ |
|||
// Write attribute name.
|
|||
this.WriteString(stream, name); |
|||
attributeSize += channelInfo.ChannelName.Length + 1; |
|||
attributeSize += 16; |
|||
} |
|||
|
|||
// Write attribute type.
|
|||
this.WriteString(stream, type); |
|||
// Last zero byte.
|
|||
attributeSize++; |
|||
this.WriteAttributeInformation(stream, ExrConstants.AttributeNames.Channels, ExrConstants.AttibuteTypes.ChannelList, attributeSize); |
|||
|
|||
// Write attribute size.
|
|||
BinaryPrimitives.WriteUInt32LittleEndian(this.buffer, (uint)size); |
|||
stream.Write(this.buffer.AsSpan(0, 4)); |
|||
foreach (ExrChannelInfo channelInfo in channels) |
|||
{ |
|||
this.WriteChannelInfo(stream, channelInfo); |
|||
} |
|||
|
|||
private void WriteChannelInfo(Stream stream, ExrChannelInfo channelInfo) |
|||
{ |
|||
this.WriteString(stream, channelInfo.ChannelName); |
|||
// Last byte should be zero.
|
|||
stream.WriteByte(0); |
|||
} |
|||
|
|||
BinaryPrimitives.WriteInt32LittleEndian(this.buffer, (int)channelInfo.PixelType); |
|||
stream.Write(this.buffer.AsSpan(0, 4)); |
|||
private void WriteCompression(Stream stream, ExrCompressionType compression) |
|||
{ |
|||
this.WriteAttributeInformation(stream, ExrConstants.AttributeNames.Compression, ExrConstants.AttibuteTypes.Compression, 1); |
|||
stream.WriteByte((byte)compression); |
|||
} |
|||
|
|||
stream.WriteByte(channelInfo.PLinear); |
|||
private void WritePixelAspectRatio(Stream stream, float aspectRatio) |
|||
{ |
|||
this.WriteAttributeInformation(stream, ExrConstants.AttributeNames.PixelAspectRatio, ExrConstants.AttibuteTypes.Float, 4); |
|||
this.WriteSingle(stream, aspectRatio); |
|||
} |
|||
|
|||
// Next 3 bytes are reserved and will set to zero.
|
|||
stream.WriteByte(0); |
|||
stream.WriteByte(0); |
|||
stream.WriteByte(0); |
|||
private void WriteLineOrder(Stream stream, ExrLineOrder lineOrder) |
|||
{ |
|||
this.WriteAttributeInformation(stream, ExrConstants.AttributeNames.LineOrder, ExrConstants.AttibuteTypes.LineOrder, 1); |
|||
stream.WriteByte((byte)lineOrder); |
|||
} |
|||
|
|||
BinaryPrimitives.WriteInt32LittleEndian(this.buffer, channelInfo.XSampling); |
|||
stream.Write(this.buffer.AsSpan(0, 4)); |
|||
private void WriteScreenWindowCenter(Stream stream, PointF screenWindowCenter) |
|||
{ |
|||
this.WriteAttributeInformation(stream, ExrConstants.AttributeNames.ScreenWindowCenter, ExrConstants.AttibuteTypes.TwoFloat, 8); |
|||
this.WriteSingle(stream, screenWindowCenter.X); |
|||
this.WriteSingle(stream, screenWindowCenter.Y); |
|||
} |
|||
|
|||
BinaryPrimitives.WriteInt32LittleEndian(this.buffer, channelInfo.YSampling); |
|||
stream.Write(this.buffer.AsSpan(0, 4)); |
|||
} |
|||
private void WriteScreenWindowWidth(Stream stream, float screenWindowWidth) |
|||
{ |
|||
this.WriteAttributeInformation(stream, ExrConstants.AttributeNames.ScreenWindowWidth, ExrConstants.AttibuteTypes.Float, 4); |
|||
this.WriteSingle(stream, screenWindowWidth); |
|||
} |
|||
|
|||
private void WriteString(Stream stream, string str) |
|||
{ |
|||
foreach (char c in str) |
|||
{ |
|||
stream.WriteByte((byte)c); |
|||
} |
|||
private void WriteDataWindow(Stream stream, ExrBox2i dataWindow) |
|||
{ |
|||
this.WriteAttributeInformation(stream, ExrConstants.AttributeNames.DataWindow, ExrConstants.AttibuteTypes.BoxInt, 16); |
|||
this.WriteBoxInteger(stream, dataWindow); |
|||
} |
|||
|
|||
// Write termination byte.
|
|||
stream.WriteByte(0); |
|||
} |
|||
private void WriteDisplayWindow(Stream stream, ExrBox2i displayWindow) |
|||
{ |
|||
this.WriteAttributeInformation(stream, ExrConstants.AttributeNames.DisplayWindow, ExrConstants.AttibuteTypes.BoxInt, 16); |
|||
this.WriteBoxInteger(stream, displayWindow); |
|||
} |
|||
|
|||
private void WriteBoxInteger(Stream stream, ExrBox2i box) |
|||
{ |
|||
BinaryPrimitives.WriteInt32LittleEndian(this.buffer, box.XMin); |
|||
stream.Write(this.buffer.AsSpan(0, 4)); |
|||
private void WriteAttributeInformation(Stream stream, string name, string type, int size) |
|||
{ |
|||
// Write attribute name.
|
|||
WriteString(stream, name); |
|||
|
|||
BinaryPrimitives.WriteInt32LittleEndian(this.buffer, box.YMin); |
|||
stream.Write(this.buffer.AsSpan(0, 4)); |
|||
// Write attribute type.
|
|||
WriteString(stream, type); |
|||
|
|||
BinaryPrimitives.WriteInt32LittleEndian(this.buffer, box.XMax); |
|||
stream.Write(this.buffer.AsSpan(0, 4)); |
|||
// Write attribute size.
|
|||
BinaryPrimitives.WriteUInt32LittleEndian(this.buffer, (uint)size); |
|||
stream.Write(this.buffer.AsSpan(0, 4)); |
|||
} |
|||
|
|||
BinaryPrimitives.WriteInt32LittleEndian(this.buffer, box.YMax); |
|||
stream.Write(this.buffer.AsSpan(0, 4)); |
|||
} |
|||
private void WriteChannelInfo(Stream stream, ExrChannelInfo channelInfo) |
|||
{ |
|||
WriteString(stream, channelInfo.ChannelName); |
|||
|
|||
[MethodImpl(InliningOptions.ShortMethod)] |
|||
private unsafe void WriteSingle(Stream stream, float value) |
|||
{ |
|||
BinaryPrimitives.WriteInt32LittleEndian(this.buffer, *(int*)&value); |
|||
stream.Write(this.buffer.AsSpan(0, 4)); |
|||
} |
|||
BinaryPrimitives.WriteInt32LittleEndian(this.buffer, (int)channelInfo.PixelType); |
|||
stream.Write(this.buffer.AsSpan(0, 4)); |
|||
|
|||
[MethodImpl(InliningOptions.ShortMethod)] |
|||
private void WriteHalfSingle(Stream stream, float value) |
|||
{ |
|||
ushort valueAsShort = HalfTypeHelper.Pack(value); |
|||
BinaryPrimitives.WriteUInt16LittleEndian(this.buffer, valueAsShort); |
|||
stream.Write(this.buffer.AsSpan(0, 2)); |
|||
} |
|||
stream.WriteByte(channelInfo.PLinear); |
|||
|
|||
// Next 3 bytes are reserved and will set to zero.
|
|||
stream.WriteByte(0); |
|||
stream.WriteByte(0); |
|||
stream.WriteByte(0); |
|||
|
|||
BinaryPrimitives.WriteInt32LittleEndian(this.buffer, channelInfo.XSampling); |
|||
stream.Write(this.buffer.AsSpan(0, 4)); |
|||
|
|||
[MethodImpl(InliningOptions.ShortMethod)] |
|||
private void WriteUnsignedInt(Stream stream, uint value) |
|||
BinaryPrimitives.WriteInt32LittleEndian(this.buffer, channelInfo.YSampling); |
|||
stream.Write(this.buffer.AsSpan(0, 4)); |
|||
} |
|||
|
|||
private static void WriteString(Stream stream, string str) |
|||
{ |
|||
foreach (char c in str) |
|||
{ |
|||
BinaryPrimitives.WriteUInt32LittleEndian(this.buffer, value); |
|||
stream.Write(this.buffer.AsSpan(0, 4)); |
|||
stream.WriteByte((byte)c); |
|||
} |
|||
|
|||
// Write termination byte.
|
|||
stream.WriteByte(0); |
|||
} |
|||
|
|||
private void WriteBoxInteger(Stream stream, ExrBox2i box) |
|||
{ |
|||
BinaryPrimitives.WriteInt32LittleEndian(this.buffer, box.XMin); |
|||
stream.Write(this.buffer.AsSpan(0, 4)); |
|||
|
|||
BinaryPrimitives.WriteInt32LittleEndian(this.buffer, box.YMin); |
|||
stream.Write(this.buffer.AsSpan(0, 4)); |
|||
|
|||
BinaryPrimitives.WriteInt32LittleEndian(this.buffer, box.XMax); |
|||
stream.Write(this.buffer.AsSpan(0, 4)); |
|||
|
|||
BinaryPrimitives.WriteInt32LittleEndian(this.buffer, box.YMax); |
|||
stream.Write(this.buffer.AsSpan(0, 4)); |
|||
} |
|||
|
|||
[MethodImpl(InliningOptions.ShortMethod)] |
|||
private unsafe void WriteSingle(Stream stream, float value) |
|||
{ |
|||
BinaryPrimitives.WriteInt32LittleEndian(this.buffer, *(int*)&value); |
|||
stream.Write(this.buffer.AsSpan(0, 4)); |
|||
} |
|||
|
|||
[MethodImpl(InliningOptions.ShortMethod)] |
|||
private void WriteHalfSingle(Stream stream, float value) |
|||
{ |
|||
ushort valueAsShort = HalfTypeHelper.Pack(value); |
|||
BinaryPrimitives.WriteUInt16LittleEndian(this.buffer, valueAsShort); |
|||
stream.Write(this.buffer.AsSpan(0, 2)); |
|||
} |
|||
|
|||
[MethodImpl(InliningOptions.ShortMethod)] |
|||
private void WriteUnsignedInt(Stream stream, uint value) |
|||
{ |
|||
BinaryPrimitives.WriteUInt32LittleEndian(this.buffer, value); |
|||
stream.Write(this.buffer.AsSpan(0, 4)); |
|||
} |
|||
} |
|||
|
|||
@ -1,38 +1,34 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// Licensed under the Six Labors Split License.
|
|||
|
|||
using System.Collections.Generic; |
|||
using SixLabors.ImageSharp.Formats.Bmp; |
|||
namespace SixLabors.ImageSharp.Formats.OpenExr; |
|||
|
|||
namespace SixLabors.ImageSharp.Formats.OpenExr |
|||
/// <summary>
|
|||
/// Registers the image encoders, decoders and mime type detectors for the OpenExr format.
|
|||
/// </summary>
|
|||
public sealed class ExrFormat : IImageFormat<ExrMetadata> |
|||
{ |
|||
/// <summary>
|
|||
/// Registers the image encoders, decoders and mime type detectors for the OpenExr format.
|
|||
/// </summary>
|
|||
public sealed class ExrFormat : IImageFormat<ExrMetadata> |
|||
private ExrFormat() |
|||
{ |
|||
private ExrFormat() |
|||
{ |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets the current instance.
|
|||
/// </summary>
|
|||
public static ExrFormat Instance { get; } = new(); |
|||
/// <summary>
|
|||
/// Gets the current instance.
|
|||
/// </summary>
|
|||
public static ExrFormat Instance { get; } = new(); |
|||
|
|||
/// <inheritdoc/>
|
|||
public string Name => "EXR"; |
|||
/// <inheritdoc/>
|
|||
public string Name => "EXR"; |
|||
|
|||
/// <inheritdoc/>
|
|||
public string DefaultMimeType => "image/x-exr"; |
|||
/// <inheritdoc/>
|
|||
public string DefaultMimeType => "image/x-exr"; |
|||
|
|||
/// <inheritdoc/>
|
|||
public IEnumerable<string> MimeTypes => ExrConstants.MimeTypes; |
|||
/// <inheritdoc/>
|
|||
public IEnumerable<string> MimeTypes => ExrConstants.MimeTypes; |
|||
|
|||
/// <inheritdoc/>
|
|||
public IEnumerable<string> FileExtensions => ExrConstants.FileExtensions; |
|||
/// <inheritdoc/>
|
|||
public IEnumerable<string> FileExtensions => ExrConstants.FileExtensions; |
|||
|
|||
/// <inheritdoc/>
|
|||
public ExrMetadata CreateDefaultFormatMetadata() => new(); |
|||
} |
|||
/// <inheritdoc/>
|
|||
public ExrMetadata CreateDefaultFormatMetadata() => new(); |
|||
} |
|||
|
|||
@ -1,78 +1,76 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// Licensed under the Six Labors Split License.
|
|||
|
|||
using System.Collections.Generic; |
|||
using SixLabors.ImageSharp.Formats.OpenExr.Compression; |
|||
|
|||
namespace SixLabors.ImageSharp.Formats.OpenExr |
|||
namespace SixLabors.ImageSharp.Formats.OpenExr; |
|||
|
|||
internal class ExrHeaderAttributes |
|||
{ |
|||
internal class ExrHeaderAttributes |
|||
{ |
|||
public IList<ExrChannelInfo> Channels { get; set; } |
|||
public IList<ExrChannelInfo> Channels { get; set; } |
|||
|
|||
public ExrCompressionType? Compression { get; set; } |
|||
public ExrCompressionType? Compression { get; set; } |
|||
|
|||
public ExrBox2i? DataWindow { get; set; } |
|||
public ExrBox2i? DataWindow { get; set; } |
|||
|
|||
public ExrBox2i? DisplayWindow { get; set; } |
|||
public ExrBox2i? DisplayWindow { get; set; } |
|||
|
|||
public ExrLineOrder? LineOrder { get; set; } |
|||
public ExrLineOrder? LineOrder { get; set; } |
|||
|
|||
public float? AspectRatio { get; set; } |
|||
public float? AspectRatio { get; set; } |
|||
|
|||
public float? ScreenWindowWidth { get; set; } |
|||
public float? ScreenWindowWidth { get; set; } |
|||
|
|||
public PointF? ScreenWindowCenter { get; set; } |
|||
public PointF? ScreenWindowCenter { get; set; } |
|||
|
|||
public uint? TileXSize { get; set; } |
|||
public uint? TileXSize { get; set; } |
|||
|
|||
public uint? TileYSize { get; set; } |
|||
public uint? TileYSize { get; set; } |
|||
|
|||
public int? ChunkCount { get; set; } |
|||
public int? ChunkCount { get; set; } |
|||
|
|||
public bool IsValid() |
|||
public bool IsValid() |
|||
{ |
|||
if (!this.Compression.HasValue) |
|||
{ |
|||
if (!this.Compression.HasValue) |
|||
{ |
|||
return false; |
|||
} |
|||
|
|||
if (!this.DataWindow.HasValue) |
|||
{ |
|||
return false; |
|||
} |
|||
|
|||
if (!this.DisplayWindow.HasValue) |
|||
{ |
|||
return false; |
|||
} |
|||
|
|||
if (!this.LineOrder.HasValue) |
|||
{ |
|||
return false; |
|||
} |
|||
|
|||
if (!this.AspectRatio.HasValue) |
|||
{ |
|||
return false; |
|||
} |
|||
|
|||
if (!this.ScreenWindowWidth.HasValue) |
|||
{ |
|||
return false; |
|||
} |
|||
|
|||
if (!this.ScreenWindowCenter.HasValue) |
|||
{ |
|||
return false; |
|||
} |
|||
|
|||
if (this.Channels is null) |
|||
{ |
|||
return false; |
|||
} |
|||
|
|||
return true; |
|||
return false; |
|||
} |
|||
|
|||
if (!this.DataWindow.HasValue) |
|||
{ |
|||
return false; |
|||
} |
|||
|
|||
if (!this.DisplayWindow.HasValue) |
|||
{ |
|||
return false; |
|||
} |
|||
|
|||
if (!this.LineOrder.HasValue) |
|||
{ |
|||
return false; |
|||
} |
|||
|
|||
if (!this.AspectRatio.HasValue) |
|||
{ |
|||
return false; |
|||
} |
|||
|
|||
if (!this.ScreenWindowWidth.HasValue) |
|||
{ |
|||
return false; |
|||
} |
|||
|
|||
if (!this.ScreenWindowCenter.HasValue) |
|||
{ |
|||
return false; |
|||
} |
|||
|
|||
if (this.Channels is null) |
|||
{ |
|||
return false; |
|||
} |
|||
|
|||
return true; |
|||
} |
|||
} |
|||
|
|||
@ -1,16 +1,15 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// Licensed under the Six Labors Split License.
|
|||
|
|||
namespace SixLabors.ImageSharp.Formats.OpenExr |
|||
namespace SixLabors.ImageSharp.Formats.OpenExr; |
|||
|
|||
internal enum ExrImageDataType |
|||
{ |
|||
internal enum ExrImageDataType |
|||
{ |
|||
Unknown = 0, |
|||
Unknown = 0, |
|||
|
|||
Rgb = 1, |
|||
Rgb = 1, |
|||
|
|||
Rgba = 2, |
|||
Rgba = 2, |
|||
|
|||
Gray = 3, |
|||
} |
|||
Gray = 3, |
|||
} |
|||
|
|||
@ -1,31 +1,29 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// Licensed under the Six Labors Split License.
|
|||
|
|||
using System; |
|||
using System.Buffers.Binary; |
|||
|
|||
namespace SixLabors.ImageSharp.Formats.OpenExr |
|||
namespace SixLabors.ImageSharp.Formats.OpenExr; |
|||
|
|||
/// <summary>
|
|||
/// Detects OpenExr file headers.
|
|||
/// </summary>
|
|||
public sealed class ExrImageFormatDetector : IImageFormatDetector |
|||
{ |
|||
/// <summary>
|
|||
/// Detects OpenExr file headers.
|
|||
/// </summary>
|
|||
public sealed class ExrImageFormatDetector : IImageFormatDetector |
|||
{ |
|||
/// <inheritdoc/>
|
|||
public int HeaderSize => 4; |
|||
/// <inheritdoc/>
|
|||
public int HeaderSize => 4; |
|||
|
|||
/// <inheritdoc/>
|
|||
public IImageFormat DetectFormat(ReadOnlySpan<byte> header) => this.IsSupportedFileFormat(header) ? ExrFormat.Instance : null; |
|||
/// <inheritdoc/>
|
|||
public IImageFormat DetectFormat(ReadOnlySpan<byte> header) => this.IsSupportedFileFormat(header) ? ExrFormat.Instance : null; |
|||
|
|||
private bool IsSupportedFileFormat(ReadOnlySpan<byte> header) |
|||
private bool IsSupportedFileFormat(ReadOnlySpan<byte> header) |
|||
{ |
|||
if (header.Length >= this.HeaderSize) |
|||
{ |
|||
if (header.Length >= this.HeaderSize) |
|||
{ |
|||
int fileTypeMarker = BinaryPrimitives.ReadInt32LittleEndian(header); |
|||
return fileTypeMarker == ExrConstants.MagickBytes; |
|||
} |
|||
|
|||
return false; |
|||
int fileTypeMarker = BinaryPrimitives.ReadInt32LittleEndian(header); |
|||
return fileTypeMarker == ExrConstants.MagickBytes; |
|||
} |
|||
|
|||
return false; |
|||
} |
|||
} |
|||
|
|||
@ -1,12 +1,11 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// Licensed under the Six Labors Split License.
|
|||
|
|||
namespace SixLabors.ImageSharp.Formats.OpenExr |
|||
namespace SixLabors.ImageSharp.Formats.OpenExr; |
|||
|
|||
internal enum ExrImageType |
|||
{ |
|||
internal enum ExrImageType |
|||
{ |
|||
ScanLine = 0, |
|||
ScanLine = 0, |
|||
|
|||
Tiled = 1 |
|||
} |
|||
Tiled = 1 |
|||
} |
|||
|
|||
@ -1,14 +1,13 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// Licensed under the Six Labors Split License.
|
|||
|
|||
namespace SixLabors.ImageSharp.Formats.OpenExr |
|||
namespace SixLabors.ImageSharp.Formats.OpenExr; |
|||
|
|||
internal enum ExrLineOrder : byte |
|||
{ |
|||
internal enum ExrLineOrder : byte |
|||
{ |
|||
IncreasingY = 0, |
|||
IncreasingY = 0, |
|||
|
|||
DecreasingY = 1, |
|||
DecreasingY = 1, |
|||
|
|||
RandomY = 2 |
|||
} |
|||
RandomY = 2 |
|||
} |
|||
|
|||
@ -1,32 +1,31 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// Licensed under the Six Labors Split License.
|
|||
|
|||
namespace SixLabors.ImageSharp.Formats.OpenExr |
|||
namespace SixLabors.ImageSharp.Formats.OpenExr; |
|||
|
|||
/// <summary>
|
|||
/// Provides OpenExr specific metadata information for the image.
|
|||
/// </summary>
|
|||
public class ExrMetadata : IDeepCloneable |
|||
{ |
|||
/// <summary>
|
|||
/// Provides OpenExr specific metadata information for the image.
|
|||
/// Initializes a new instance of the <see cref="ExrMetadata"/> class.
|
|||
/// </summary>
|
|||
public class ExrMetadata : IDeepCloneable |
|||
public ExrMetadata() |
|||
{ |
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="ExrMetadata"/> class.
|
|||
/// </summary>
|
|||
public ExrMetadata() |
|||
{ |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="ExrMetadata"/> class.
|
|||
/// </summary>
|
|||
/// <param name="other">The metadata to create an instance from.</param>
|
|||
private ExrMetadata(ExrMetadata other) => this.PixelType = other.PixelType; |
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="ExrMetadata"/> class.
|
|||
/// </summary>
|
|||
/// <param name="other">The metadata to create an instance from.</param>
|
|||
private ExrMetadata(ExrMetadata other) => this.PixelType = other.PixelType; |
|||
|
|||
/// <summary>
|
|||
/// Gets or sets the pixel format.
|
|||
/// </summary>
|
|||
public ExrPixelType PixelType { get; set; } = ExrPixelType.Float; |
|||
/// <summary>
|
|||
/// Gets or sets the pixel format.
|
|||
/// </summary>
|
|||
public ExrPixelType PixelType { get; set; } = ExrPixelType.Float; |
|||
|
|||
/// <inheritdoc/>
|
|||
public IDeepCloneable DeepClone() => new ExrMetadata(this); |
|||
} |
|||
/// <inheritdoc/>
|
|||
public IDeepCloneable DeepClone() => new ExrMetadata(this); |
|||
} |
|||
|
|||
@ -1,26 +1,25 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// Licensed under the Six Labors Split License.
|
|||
|
|||
namespace SixLabors.ImageSharp.Formats.OpenExr |
|||
namespace SixLabors.ImageSharp.Formats.OpenExr; |
|||
|
|||
/// <summary>
|
|||
/// The different pixel formats for a OpenEXR image.
|
|||
/// </summary>
|
|||
public enum ExrPixelType |
|||
{ |
|||
/// <summary>
|
|||
/// The different pixel formats for a OpenEXR image.
|
|||
/// unsigned int (32 bit).
|
|||
/// </summary>
|
|||
public enum ExrPixelType |
|||
{ |
|||
/// <summary>
|
|||
/// unsigned int (32 bit).
|
|||
/// </summary>
|
|||
UnsignedInt = 0, |
|||
UnsignedInt = 0, |
|||
|
|||
/// <summary>
|
|||
/// half (16 bit floating point).
|
|||
/// </summary>
|
|||
Half = 1, |
|||
/// <summary>
|
|||
/// half (16 bit floating point).
|
|||
/// </summary>
|
|||
Half = 1, |
|||
|
|||
/// <summary>
|
|||
/// float (32 bit floating point).
|
|||
/// </summary>
|
|||
Float = 2 |
|||
} |
|||
/// <summary>
|
|||
/// float (32 bit floating point).
|
|||
/// </summary>
|
|||
Float = 2 |
|||
} |
|||
|
|||
@ -1,32 +1,22 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// Licensed under the Six Labors Split License.
|
|||
|
|||
using System; |
|||
using System.Runtime.CompilerServices; |
|||
namespace SixLabors.ImageSharp.Formats.OpenExr; |
|||
|
|||
namespace SixLabors.ImageSharp.Formats.OpenExr |
|||
/// <summary>
|
|||
/// Cold path optimizations for throwing exr format based exceptions.
|
|||
/// </summary>
|
|||
internal static class ExrThrowHelper |
|||
{ |
|||
/// <summary>
|
|||
/// Cold path optimizations for throwing exr format based exceptions.
|
|||
/// </summary>
|
|||
internal static class ExrThrowHelper |
|||
{ |
|||
[MethodImpl(InliningOptions.ColdPath)] |
|||
public static Exception NotSupportedDecompressor(string compressionType) => throw new NotSupportedException($"Not supported decoder compression method: {compressionType}"); |
|||
public static Exception NotSupportedDecompressor(string compressionType) => throw new NotSupportedException($"Not supported decoder compression method: {compressionType}"); |
|||
|
|||
[MethodImpl(MethodImplOptions.NoInlining)] |
|||
public static void ThrowInvalidImageContentException(string errorMessage) => throw new InvalidImageContentException(errorMessage); |
|||
public static void ThrowInvalidImageContentException(string errorMessage) => throw new InvalidImageContentException(errorMessage); |
|||
|
|||
[MethodImpl(InliningOptions.ColdPath)] |
|||
public static void ThrowNotSupportedVersion() => throw new NotSupportedException("Unsupported EXR version"); |
|||
public static void ThrowNotSupportedVersion() => throw new NotSupportedException("Unsupported EXR version"); |
|||
|
|||
[MethodImpl(InliningOptions.ColdPath)] |
|||
public static void ThrowNotSupported(string msg) => throw new NotSupportedException(msg); |
|||
public static void ThrowNotSupported(string msg) => throw new NotSupportedException(msg); |
|||
|
|||
[MethodImpl(InliningOptions.ColdPath)] |
|||
public static void ThrowInvalidImageHeader() => throw new InvalidImageContentException("Invalid EXR image header"); |
|||
public static void ThrowInvalidImageHeader() => throw new InvalidImageContentException("Invalid EXR image header"); |
|||
|
|||
[MethodImpl(InliningOptions.ColdPath)] |
|||
public static void ThrowInvalidImageHeader(string msg) => throw new InvalidImageContentException(msg); |
|||
} |
|||
public static void ThrowInvalidImageHeader(string msg) => throw new InvalidImageContentException(msg); |
|||
} |
|||
|
|||
@ -1,12 +0,0 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
namespace SixLabors.ImageSharp.Formats.OpenExr |
|||
{ |
|||
/// <summary>
|
|||
/// Image decoder options for decoding OpenExr streams.
|
|||
/// </summary>
|
|||
internal interface IExrDecoderOptions |
|||
{ |
|||
} |
|||
} |
|||
@ -1,16 +1,15 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// Licensed under the Six Labors Split License.
|
|||
|
|||
namespace SixLabors.ImageSharp.Formats.OpenExr |
|||
namespace SixLabors.ImageSharp.Formats.OpenExr; |
|||
|
|||
/// <summary>
|
|||
/// Configuration options for use during OpenExr encoding.
|
|||
/// </summary>
|
|||
internal interface IExrEncoderOptions |
|||
{ |
|||
/// <summary>
|
|||
/// Configuration options for use during OpenExr encoding.
|
|||
/// Gets the pixel type of the image.
|
|||
/// </summary>
|
|||
internal interface IExrEncoderOptions |
|||
{ |
|||
/// <summary>
|
|||
/// Gets the pixel type of the image.
|
|||
/// </summary>
|
|||
ExrPixelType? PixelType { get; } |
|||
} |
|||
ExrPixelType? PixelType { get; } |
|||
} |
|||
|
|||
@ -1,21 +1,20 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// Licensed under the Six Labors Split License.
|
|||
|
|||
using SixLabors.ImageSharp.Formats.OpenExr; |
|||
using SixLabors.ImageSharp.Metadata; |
|||
|
|||
namespace SixLabors.ImageSharp |
|||
namespace SixLabors.ImageSharp; |
|||
|
|||
/// <summary>
|
|||
/// Extension methods for the <see cref="ImageMetadata"/> type.
|
|||
/// </summary>
|
|||
public static partial class MetadataExtensions |
|||
{ |
|||
/// <summary>
|
|||
/// Extension methods for the <see cref="ImageMetadata"/> type.
|
|||
/// Gets the open exr format specific metadata for the image.
|
|||
/// </summary>
|
|||
public static partial class MetadataExtensions |
|||
{ |
|||
/// <summary>
|
|||
/// Gets the open exr format specific metadata for the image.
|
|||
/// </summary>
|
|||
/// <param name="metadata">The metadata this method extends.</param>
|
|||
/// <returns>The <see cref="ExrMetadata"/>.</returns>
|
|||
public static ExrMetadata GetExrMetadata(this ImageMetadata metadata) => metadata.GetFormatMetadata(ExrFormat.Instance); |
|||
} |
|||
/// <param name="metadata">The metadata this method extends.</param>
|
|||
/// <returns>The <see cref="ExrMetadata"/>.</returns>
|
|||
public static ExrMetadata GetExrMetadata(this ImageMetadata metadata) => metadata.GetFormatMetadata(ExrFormat.Instance); |
|||
} |
|||
|
|||
@ -1,175 +1,173 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// Licensed under the Six Labors Split License.
|
|||
|
|||
using System; |
|||
using System.Numerics; |
|||
using System.Runtime.CompilerServices; |
|||
using System.Runtime.InteropServices; |
|||
|
|||
namespace SixLabors.ImageSharp.PixelFormats |
|||
namespace SixLabors.ImageSharp.PixelFormats; |
|||
|
|||
/// <summary>
|
|||
/// Pixel type containing three 32-bit unsigned normalized values ranging from 0 to 4294967295.
|
|||
/// The color components are stored in red, green, blue.
|
|||
/// <para>
|
|||
/// Ranges from [0, 0, 0] to [1, 1, 1] in vector form.
|
|||
/// </para>
|
|||
/// </summary>
|
|||
[StructLayout(LayoutKind.Sequential)] |
|||
public partial struct Rgb96 : IPixel<Rgb96> |
|||
{ |
|||
private const float InvMax = 1.0f / uint.MaxValue; |
|||
|
|||
private const double Max = uint.MaxValue; |
|||
|
|||
/// <summary>
|
|||
/// Gets the red component.
|
|||
/// </summary>
|
|||
public uint R; |
|||
|
|||
/// <summary>
|
|||
/// Gets the green component.
|
|||
/// </summary>
|
|||
public uint G; |
|||
|
|||
/// <summary>
|
|||
/// Gets the blue component.
|
|||
/// </summary>
|
|||
public uint B; |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="Rgb96"/> struct.
|
|||
/// </summary>
|
|||
/// <param name="r">The red component.</param>
|
|||
/// <param name="g">The green component.</param>
|
|||
/// <param name="b">The blue component.</param>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public Rgb96(uint r, uint g, uint b) |
|||
{ |
|||
this.R = r; |
|||
this.G = g; |
|||
this.B = b; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Compares two <see cref="Rgb96"/> objects for equality.
|
|||
/// </summary>
|
|||
/// <param name="left">The <see cref="Rgb96"/> on the left side of the operand.</param>
|
|||
/// <returns>
|
|||
/// True if the <paramref name="left"/> parameter is equal to the <paramref name="right"/> parameter; otherwise, false.
|
|||
/// </returns>
|
|||
/// <param name="right">The <see cref="Rgb96"/> on the right side of the operand.</param>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static bool operator ==(Rgb96 left, Rgb96 right) => left.Equals(right); |
|||
|
|||
/// <summary>
|
|||
/// Pixel type containing three 32-bit unsigned normalized values ranging from 0 to 4294967295.
|
|||
/// The color components are stored in red, green, blue.
|
|||
/// <para>
|
|||
/// Ranges from [0, 0, 0] to [1, 1, 1] in vector form.
|
|||
/// </para>
|
|||
/// Compares two <see cref="Rgb96"/> objects for equality.
|
|||
/// </summary>
|
|||
[StructLayout(LayoutKind.Sequential)] |
|||
public partial struct Rgb96 : IPixel<Rgb96> |
|||
/// <param name="left">The <see cref="Rgb96"/> on the left side of the operand.</param>
|
|||
/// <param name="right">The <see cref="Rgb96"/> on the right side of the operand.</param>
|
|||
/// <returns>
|
|||
/// True if the <paramref name="left"/> parameter is not equal to the <paramref name="right"/> parameter; otherwise, false.
|
|||
/// </returns>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static bool operator !=(Rgb96 left, Rgb96 right) => !left.Equals(right); |
|||
|
|||
/// <inheritdoc />
|
|||
public PixelOperations<Rgb96> CreatePixelOperations() => new(); |
|||
|
|||
/// <inheritdoc/>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public void FromScaledVector4(Vector4 vector) => this.FromVector4(vector); |
|||
|
|||
/// <inheritdoc/>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public Vector4 ToScaledVector4() => this.ToVector4(); |
|||
|
|||
/// <inheritdoc />
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public void FromVector4(Vector4 vector) |
|||
{ |
|||
private const float InvMax = 1.0f / uint.MaxValue; |
|||
|
|||
private const double Max = uint.MaxValue; |
|||
|
|||
/// <summary>
|
|||
/// Gets the red component.
|
|||
/// </summary>
|
|||
public uint R; |
|||
|
|||
/// <summary>
|
|||
/// Gets the green component.
|
|||
/// </summary>
|
|||
public uint G; |
|||
|
|||
/// <summary>
|
|||
/// Gets the blue component.
|
|||
/// </summary>
|
|||
public uint B; |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="Rgb96"/> struct.
|
|||
/// </summary>
|
|||
/// <param name="r">The red component.</param>
|
|||
/// <param name="g">The green component.</param>
|
|||
/// <param name="b">The blue component.</param>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public Rgb96(uint r, uint g, uint b) |
|||
{ |
|||
this.R = r; |
|||
this.G = g; |
|||
this.B = b; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Compares two <see cref="Rgb96"/> objects for equality.
|
|||
/// </summary>
|
|||
/// <param name="left">The <see cref="Rgb96"/> on the left side of the operand.</param>
|
|||
/// <returns>
|
|||
/// True if the <paramref name="left"/> parameter is equal to the <paramref name="right"/> parameter; otherwise, false.
|
|||
/// </returns>
|
|||
/// <param name="right">The <see cref="Rgb96"/> on the right side of the operand.</param>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static bool operator ==(Rgb96 left, Rgb96 right) => left.Equals(right); |
|||
|
|||
/// <summary>
|
|||
/// Compares two <see cref="Rgb96"/> objects for equality.
|
|||
/// </summary>
|
|||
/// <param name="left">The <see cref="Rgb96"/> on the left side of the operand.</param>
|
|||
/// <param name="right">The <see cref="Rgb96"/> on the right side of the operand.</param>
|
|||
/// <returns>
|
|||
/// True if the <paramref name="left"/> parameter is not equal to the <paramref name="right"/> parameter; otherwise, false.
|
|||
/// </returns>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static bool operator !=(Rgb96 left, Rgb96 right) => !left.Equals(right); |
|||
|
|||
/// <inheritdoc />
|
|||
public PixelOperations<Rgb96> CreatePixelOperations() => new(); |
|||
|
|||
/// <inheritdoc/>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public void FromScaledVector4(Vector4 vector) => this.FromVector4(vector); |
|||
|
|||
/// <inheritdoc/>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public Vector4 ToScaledVector4() => this.ToVector4(); |
|||
|
|||
/// <inheritdoc />
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public void FromVector4(Vector4 vector) |
|||
{ |
|||
vector = Numerics.Clamp(vector, Vector4.Zero, Vector4.One); |
|||
this.R = (uint)(vector.X * Max); |
|||
this.G = (uint)(vector.Y * Max); |
|||
this.B = (uint)(vector.Z * Max); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public Vector4 ToVector4() => new( |
|||
this.R * InvMax, |
|||
this.G * InvMax, |
|||
this.B * InvMax, |
|||
1.0f); |
|||
|
|||
/// <inheritdoc />
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public void FromBgra5551(Bgra5551 source) => this.FromScaledVector4(source.ToScaledVector4()); |
|||
|
|||
/// <inheritdoc />
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public void FromArgb32(Argb32 source) => this.FromScaledVector4(source.ToScaledVector4()); |
|||
|
|||
/// <inheritdoc />
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public void FromBgr24(Bgr24 source) => this.FromScaledVector4(source.ToScaledVector4()); |
|||
|
|||
/// <inheritdoc />
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public void FromBgra32(Bgra32 source) => this.FromScaledVector4(source.ToScaledVector4()); |
|||
|
|||
/// <inheritdoc/>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public void FromL8(L8 source) => this.FromScaledVector4(source.ToScaledVector4()); |
|||
|
|||
/// <inheritdoc/>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public void FromL16(L16 source) => this.FromScaledVector4(source.ToScaledVector4()); |
|||
|
|||
/// <inheritdoc/>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public void FromLa16(La16 source) => this.FromScaledVector4(source.ToScaledVector4()); |
|||
|
|||
/// <inheritdoc/>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public void FromLa32(La32 source) => this.FromScaledVector4(source.ToScaledVector4()); |
|||
|
|||
/// <inheritdoc />
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public void FromRgb24(Rgb24 source) => this.FromScaledVector4(source.ToScaledVector4()); |
|||
|
|||
/// <inheritdoc />
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public void FromRgba32(Rgba32 source) => this.FromScaledVector4(source.ToScaledVector4()); |
|||
|
|||
/// <inheritdoc />
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public void FromAbgr32(Abgr32 source) => this.FromScaledVector4(source.ToScaledVector4()); |
|||
|
|||
/// <inheritdoc />
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public void ToRgba32(ref Rgba32 dest) => dest.FromScaledVector4(this.ToScaledVector4()); |
|||
|
|||
/// <inheritdoc/>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public void FromRgb48(Rgb48 source) => this.FromScaledVector4(source.ToScaledVector4()); |
|||
|
|||
/// <inheritdoc/>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public void FromRgba64(Rgba64 source) => this.FromScaledVector4(source.ToScaledVector4()); |
|||
|
|||
/// <inheritdoc />
|
|||
public override bool Equals(object obj) => obj is Rgb96 other && this.Equals(other); |
|||
|
|||
/// <inheritdoc />
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public override int GetHashCode() => HashCode.Combine(this.R, this.G, this.B); |
|||
|
|||
/// <inheritdoc />
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public bool Equals(Rgb96 other) => this.R.Equals(other.R) && this.G.Equals(other.G) && this.B.Equals(other.B); |
|||
|
|||
/// <inheritdoc />
|
|||
public override string ToString() => FormattableString.Invariant($"Rgb96({this.R}, {this.G}, {this.B})"); |
|||
vector = Numerics.Clamp(vector, Vector4.Zero, Vector4.One); |
|||
this.R = (uint)(vector.X * Max); |
|||
this.G = (uint)(vector.Y * Max); |
|||
this.B = (uint)(vector.Z * Max); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public Vector4 ToVector4() => new( |
|||
this.R * InvMax, |
|||
this.G * InvMax, |
|||
this.B * InvMax, |
|||
1.0f); |
|||
|
|||
/// <inheritdoc />
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public void FromBgra5551(Bgra5551 source) => this.FromScaledVector4(source.ToScaledVector4()); |
|||
|
|||
/// <inheritdoc />
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public void FromArgb32(Argb32 source) => this.FromScaledVector4(source.ToScaledVector4()); |
|||
|
|||
/// <inheritdoc />
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public void FromBgr24(Bgr24 source) => this.FromScaledVector4(source.ToScaledVector4()); |
|||
|
|||
/// <inheritdoc />
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public void FromBgra32(Bgra32 source) => this.FromScaledVector4(source.ToScaledVector4()); |
|||
|
|||
/// <inheritdoc/>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public void FromL8(L8 source) => this.FromScaledVector4(source.ToScaledVector4()); |
|||
|
|||
/// <inheritdoc/>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public void FromL16(L16 source) => this.FromScaledVector4(source.ToScaledVector4()); |
|||
|
|||
/// <inheritdoc/>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public void FromLa16(La16 source) => this.FromScaledVector4(source.ToScaledVector4()); |
|||
|
|||
/// <inheritdoc/>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public void FromLa32(La32 source) => this.FromScaledVector4(source.ToScaledVector4()); |
|||
|
|||
/// <inheritdoc />
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public void FromRgb24(Rgb24 source) => this.FromScaledVector4(source.ToScaledVector4()); |
|||
|
|||
/// <inheritdoc />
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public void FromRgba32(Rgba32 source) => this.FromScaledVector4(source.ToScaledVector4()); |
|||
|
|||
/// <inheritdoc />
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public void FromAbgr32(Abgr32 source) => this.FromScaledVector4(source.ToScaledVector4()); |
|||
|
|||
/// <inheritdoc />
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public void ToRgba32(ref Rgba32 dest) => dest.FromScaledVector4(this.ToScaledVector4()); |
|||
|
|||
/// <inheritdoc/>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public void FromRgb48(Rgb48 source) => this.FromScaledVector4(source.ToScaledVector4()); |
|||
|
|||
/// <inheritdoc/>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public void FromRgba64(Rgba64 source) => this.FromScaledVector4(source.ToScaledVector4()); |
|||
|
|||
/// <inheritdoc />
|
|||
public override bool Equals(object obj) => obj is Rgb96 other && this.Equals(other); |
|||
|
|||
/// <inheritdoc />
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public override int GetHashCode() => HashCode.Combine(this.R, this.G, this.B); |
|||
|
|||
/// <inheritdoc />
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public bool Equals(Rgb96 other) => this.R.Equals(other.R) && this.G.Equals(other.G) && this.B.Equals(other.B); |
|||
|
|||
/// <inheritdoc />
|
|||
public override string ToString() => FormattableString.Invariant($"Rgb96({this.R}, {this.G}, {this.B})"); |
|||
} |
|||
|
|||
@ -1,183 +1,181 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// Licensed under the Six Labors Split License.
|
|||
|
|||
using System; |
|||
using System.Numerics; |
|||
using System.Runtime.CompilerServices; |
|||
using System.Runtime.InteropServices; |
|||
|
|||
namespace SixLabors.ImageSharp.PixelFormats |
|||
namespace SixLabors.ImageSharp.PixelFormats; |
|||
|
|||
/// <summary>
|
|||
/// Pixel type containing four 32-bit unsigned normalized values ranging from 0 to 4294967295.
|
|||
/// The color components are stored in red, green, blue and alpha.
|
|||
/// <para>
|
|||
/// Ranges from [0, 0, 0, 0] to [1, 1, 1, 1] in vector form.
|
|||
/// </para>
|
|||
/// </summary>
|
|||
[StructLayout(LayoutKind.Sequential)] |
|||
public partial struct Rgba128 : IPixel<Rgba128> |
|||
{ |
|||
private const float InvMax = 1.0f / uint.MaxValue; |
|||
|
|||
private const double Max = uint.MaxValue; |
|||
|
|||
/// <summary>
|
|||
/// Gets the red component.
|
|||
/// </summary>
|
|||
public uint R; |
|||
|
|||
/// <summary>
|
|||
/// Gets the green component.
|
|||
/// </summary>
|
|||
public uint G; |
|||
|
|||
/// <summary>
|
|||
/// Gets the blue component.
|
|||
/// </summary>
|
|||
public uint B; |
|||
|
|||
/// <summary>
|
|||
/// Pixel type containing four 32-bit unsigned normalized values ranging from 0 to 4294967295.
|
|||
/// The color components are stored in red, green, blue and alpha.
|
|||
/// <para>
|
|||
/// Ranges from [0, 0, 0, 0] to [1, 1, 1, 1] in vector form.
|
|||
/// </para>
|
|||
/// Gets the alpha channel.
|
|||
/// </summary>
|
|||
[StructLayout(LayoutKind.Sequential)] |
|||
public partial struct Rgba128 : IPixel<Rgba128> |
|||
public uint A; |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="Rgba128"/> struct.
|
|||
/// </summary>
|
|||
/// <param name="r">The red component.</param>
|
|||
/// <param name="g">The green component.</param>
|
|||
/// <param name="b">The blue component.</param>
|
|||
/// <param name="a">The alpha component.</param>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public Rgba128(uint r, uint g, uint b, uint a) |
|||
{ |
|||
private const float InvMax = 1.0f / uint.MaxValue; |
|||
|
|||
private const double Max = uint.MaxValue; |
|||
|
|||
/// <summary>
|
|||
/// Gets the red component.
|
|||
/// </summary>
|
|||
public uint R; |
|||
|
|||
/// <summary>
|
|||
/// Gets the green component.
|
|||
/// </summary>
|
|||
public uint G; |
|||
|
|||
/// <summary>
|
|||
/// Gets the blue component.
|
|||
/// </summary>
|
|||
public uint B; |
|||
|
|||
/// <summary>
|
|||
/// Gets the alpha channel.
|
|||
/// </summary>
|
|||
public uint A; |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="Rgba128"/> struct.
|
|||
/// </summary>
|
|||
/// <param name="r">The red component.</param>
|
|||
/// <param name="g">The green component.</param>
|
|||
/// <param name="b">The blue component.</param>
|
|||
/// <param name="a">The alpha component.</param>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public Rgba128(uint r, uint g, uint b, uint a) |
|||
{ |
|||
this.R = r; |
|||
this.G = g; |
|||
this.B = b; |
|||
this.A = a; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Compares two <see cref="Rgba128"/> objects for equality.
|
|||
/// </summary>
|
|||
/// <param name="left">The <see cref="Rgba128"/> on the left side of the operand.</param>
|
|||
/// <returns>
|
|||
/// True if the <paramref name="left"/> parameter is equal to the <paramref name="right"/> parameter; otherwise, false.
|
|||
/// </returns>
|
|||
/// <param name="right">The <see cref="Rgba128"/> on the right side of the operand.</param>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static bool operator ==(Rgba128 left, Rgba128 right) => left.Equals(right); |
|||
|
|||
/// <summary>
|
|||
/// Compares two <see cref="Rgba128"/> objects for equality.
|
|||
/// </summary>
|
|||
/// <param name="left">The <see cref="Rgba128"/> on the left side of the operand.</param>
|
|||
/// <param name="right">The <see cref="Rgba128"/> on the right side of the operand.</param>
|
|||
/// <returns>
|
|||
/// True if the <paramref name="left"/> parameter is not equal to the <paramref name="right"/> parameter; otherwise, false.
|
|||
/// </returns>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static bool operator !=(Rgba128 left, Rgba128 right) => !left.Equals(right); |
|||
|
|||
/// <inheritdoc />
|
|||
public PixelOperations<Rgba128> CreatePixelOperations() => new(); |
|||
|
|||
/// <inheritdoc/>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public void FromScaledVector4(Vector4 vector) => this.FromVector4(vector); |
|||
|
|||
/// <inheritdoc/>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public Vector4 ToScaledVector4() => this.ToVector4(); |
|||
|
|||
/// <inheritdoc />
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public void FromVector4(Vector4 vector) |
|||
{ |
|||
vector = Numerics.Clamp(vector, Vector4.Zero, Vector4.One); |
|||
this.R = (uint)(vector.X * Max); |
|||
this.G = (uint)(vector.Y * Max); |
|||
this.B = (uint)(vector.Z * Max); |
|||
this.A = (uint)(vector.W * Max); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public Vector4 ToVector4() => new( |
|||
this.R * InvMax, |
|||
this.G * InvMax, |
|||
this.B * InvMax, |
|||
this.A * InvMax); |
|||
|
|||
/// <inheritdoc />
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public void FromBgra5551(Bgra5551 source) => this.FromScaledVector4(source.ToScaledVector4()); |
|||
|
|||
/// <inheritdoc />
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public void FromArgb32(Argb32 source) => this.FromScaledVector4(source.ToScaledVector4()); |
|||
|
|||
/// <inheritdoc />
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public void FromBgr24(Bgr24 source) => this.FromScaledVector4(source.ToScaledVector4()); |
|||
|
|||
/// <inheritdoc />
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public void FromBgra32(Bgra32 source) => this.FromScaledVector4(source.ToScaledVector4()); |
|||
|
|||
/// <inheritdoc/>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public void FromL8(L8 source) => this.FromScaledVector4(source.ToScaledVector4()); |
|||
|
|||
/// <inheritdoc/>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public void FromL16(L16 source) => this.FromScaledVector4(source.ToScaledVector4()); |
|||
|
|||
/// <inheritdoc/>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public void FromLa16(La16 source) => this.FromScaledVector4(source.ToScaledVector4()); |
|||
|
|||
/// <inheritdoc/>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public void FromLa32(La32 source) => this.FromScaledVector4(source.ToScaledVector4()); |
|||
|
|||
/// <inheritdoc />
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public void FromRgb24(Rgb24 source) => this.FromScaledVector4(source.ToScaledVector4()); |
|||
|
|||
/// <inheritdoc />
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public void FromRgba32(Rgba32 source) => this.FromScaledVector4(source.ToScaledVector4()); |
|||
|
|||
/// <inheritdoc />
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public void FromAbgr32(Abgr32 source) => this.FromScaledVector4(source.ToScaledVector4()); |
|||
|
|||
/// <inheritdoc />
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public void ToRgba32(ref Rgba32 dest) => dest.FromScaledVector4(this.ToScaledVector4()); |
|||
|
|||
/// <inheritdoc/>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public void FromRgb48(Rgb48 source) => this.FromScaledVector4(source.ToScaledVector4()); |
|||
|
|||
/// <inheritdoc/>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public void FromRgba64(Rgba64 source) => this.FromScaledVector4(source.ToScaledVector4()); |
|||
|
|||
/// <inheritdoc />
|
|||
public override bool Equals(object obj) => obj is Rgba128 other && this.Equals(other); |
|||
|
|||
/// <inheritdoc />
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public override int GetHashCode() => HashCode.Combine(this.R, this.G, this.B, this.A); |
|||
|
|||
/// <inheritdoc />
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public bool Equals(Rgba128 other) => this.R.Equals(other.R) && this.G.Equals(other.G) && this.B.Equals(other.B) && this.A.Equals(other.A); |
|||
|
|||
/// <inheritdoc />
|
|||
public override string ToString() => FormattableString.Invariant($"Rgba128({this.R}, {this.G}, {this.B}, {this.A})"); |
|||
this.R = r; |
|||
this.G = g; |
|||
this.B = b; |
|||
this.A = a; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Compares two <see cref="Rgba128"/> objects for equality.
|
|||
/// </summary>
|
|||
/// <param name="left">The <see cref="Rgba128"/> on the left side of the operand.</param>
|
|||
/// <returns>
|
|||
/// True if the <paramref name="left"/> parameter is equal to the <paramref name="right"/> parameter; otherwise, false.
|
|||
/// </returns>
|
|||
/// <param name="right">The <see cref="Rgba128"/> on the right side of the operand.</param>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static bool operator ==(Rgba128 left, Rgba128 right) => left.Equals(right); |
|||
|
|||
/// <summary>
|
|||
/// Compares two <see cref="Rgba128"/> objects for equality.
|
|||
/// </summary>
|
|||
/// <param name="left">The <see cref="Rgba128"/> on the left side of the operand.</param>
|
|||
/// <param name="right">The <see cref="Rgba128"/> on the right side of the operand.</param>
|
|||
/// <returns>
|
|||
/// True if the <paramref name="left"/> parameter is not equal to the <paramref name="right"/> parameter; otherwise, false.
|
|||
/// </returns>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static bool operator !=(Rgba128 left, Rgba128 right) => !left.Equals(right); |
|||
|
|||
/// <inheritdoc />
|
|||
public PixelOperations<Rgba128> CreatePixelOperations() => new(); |
|||
|
|||
/// <inheritdoc/>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public void FromScaledVector4(Vector4 vector) => this.FromVector4(vector); |
|||
|
|||
/// <inheritdoc/>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public Vector4 ToScaledVector4() => this.ToVector4(); |
|||
|
|||
/// <inheritdoc />
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public void FromVector4(Vector4 vector) |
|||
{ |
|||
vector = Numerics.Clamp(vector, Vector4.Zero, Vector4.One); |
|||
this.R = (uint)(vector.X * Max); |
|||
this.G = (uint)(vector.Y * Max); |
|||
this.B = (uint)(vector.Z * Max); |
|||
this.A = (uint)(vector.W * Max); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public Vector4 ToVector4() => new( |
|||
this.R * InvMax, |
|||
this.G * InvMax, |
|||
this.B * InvMax, |
|||
this.A * InvMax); |
|||
|
|||
/// <inheritdoc />
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public void FromBgra5551(Bgra5551 source) => this.FromScaledVector4(source.ToScaledVector4()); |
|||
|
|||
/// <inheritdoc />
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public void FromArgb32(Argb32 source) => this.FromScaledVector4(source.ToScaledVector4()); |
|||
|
|||
/// <inheritdoc />
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public void FromBgr24(Bgr24 source) => this.FromScaledVector4(source.ToScaledVector4()); |
|||
|
|||
/// <inheritdoc />
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public void FromBgra32(Bgra32 source) => this.FromScaledVector4(source.ToScaledVector4()); |
|||
|
|||
/// <inheritdoc/>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public void FromL8(L8 source) => this.FromScaledVector4(source.ToScaledVector4()); |
|||
|
|||
/// <inheritdoc/>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public void FromL16(L16 source) => this.FromScaledVector4(source.ToScaledVector4()); |
|||
|
|||
/// <inheritdoc/>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public void FromLa16(La16 source) => this.FromScaledVector4(source.ToScaledVector4()); |
|||
|
|||
/// <inheritdoc/>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public void FromLa32(La32 source) => this.FromScaledVector4(source.ToScaledVector4()); |
|||
|
|||
/// <inheritdoc />
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public void FromRgb24(Rgb24 source) => this.FromScaledVector4(source.ToScaledVector4()); |
|||
|
|||
/// <inheritdoc />
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public void FromRgba32(Rgba32 source) => this.FromScaledVector4(source.ToScaledVector4()); |
|||
|
|||
/// <inheritdoc />
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public void FromAbgr32(Abgr32 source) => this.FromScaledVector4(source.ToScaledVector4()); |
|||
|
|||
/// <inheritdoc />
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public void ToRgba32(ref Rgba32 dest) => dest.FromScaledVector4(this.ToScaledVector4()); |
|||
|
|||
/// <inheritdoc/>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public void FromRgb48(Rgb48 source) => this.FromScaledVector4(source.ToScaledVector4()); |
|||
|
|||
/// <inheritdoc/>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public void FromRgba64(Rgba64 source) => this.FromScaledVector4(source.ToScaledVector4()); |
|||
|
|||
/// <inheritdoc />
|
|||
public override bool Equals(object obj) => obj is Rgba128 other && this.Equals(other); |
|||
|
|||
/// <inheritdoc />
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public override int GetHashCode() => HashCode.Combine(this.R, this.G, this.B, this.A); |
|||
|
|||
/// <inheritdoc />
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public bool Equals(Rgba128 other) => this.R.Equals(other.R) && this.G.Equals(other.G) && this.B.Equals(other.B) && this.A.Equals(other.A); |
|||
|
|||
/// <inheritdoc />
|
|||
public override string ToString() => FormattableString.Invariant($"Rgba128({this.R}, {this.G}, {this.B}, {this.A})"); |
|||
} |
|||
|
|||
@ -0,0 +1,64 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Six Labors Split License.
|
|||
|
|||
using SixLabors.ImageSharp.Formats.OpenExr; |
|||
using SixLabors.ImageSharp.PixelFormats; |
|||
|
|||
namespace SixLabors.ImageSharp.Tests.Formats.Exr; |
|||
|
|||
[Trait("Format", "Exr")] |
|||
[ValidateDisposedMemoryAllocations] |
|||
public class ExrDecoderTests |
|||
{ |
|||
private static ExrDecoder ExrDecoder => new(); |
|||
|
|||
[Theory] |
|||
[WithFile(TestImages.Exr.Uncompressed, PixelTypes.Rgba32)] |
|||
public void ExrDecoder_CanDecode_Uncompressed<TPixel>(TestImageProvider<TPixel> provider) |
|||
where TPixel : unmanaged, IPixel<TPixel> |
|||
{ |
|||
using Image<TPixel> image = provider.GetImage(ExrDecoder); |
|||
image.DebugSave(provider); |
|||
image.CompareToOriginal(provider); |
|||
} |
|||
|
|||
[Theory] |
|||
[WithFile(TestImages.Exr.Zip, PixelTypes.Rgba32)] |
|||
public void ExrDecoder_CanDecode_ZipCompressed<TPixel>(TestImageProvider<TPixel> provider) |
|||
where TPixel : unmanaged, IPixel<TPixel> |
|||
{ |
|||
using Image<TPixel> image = provider.GetImage(ExrDecoder); |
|||
image.DebugSave(provider); |
|||
image.CompareToOriginal(provider); |
|||
} |
|||
|
|||
[Theory] |
|||
[WithFile(TestImages.Exr.Zips, PixelTypes.Rgba32)] |
|||
public void ExrDecoder_CanDecode_ZipsCompressed<TPixel>(TestImageProvider<TPixel> provider) |
|||
where TPixel : unmanaged, IPixel<TPixel> |
|||
{ |
|||
using Image<TPixel> image = provider.GetImage(ExrDecoder); |
|||
image.DebugSave(provider); |
|||
image.CompareToOriginal(provider); |
|||
} |
|||
|
|||
[Theory] |
|||
[WithFile(TestImages.Exr.Rle, PixelTypes.Rgba32)] |
|||
public void ExrDecoder_CanDecode_RunLengthCompressed<TPixel>(TestImageProvider<TPixel> provider) |
|||
where TPixel : unmanaged, IPixel<TPixel> |
|||
{ |
|||
using Image<TPixel> image = provider.GetImage(ExrDecoder); |
|||
image.DebugSave(provider); |
|||
image.CompareToOriginal(provider); |
|||
} |
|||
|
|||
[Theory] |
|||
[WithFile(TestImages.Exr.B44, PixelTypes.Rgba32)] |
|||
public void ExrDecoder_CanDecode_B44Compressed<TPixel>(TestImageProvider<TPixel> provider) |
|||
where TPixel : unmanaged, IPixel<TPixel> |
|||
{ |
|||
using Image<TPixel> image = provider.GetImage(ExrDecoder); |
|||
image.DebugSave(provider); |
|||
image.CompareToOriginal(provider); |
|||
} |
|||
} |
|||
@ -1,156 +1,66 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// Licensed under the Six Labors Split License.
|
|||
|
|||
using System.IO; |
|||
using System.Threading.Tasks; |
|||
using SixLabors.ImageSharp.Formats; |
|||
using SixLabors.ImageSharp.Formats.OpenExr; |
|||
using SixLabors.ImageSharp.PixelFormats; |
|||
using Xunit; |
|||
|
|||
namespace SixLabors.ImageSharp.Tests.Formats.Exr |
|||
namespace SixLabors.ImageSharp.Tests.Formats.Exr; |
|||
|
|||
[Trait("Format", "Exr")] |
|||
public class ImageExtensionsTest |
|||
{ |
|||
[Trait("Format", "Exr")] |
|||
public class ImageExtensionsTest |
|||
[Fact] |
|||
public void SaveAsExr_Stream() |
|||
{ |
|||
[Fact] |
|||
public void SaveAsExr_Path() |
|||
{ |
|||
string dir = TestEnvironment.CreateOutputDirectory(nameof(ImageExtensionsTest)); |
|||
string file = Path.Combine(dir, "SaveAsExr_Path.exr"); |
|||
|
|||
using (var image = new Image<Rgba32>(10, 10)) |
|||
{ |
|||
image.SaveAsOpenExr(file); |
|||
} |
|||
|
|||
using (Image.Load(file, out IImageFormat mime)) |
|||
{ |
|||
Assert.Equal("image/x-exr", mime.DefaultMimeType); |
|||
} |
|||
} |
|||
using var memoryStream = new MemoryStream(); |
|||
|
|||
[Fact] |
|||
public async Task SaveAsExrAsync_Path() |
|||
using (var image = new Image<Rgba32>(10, 10)) |
|||
{ |
|||
string dir = TestEnvironment.CreateOutputDirectory(nameof(ImageExtensionsTest)); |
|||
string file = Path.Combine(dir, "SaveAsExrAsync_Path.exr"); |
|||
|
|||
using (var image = new Image<Rgba32>(10, 10)) |
|||
{ |
|||
await image.SaveAsOpenExrAsync(file); |
|||
} |
|||
|
|||
using (Image.Load(file, out IImageFormat mime)) |
|||
{ |
|||
Assert.Equal("image/x-exr", mime.DefaultMimeType); |
|||
} |
|||
image.SaveAsOpenExr(memoryStream, new ExrEncoder()); |
|||
} |
|||
|
|||
[Fact] |
|||
public void SaveAsExr_Path_Encoder() |
|||
{ |
|||
string dir = TestEnvironment.CreateOutputDirectory(nameof(ImageExtensions)); |
|||
string file = Path.Combine(dir, "SaveAsExr_Path_Encoder.exr"); |
|||
|
|||
using (var image = new Image<Rgba32>(10, 10)) |
|||
{ |
|||
image.SaveAsOpenExr(file, new ExrEncoder()); |
|||
} |
|||
memoryStream.Position = 0; |
|||
|
|||
using (Image.Load(file, out IImageFormat mime)) |
|||
{ |
|||
Assert.Equal("image/x-exr", mime.DefaultMimeType); |
|||
} |
|||
} |
|||
|
|||
[Fact] |
|||
public async Task SaveAsExrAsync_Path_Encoder() |
|||
using (Image.Load(memoryStream, out IImageFormat mime)) |
|||
{ |
|||
string dir = TestEnvironment.CreateOutputDirectory(nameof(ImageExtensions)); |
|||
string file = Path.Combine(dir, "SaveAsExrAsync_Path_Encoder.tiff"); |
|||
|
|||
using (var image = new Image<Rgba32>(10, 10)) |
|||
{ |
|||
await image.SaveAsOpenExrAsync(file, new ExrEncoder()); |
|||
} |
|||
|
|||
using (Image.Load(file, out IImageFormat mime)) |
|||
{ |
|||
Assert.Equal("image/x-exr", mime.DefaultMimeType); |
|||
} |
|||
Assert.Equal("image/x-exr", mime.DefaultMimeType); |
|||
} |
|||
} |
|||
|
|||
[Fact] |
|||
public void SaveAsExr_Stream() |
|||
{ |
|||
using var memoryStream = new MemoryStream(); |
|||
|
|||
using (var image = new Image<Rgba32>(10, 10)) |
|||
{ |
|||
image.SaveAsOpenExr(memoryStream); |
|||
} |
|||
|
|||
memoryStream.Position = 0; |
|||
|
|||
using (Image.Load(memoryStream, out IImageFormat mime)) |
|||
{ |
|||
Assert.Equal("image/x-exr", mime.DefaultMimeType); |
|||
} |
|||
} |
|||
[Fact] |
|||
public void SaveAsExr_Stream_Encoder() |
|||
{ |
|||
using var memoryStream = new MemoryStream(); |
|||
|
|||
[Fact] |
|||
public async Task SaveAsExrAsync_StreamAsync() |
|||
using (var image = new Image<Rgba32>(10, 10)) |
|||
{ |
|||
using var memoryStream = new MemoryStream(); |
|||
|
|||
using (var image = new Image<Rgba32>(10, 10)) |
|||
{ |
|||
await image.SaveAsOpenExrAsync(memoryStream); |
|||
} |
|||
|
|||
memoryStream.Position = 0; |
|||
|
|||
using (Image.Load(memoryStream, out IImageFormat mime)) |
|||
{ |
|||
Assert.Equal("image/x-exr", mime.DefaultMimeType); |
|||
} |
|||
image.SaveAsOpenExr(memoryStream, new ExrEncoder()); |
|||
} |
|||
|
|||
[Fact] |
|||
public void SaveAsExr_Stream_Encoder() |
|||
{ |
|||
using var memoryStream = new MemoryStream(); |
|||
|
|||
using (var image = new Image<Rgba32>(10, 10)) |
|||
{ |
|||
image.SaveAsOpenExr(memoryStream, new ExrEncoder()); |
|||
} |
|||
memoryStream.Position = 0; |
|||
|
|||
memoryStream.Position = 0; |
|||
|
|||
using (Image.Load(memoryStream, out IImageFormat mime)) |
|||
{ |
|||
Assert.Equal("image/x-exr", mime.DefaultMimeType); |
|||
} |
|||
using (Image.Load(memoryStream, out IImageFormat mime)) |
|||
{ |
|||
Assert.Equal("image/x-exr", mime.DefaultMimeType); |
|||
} |
|||
} |
|||
|
|||
[Fact] |
|||
public async Task SaveAsExrAsync_Stream_Encoder() |
|||
{ |
|||
using var memoryStream = new MemoryStream(); |
|||
[Fact] |
|||
public async Task SaveAsExrAsync_Stream_Encoder() |
|||
{ |
|||
using var memoryStream = new MemoryStream(); |
|||
|
|||
using (var image = new Image<Rgba32>(10, 10)) |
|||
{ |
|||
await image.SaveAsOpenExrAsync(memoryStream, new ExrEncoder()); |
|||
} |
|||
using (var image = new Image<Rgba32>(10, 10)) |
|||
{ |
|||
await image.SaveAsOpenExrAsync(memoryStream, new ExrEncoder()); |
|||
} |
|||
|
|||
memoryStream.Position = 0; |
|||
memoryStream.Position = 0; |
|||
|
|||
using (Image.Load(memoryStream, out IImageFormat mime)) |
|||
{ |
|||
Assert.Equal("image/x-exr", mime.DefaultMimeType); |
|||
} |
|||
using (Image.Load(memoryStream, out IImageFormat mime)) |
|||
{ |
|||
Assert.Equal("image/x-exr", mime.DefaultMimeType); |
|||
} |
|||
} |
|||
} |
|||
|
|||
@ -0,0 +1,3 @@ |
|||
version https://git-lfs.github.com/spec/v1 |
|||
oid sha256:cde761051241cba1e7f8466d71602abdb130677de55602fe6afec4b287c75b9d |
|||
size 2533521 |
|||
@ -0,0 +1,3 @@ |
|||
version https://git-lfs.github.com/spec/v1 |
|||
oid sha256:6302e72676f5574b8a9dde7e4385cff1c115e9833b630118328b88aea07e31d0 |
|||
size 4098454 |
|||
@ -0,0 +1,3 @@ |
|||
version https://git-lfs.github.com/spec/v1 |
|||
oid sha256:71613ff5972fa9e7b405ac944d159d1791ad229f5560da616438c9d718eafd24 |
|||
size 5798633 |
|||
@ -0,0 +1,3 @@ |
|||
version https://git-lfs.github.com/spec/v1 |
|||
oid sha256:92c78a7cf9fce29e725511acadf49f0f784914da5bef55b0e0c4e75ba09c3a75 |
|||
size 2652397 |
|||
@ -0,0 +1,3 @@ |
|||
version https://git-lfs.github.com/spec/v1 |
|||
oid sha256:3e34a9b0bb7fd6eb24eef633dea737653812fd8ab5c5352f6e10523055823b1d |
|||
size 2918571 |
|||
Loading…
Reference in new issue