diff --git a/src/ImageSharp/Formats/Exr/Compression/Compressors/NoneExrCompressor.cs b/src/ImageSharp/Formats/Exr/Compression/Compressors/NoneExrCompressor.cs
index 21a50c5311..58768e990f 100644
--- a/src/ImageSharp/Formats/Exr/Compression/Compressors/NoneExrCompressor.cs
+++ b/src/ImageSharp/Formats/Exr/Compression/Compressors/NoneExrCompressor.cs
@@ -5,8 +5,18 @@ using SixLabors.ImageSharp.Memory;
namespace SixLabors.ImageSharp.Formats.Exr.Compression.Compressors;
+///
+/// Compressor for EXR image data which does not use any compression method.
+///
internal class NoneExrCompressor : ExrBaseCompressor
{
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The output stream to write the compressed image data to.
+ /// The memory allocator.
+ /// Bytes per row block.
+ /// Bytes per pixel row.
public NoneExrCompressor(Stream output, MemoryAllocator allocator, uint bytesPerBlock, uint bytesPerRow)
: base(output, allocator, bytesPerBlock, bytesPerRow)
{
diff --git a/src/ImageSharp/Formats/Exr/Compression/Compressors/ZipExrCompressor.cs b/src/ImageSharp/Formats/Exr/Compression/Compressors/ZipExrCompressor.cs
index d24b8f7dd7..ef7285da0c 100644
--- a/src/ImageSharp/Formats/Exr/Compression/Compressors/ZipExrCompressor.cs
+++ b/src/ImageSharp/Formats/Exr/Compression/Compressors/ZipExrCompressor.cs
@@ -6,6 +6,9 @@ using SixLabors.ImageSharp.Memory;
namespace SixLabors.ImageSharp.Formats.Exr.Compression.Compressors;
+///
+/// Compressor for EXR image data using the ZIP compression.
+///
internal class ZipExrCompressor : ExrBaseCompressor
{
private readonly DeflateCompressionLevel compressionLevel;
@@ -14,6 +17,14 @@ internal class ZipExrCompressor : ExrBaseCompressor
private readonly System.Buffers.IMemoryOwner buffer;
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The stream to write the compressed data to.
+ /// The memory allocator.
+ /// The bytes per block.
+ /// The bytes per row.
+ /// The compression level for deflate compression.
public ZipExrCompressor(Stream output, MemoryAllocator allocator, uint bytesPerBlock, uint bytesPerRow, DeflateCompressionLevel compressionLevel)
: base(output, allocator, bytesPerBlock, bytesPerRow)
{
diff --git a/src/ImageSharp/Formats/Exr/Compression/Decompressors/B44ExrCompression.cs b/src/ImageSharp/Formats/Exr/Compression/Decompressors/B44ExrCompression.cs
index e5b735a395..aa4944649c 100644
--- a/src/ImageSharp/Formats/Exr/Compression/Decompressors/B44ExrCompression.cs
+++ b/src/ImageSharp/Formats/Exr/Compression/Decompressors/B44ExrCompression.cs
@@ -8,6 +8,9 @@ using SixLabors.ImageSharp.Memory;
namespace SixLabors.ImageSharp.Formats.Exr.Compression.Decompressors;
+///
+/// Implementation of B44 decompressor for EXR image data.
+///
internal class B44ExrCompression : ExrBaseDecompressor
{
private readonly int width;
@@ -22,6 +25,15 @@ internal class B44ExrCompression : ExrBaseDecompressor
private readonly IMemoryOwner tmpBuffer;
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The memory allocator.
+ /// The bytes per pixel row block.
+ /// The bytes per row.
+ /// The rows per block.
+ /// The width of a pixel row in pixels.
+ /// The number of channels of the image.
public B44ExrCompression(MemoryAllocator allocator, uint bytesPerBlock, uint bytesPerRow, uint rowsPerBlock, int width, int channelCount)
: base(allocator, bytesPerBlock, bytesPerRow)
{
@@ -57,7 +69,7 @@ internal class B44ExrCompression : ExrBaseDecompressor
int bytesRead = stream.Read(this.scratch, 0, 3);
if (bytesRead == 0)
{
- ExrThrowHelper.ThrowInvalidImageContentException("Could not read enough data from the stream");
+ ExrThrowHelper.ThrowInvalidImageContentException("Could not read enough data from the stream!");
}
if (this.scratch[2] >= 13 << 2)
@@ -70,7 +82,7 @@ internal class B44ExrCompression : ExrBaseDecompressor
bytesRead = stream.Read(this.scratch, 3, 11);
if (bytesRead == 0)
{
- ExrThrowHelper.ThrowInvalidImageContentException("Could not read enough data from the stream");
+ ExrThrowHelper.ThrowInvalidImageContentException("Could not read enough data from the stream!");
}
Unpack14(this.scratch, this.s);
@@ -80,22 +92,22 @@ internal class B44ExrCompression : ExrBaseDecompressor
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));
+ this.s.AsSpan(0, n).CopyTo(row0[rowOffset..]);
+ this.s.AsSpan(4, n).CopyTo(row1[rowOffset..]);
+ this.s.AsSpan(8, n).CopyTo(row2[rowOffset..]);
+ this.s.AsSpan(12, n).CopyTo(row3[rowOffset..]);
}
else
{
- this.s.AsSpan(0, n).CopyTo(row0.Slice(rowOffset));
+ this.s.AsSpan(0, n).CopyTo(row0[rowOffset..]);
if (y + 1 < this.rowsPerBlock)
{
- this.s.AsSpan(4, n).CopyTo(row1.Slice(rowOffset));
+ this.s.AsSpan(4, n).CopyTo(row1[rowOffset..]);
}
if (y + 2 < this.rowsPerBlock)
{
- this.s.AsSpan(8, n).CopyTo(row2.Slice(rowOffset));
+ this.s.AsSpan(8, n).CopyTo(row2[rowOffset..]);
}
}
@@ -117,7 +129,7 @@ internal class B44ExrCompression : ExrBaseDecompressor
{
for (int i = 0; i < this.channelCount; i++)
{
- decompressed.Slice(offsetDecompressed + (i * blockSize), this.width).CopyTo(outputBuffer.Slice(offsetOutput));
+ decompressed.Slice(offsetDecompressed + (i * blockSize), this.width).CopyTo(outputBuffer[offsetOutput..]);
offsetOutput += this.width;
}
@@ -125,7 +137,11 @@ internal class B44ExrCompression : ExrBaseDecompressor
}
}
- // Unpack a 14-byte block into 4 by 4 16-bit pixels.
+ ///
+ /// Unpack a 14-byte block into 4 by 4 16-bit pixels.
+ ///
+ /// The source byte data to unpack.
+ /// Destintation buffer.
private static void Unpack14(Span b, Span s)
{
s[0] = (ushort)((b[0] << 8) | b[1]);
@@ -165,7 +181,11 @@ internal class B44ExrCompression : ExrBaseDecompressor
}
}
- // Unpack a 3-byte block into 4 by 4 identical 16-bit pixels.
+ ///
+ /// // Unpack a 3-byte block into 4 by 4 identical 16-bit pixels.
+ ///
+ /// The source byte data to unpack.
+ /// The destination buffer.
private static void Unpack3(Span b, Span s)
{
s[0] = (ushort)((b[0] << 8) | b[1]);
diff --git a/src/ImageSharp/Formats/Exr/Compression/Decompressors/NoneExrCompression.cs b/src/ImageSharp/Formats/Exr/Compression/Decompressors/NoneExrCompression.cs
index fb4fa5d832..c15ffbe325 100644
--- a/src/ImageSharp/Formats/Exr/Compression/Decompressors/NoneExrCompression.cs
+++ b/src/ImageSharp/Formats/Exr/Compression/Decompressors/NoneExrCompression.cs
@@ -6,8 +6,17 @@ using SixLabors.ImageSharp.Memory;
namespace SixLabors.ImageSharp.Formats.Exr.Compression.Decompressors;
+///
+/// Decompressor for EXR image data which do not use any compression.
+///
internal class NoneExrCompression : ExrBaseDecompressor
{
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The memory allocator.
+ /// The bytes per pixel row block.
+ /// The bytes per pixel row.
public NoneExrCompression(MemoryAllocator allocator, uint bytesPerBlock, uint bytesPerRow)
: base(allocator, bytesPerBlock, bytesPerRow)
{
@@ -19,7 +28,7 @@ internal class NoneExrCompression : ExrBaseDecompressor
int bytesRead = stream.Read(buffer, 0, Math.Min(buffer.Length, (int)this.BytesPerBlock));
if (bytesRead != (int)this.BytesPerBlock)
{
- ExrThrowHelper.ThrowInvalidImageContentException("Could not read enough pixel data!");
+ ExrThrowHelper.ThrowInvalidImageContentException("Could not read enough pixel data from the stream!");
}
}
diff --git a/src/ImageSharp/Formats/Exr/Compression/Decompressors/RunLengthExrCompression.cs b/src/ImageSharp/Formats/Exr/Compression/Decompressors/RunLengthExrCompression.cs
index 12f5fc8ab6..489493d82f 100644
--- a/src/ImageSharp/Formats/Exr/Compression/Decompressors/RunLengthExrCompression.cs
+++ b/src/ImageSharp/Formats/Exr/Compression/Decompressors/RunLengthExrCompression.cs
@@ -7,12 +7,21 @@ using SixLabors.ImageSharp.Memory;
namespace SixLabors.ImageSharp.Formats.Exr.Compression.Decompressors;
+///
+/// Implementation of RLE decompressor for EXR images.
+///
internal class RunLengthExrCompression : ExrBaseDecompressor
{
private readonly IMemoryOwner tmpBuffer;
private readonly ushort[] s = new ushort[16];
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The memory allocator.
+ /// The bytes per pixel row block.
+ /// The bytes per row.
public RunLengthExrCompression(MemoryAllocator allocator, uint bytesPerBlock, uint bytesPerRow)
: base(allocator, bytesPerBlock, bytesPerRow) => this.tmpBuffer = allocator.Allocate((int)bytesPerBlock);
@@ -68,12 +77,17 @@ internal class RunLengthExrCompression : ExrBaseDecompressor
Interleave(uncompressed, this.BytesPerBlock, buffer);
}
+ ///
+ /// Reads the next byte from the stream.
+ ///
+ /// The stream.
+ /// The next byte.
private static byte ReadNextByte(BufferedReadStream stream)
{
int nextByte = stream.ReadByte();
if (nextByte == -1)
{
- ExrThrowHelper.ThrowInvalidImageContentException("Not enough data to decompress RLE image!");
+ ExrThrowHelper.ThrowInvalidImageContentException("Not enough data to decompress RLE encoded EXR image!");
}
return (byte)nextByte;
diff --git a/src/ImageSharp/Formats/Exr/Compression/Decompressors/ZipExrCompression.cs b/src/ImageSharp/Formats/Exr/Compression/Decompressors/ZipExrCompression.cs
index b8dc5efa8e..dafe3d8321 100644
--- a/src/ImageSharp/Formats/Exr/Compression/Decompressors/ZipExrCompression.cs
+++ b/src/ImageSharp/Formats/Exr/Compression/Decompressors/ZipExrCompression.cs
@@ -9,10 +9,19 @@ using SixLabors.ImageSharp.Memory;
namespace SixLabors.ImageSharp.Formats.Exr.Compression.Decompressors;
+///
+/// Implementation of zhe Zip decompressor for EXR image data.
+///
internal class ZipExrCompression : ExrBaseDecompressor
{
private readonly IMemoryOwner tmpBuffer;
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The memory allocator.
+ /// The bytes per pixel row block.
+ /// The bytes per pixel row.
public ZipExrCompression(MemoryAllocator allocator, uint bytesPerBlock, uint bytesPerRow)
: base(allocator, bytesPerBlock, bytesPerRow) => this.tmpBuffer = allocator.Allocate((int)bytesPerBlock);
@@ -46,7 +55,7 @@ internal class ZipExrCompression : ExrBaseDecompressor
if (totalRead == 0)
{
- ExrThrowHelper.ThrowInvalidImageContentException("Could not read zip compressed image data!");
+ ExrThrowHelper.ThrowInvalidImageContentException("Could not read enough data for zip compressed image data!");
}
Reconstruct(uncompressed, (uint)totalRead);
diff --git a/src/ImageSharp/Formats/Exr/Compression/ExrBaseCompression.cs b/src/ImageSharp/Formats/Exr/Compression/ExrBaseCompression.cs
index 57e6b2a26c..b116dffc65 100644
--- a/src/ImageSharp/Formats/Exr/Compression/ExrBaseCompression.cs
+++ b/src/ImageSharp/Formats/Exr/Compression/ExrBaseCompression.cs
@@ -5,10 +5,19 @@ using SixLabors.ImageSharp.Memory;
namespace SixLabors.ImageSharp.Formats.Exr.Compression;
+///
+/// Base class for EXR compression.
+///
internal abstract class ExrBaseCompression : IDisposable
{
private bool isDisposed;
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The memory allocator.
+ /// The bytes per block.
+ /// The bytes per row.
protected ExrBaseCompression(MemoryAllocator allocator, uint bytesPerBlock, uint bytesPerRow)
{
this.Allocator = allocator;
diff --git a/src/ImageSharp/Formats/Exr/Compression/ExrBaseDecompressor.cs b/src/ImageSharp/Formats/Exr/Compression/ExrBaseDecompressor.cs
index 1bbf36d768..efe3c7877f 100644
--- a/src/ImageSharp/Formats/Exr/Compression/ExrBaseDecompressor.cs
+++ b/src/ImageSharp/Formats/Exr/Compression/ExrBaseDecompressor.cs
@@ -6,15 +6,36 @@ using SixLabors.ImageSharp.Memory;
namespace SixLabors.ImageSharp.Formats.Exr.Compression;
+///
+/// The base EXR decompressor class.
+///
internal abstract class ExrBaseDecompressor : ExrBaseCompression
{
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The memory allocator.
+ /// The bytes per row block.
+ /// The bytes per row.
protected ExrBaseDecompressor(MemoryAllocator allocator, uint bytesPerBlock, uint bytesPerRow)
: base(allocator, bytesPerBlock, bytesPerRow)
{
}
+ ///
+ /// Decompresses the specified stream.
+ ///
+ /// The buffered stream to decompress.
+ /// The compressed bytes.
+ /// The buffer to write the decompressed data to.
public abstract void Decompress(BufferedReadStream stream, uint compressedBytes, Span buffer);
+ ///
+ /// Integrate over all differences to the previous value in order to
+ /// reconstruct sample values.
+ ///
+ /// The buffer with the data.
+ /// The un compressed bytes.
protected static void Reconstruct(Span buffer, uint unCompressedBytes)
{
int offset = 0;
@@ -26,6 +47,12 @@ internal abstract class ExrBaseDecompressor : ExrBaseCompression
}
}
+ ///
+ /// Interleaves the input data.
+ ///
+ /// The source data.
+ /// The uncompressed bytes.
+ /// The output to write to.
protected static void Interleave(Span source, uint unCompressedBytes, Span output)
{
int sourceOffset = 0;
diff --git a/src/ImageSharp/Formats/Exr/Compression/ExrCompressorFactory.cs b/src/ImageSharp/Formats/Exr/Compression/ExrCompressorFactory.cs
index 24f396e16f..b1b7d2e8e6 100644
--- a/src/ImageSharp/Formats/Exr/Compression/ExrCompressorFactory.cs
+++ b/src/ImageSharp/Formats/Exr/Compression/ExrCompressorFactory.cs
@@ -8,27 +8,32 @@ using SixLabors.ImageSharp.Memory;
namespace SixLabors.ImageSharp.Formats.Exr.Compression;
+///
+/// Factory class for creating a compressor for EXR image data.
+///
internal static class ExrCompressorFactory
{
+ ///
+ /// Creates the specified exr data compressor.
+ ///
+ /// The compression method.
+ /// The memory allocator.
+ /// The output stream.
+ /// The bytes per block.
+ /// The bytes per row.
+ /// The deflate compression level.
+ /// A compressor for EXR image data.
public static ExrBaseCompressor Create(
ExrCompression method,
MemoryAllocator allocator,
Stream output,
uint bytesPerBlock,
uint bytesPerRow,
- DeflateCompressionLevel compressionLevel = DeflateCompressionLevel.DefaultCompression)
- {
- switch (method)
+ DeflateCompressionLevel compressionLevel = DeflateCompressionLevel.DefaultCompression) => method switch
{
- case ExrCompression.None:
- return new NoneExrCompressor(output, allocator, bytesPerBlock, bytesPerRow);
- case ExrCompression.Zips:
- return new ZipExrCompressor(output, allocator, bytesPerBlock, bytesPerRow, compressionLevel);
- case ExrCompression.Zip:
- return new ZipExrCompressor(output, allocator, bytesPerBlock, bytesPerRow, compressionLevel);
-
- default:
- throw ExrThrowHelper.NotSupportedCompressor(method.ToString());
- }
- }
+ ExrCompression.None => new NoneExrCompressor(output, allocator, bytesPerBlock, bytesPerRow),
+ ExrCompression.Zips => new ZipExrCompressor(output, allocator, bytesPerBlock, bytesPerRow, compressionLevel),
+ ExrCompression.Zip => new ZipExrCompressor(output, allocator, bytesPerBlock, bytesPerRow, compressionLevel),
+ _ => throw ExrThrowHelper.NotSupportedCompressor(method.ToString()),
+ };
}
diff --git a/src/ImageSharp/Formats/Exr/Compression/ExrDecompressorFactory.cs b/src/ImageSharp/Formats/Exr/Compression/ExrDecompressorFactory.cs
index 2696a289cd..62519666b5 100644
--- a/src/ImageSharp/Formats/Exr/Compression/ExrDecompressorFactory.cs
+++ b/src/ImageSharp/Formats/Exr/Compression/ExrDecompressorFactory.cs
@@ -7,8 +7,22 @@ using SixLabors.ImageSharp.Memory;
namespace SixLabors.ImageSharp.Formats.Exr.Compression;
+///
+/// The Factory class for creating a EXR data decompressor.
+///
internal static class ExrDecompressorFactory
{
+ ///
+ /// Creates a decomprssor for a specific EXR compression type.
+ ///
+ /// The compression method.
+ /// The memory allocator.
+ /// The width in pixels of the image.
+ /// The bytes per block.
+ /// The bytes per row.
+ /// The rows per block.
+ /// The number of image channels.
+ /// Decompressor for EXR image data.
public static ExrBaseDecompressor Create(
ExrCompression method,
MemoryAllocator memoryAllocator,
@@ -16,22 +30,13 @@ internal static class ExrDecompressorFactory
uint bytesPerBlock,
uint bytesPerRow,
uint rowsPerBlock,
- int channelCount)
- {
- switch (method)
+ int channelCount) => method switch
{
- case ExrCompression.None:
- return new NoneExrCompression(memoryAllocator, bytesPerBlock, bytesPerRow);
- case ExrCompression.Zips:
- return new ZipExrCompression(memoryAllocator, bytesPerBlock, bytesPerRow);
- case ExrCompression.Zip:
- return new ZipExrCompression(memoryAllocator, bytesPerBlock, bytesPerRow);
- case ExrCompression.RunLengthEncoded:
- return new RunLengthExrCompression(memoryAllocator, bytesPerBlock, bytesPerRow);
- case ExrCompression.B44:
- return new B44ExrCompression(memoryAllocator, bytesPerBlock, bytesPerRow, rowsPerBlock, width, channelCount);
- default:
- throw ExrThrowHelper.NotSupportedDecompressor(nameof(method));
- }
- }
+ ExrCompression.None => new NoneExrCompression(memoryAllocator, bytesPerBlock, bytesPerRow),
+ ExrCompression.Zips => new ZipExrCompression(memoryAllocator, bytesPerBlock, bytesPerRow),
+ ExrCompression.Zip => new ZipExrCompression(memoryAllocator, bytesPerBlock, bytesPerRow),
+ ExrCompression.RunLengthEncoded => new RunLengthExrCompression(memoryAllocator, bytesPerBlock, bytesPerRow),
+ ExrCompression.B44 => new B44ExrCompression(memoryAllocator, bytesPerBlock, bytesPerRow, rowsPerBlock, width, channelCount),
+ _ => throw ExrThrowHelper.NotSupportedDecompressor(nameof(method)),
+ };
}
diff --git a/src/ImageSharp/Formats/Exr/Constants/ExrImageType.cs b/src/ImageSharp/Formats/Exr/Constants/ExrImageType.cs
index beeabe35e1..9e2cd009ff 100644
--- a/src/ImageSharp/Formats/Exr/Constants/ExrImageType.cs
+++ b/src/ImageSharp/Formats/Exr/Constants/ExrImageType.cs
@@ -3,9 +3,19 @@
namespace SixLabors.ImageSharp.Formats.Exr.Constants;
+///
+/// Enum for the differnt exr image type.
+///
internal enum ExrImageType
{
+ ///
+ /// The image data is stored in scan lines.
+ ///
ScanLine = 0,
+ ///
+ /// The image data is stored in tile.
+ /// This is not yet supported.
+ ///
Tiled = 1
}
diff --git a/src/ImageSharp/Formats/Exr/Constants/ExrLineOrder.cs b/src/ImageSharp/Formats/Exr/Constants/ExrLineOrder.cs
index 56573472ca..73e86d6ef1 100644
--- a/src/ImageSharp/Formats/Exr/Constants/ExrLineOrder.cs
+++ b/src/ImageSharp/Formats/Exr/Constants/ExrLineOrder.cs
@@ -3,11 +3,23 @@
namespace SixLabors.ImageSharp.Formats.Exr.Constants;
+///
+/// Enum for the different scan line ordering.
+///
internal enum ExrLineOrder : byte
{
+ ///
+ /// The scan lines are written from top-to-bottom.
+ ///
IncreasingY = 0,
+ ///
+ /// The scan lines are written from bottom-to-top.
+ ///
DecreasingY = 1,
+ ///
+ /// The Scan lines are written in no particular oder.
+ ///
RandomY = 2
}
diff --git a/src/ImageSharp/Formats/Exr/ExrAttribute.cs b/src/ImageSharp/Formats/Exr/ExrAttribute.cs
index b4e95f1d47..093c973919 100644
--- a/src/ImageSharp/Formats/Exr/ExrAttribute.cs
+++ b/src/ImageSharp/Formats/Exr/ExrAttribute.cs
@@ -5,11 +5,20 @@ using System.Diagnostics;
namespace SixLabors.ImageSharp.Formats.Exr;
+///
+/// Repressents an exr image attribute.
+///
[DebuggerDisplay("Name: {Name}, Type: {Type}, Length: {Length}")]
internal class ExrAttribute
{
public static readonly ExrAttribute EmptyAttribute = new(string.Empty, string.Empty, 0);
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The name of the attribute.
+ /// The type of the attribute.
+ /// The length in bytes.
public ExrAttribute(string name, string type, int length)
{
this.Name = name;
@@ -17,9 +26,18 @@ internal class ExrAttribute
this.Length = length;
}
+ ///
+ /// Gets the name of the attribute.
+ ///
public string Name { get; }
+ ///
+ /// Gets the type of the attribute.
+ ///
public string Type { get; }
+ ///
+ /// Gets the length in bytes of the attribute.
+ ///
public int Length { get; }
}
diff --git a/src/ImageSharp/Formats/Exr/ExrBox2i.cs b/src/ImageSharp/Formats/Exr/ExrBox2i.cs
index 032e60d929..c9c53d6486 100644
--- a/src/ImageSharp/Formats/Exr/ExrBox2i.cs
+++ b/src/ImageSharp/Formats/Exr/ExrBox2i.cs
@@ -5,9 +5,19 @@ using System.Diagnostics;
namespace SixLabors.ImageSharp.Formats.Exr;
+///
+/// Integer region definition.
+///
[DebuggerDisplay("xMin: {XMin}, yMin: {YMin}, xMax: {XMax}, yMax: {YMax}")]
internal readonly struct ExrBox2i
{
+ ///
+ /// Initializes a new instance of the struct.
+ ///
+ /// The minimum x value.
+ /// The minimum y value.
+ /// The maximum x value.
+ /// The maximum y value.
public ExrBox2i(int xMin, int yMin, int xMax, int yMax)
{
this.XMin = xMin;
@@ -16,11 +26,23 @@ internal readonly struct ExrBox2i
this.YMax = yMax;
}
+ ///
+ /// Gets the minimum x value.
+ ///
public int XMin { get; }
+ ///
+ /// Gets the minimum y value.
+ ///
public int YMin { get; }
+ ///
+ /// Gets the maximum x value.
+ ///
public int XMax { get; }
+ ///
+ /// Gets the maximum y value.
+ ///
public int YMax { get; }
}
diff --git a/src/ImageSharp/Formats/Exr/ExrChannelInfo.cs b/src/ImageSharp/Formats/Exr/ExrChannelInfo.cs
index d4f5825b99..5aae64f283 100644
--- a/src/ImageSharp/Formats/Exr/ExrChannelInfo.cs
+++ b/src/ImageSharp/Formats/Exr/ExrChannelInfo.cs
@@ -7,26 +7,55 @@ using SixLabors.ImageSharp.Formats.Exr.Constants;
namespace SixLabors.ImageSharp.Formats.Exr;
+///
+/// Information about a pixel channel.
+///
[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)
+ ///
+ /// Initializes a new instance of the struct.
+ ///
+ /// Name of the channel.
+ /// The type of the pixel data.
+ /// Linear flag, possible values are 0 and 1.
+ /// X sampling.
+ /// Y sampling.
+ public ExrChannelInfo(string channelName, ExrPixelType pixelType, byte linear, int xSampling, int ySampling)
{
this.ChannelName = channelName;
this.PixelType = pixelType;
- this.PLinear = pLinear;
+ this.Linear = linear;
this.XSampling = xSampling;
this.YSampling = ySampling;
}
+ ///
+ /// Gets the channel name.
+ ///
public string ChannelName { get; }
+
+ ///
+ /// Gets the type of the pixel data.
+ ///
public ExrPixelType PixelType { get; }
- public byte PLinear { get; }
+ ///
+ /// Gets the linear flag. Hint to lossy compression methods that indicates whether
+ /// human perception of the quantity represented by this channel
+ /// is closer to linear or closer to logarithmic.
+ ///
+ public byte Linear { get; }
+ ///
+ /// Gets the x sampling value.
+ ///
public int XSampling { get; }
+ ///
+ /// Gets the y sampling value.
+ ///
public int YSampling { get; }
}
diff --git a/src/ImageSharp/Formats/Exr/ExrDecoderCore.cs b/src/ImageSharp/Formats/Exr/ExrDecoderCore.cs
index a4fa4b0ac2..0b75154c2c 100644
--- a/src/ImageSharp/Formats/Exr/ExrDecoderCore.cs
+++ b/src/ImageSharp/Formats/Exr/ExrDecoderCore.cs
@@ -120,6 +120,21 @@ internal sealed class ExrDecoderCore : ImageDecoderCore
return image;
}
+ ///
+ protected override ImageInfo Identify(BufferedReadStream stream, CancellationToken cancellationToken)
+ {
+ ExrHeaderAttributes header = this.ReadExrHeader(stream);
+
+ return new ImageInfo(new Size(header.DataWindow.XMax, header.DataWindow.YMax), this.metadata);
+ }
+
+ ///
+ /// Decodes image data with floating point pixel data.
+ ///
+ /// The type of the pixels.
+ /// The stream to read from.
+ /// The pixel buffer.
+ /// The cancellation token.
private void DecodeFloatingPointPixelData(BufferedReadStream stream, Buffer2D pixels, CancellationToken cancellationToken)
where TPixel : unmanaged, IPixel
{
@@ -178,6 +193,13 @@ internal sealed class ExrDecoderCore : ImageDecoderCore
}
}
+ ///
+ /// Decodes image data with unsigned int pixel data.
+ ///
+ /// The type of the pixels.
+ /// The stream to read from.
+ /// The pixel buffer.
+ /// The cancellation token.
private void DecodeUnsignedIntPixelData(BufferedReadStream stream, Buffer2D pixels, CancellationToken cancellationToken)
where TPixel : unmanaged, IPixel
{
@@ -236,6 +258,18 @@ internal sealed class ExrDecoderCore : ImageDecoderCore
}
}
+ ///
+ /// Reads float image channel data.
+ ///
+ /// The stream to read from.
+ /// The channel info.
+ /// The decompressed pixel data.
+ /// The red channel pixel data.
+ /// The green channel pixel data.
+ /// The blue channel pixel data.
+ /// The alpha channel pixel data.
+ /// The width of a row in pixels.
+ /// The bytes read.
private static int ReadFloatChannelData(
BufferedReadStream stream,
ExrChannelInfo channel,
@@ -275,6 +309,18 @@ internal sealed class ExrDecoderCore : ImageDecoderCore
}
}
+ ///
+ /// Reads UINT image channel data.
+ ///
+ /// The stream to read from.
+ /// The channel info.
+ /// The decompressed pixel data.
+ /// The red channel pixel data.
+ /// The green channel pixel data.
+ /// The blue channel pixel data.
+ /// The alpha channel pixel data.
+ /// The width of a row in pixels.
+ /// The bytes read.
private int ReadUnsignedIntChannelData(
BufferedReadStream stream,
ExrChannelInfo channel,
@@ -313,6 +359,14 @@ internal sealed class ExrDecoderCore : ImageDecoderCore
}
}
+ ///
+ /// Reads the channel data for pixel type HALF or FLOAT.
+ ///
+ /// The channel info.
+ /// The decompressed pixel data.
+ /// The pixel data as float.
+ /// The width in pixel of a row.
+ /// The bytes read.
private static int ReadChannelData(ExrChannelInfo channel, Span decompressedPixelData, Span pixelData, int width) => channel.PixelType switch
{
ExrPixelType.Half => ReadPixelRowChannelHalfSingle(decompressedPixelData, pixelData, width),
@@ -320,12 +374,27 @@ internal sealed class ExrDecoderCore : ImageDecoderCore
_ => 0,
};
+ ///
+ /// Reads the channel data for pixel type UINT.
+ ///
+ /// The channel info.
+ /// The decompressed pixel data.
+ /// The pixel data as uint.
+ /// The width in pixels.
+ /// The bytes read.
private static int ReadChannelData(ExrChannelInfo channel, Span decompressedPixelData, Span pixelData, int width) => channel.PixelType switch
{
ExrPixelType.UnsignedInt => ReadPixelRowChannelUnsignedInt(decompressedPixelData, pixelData, width),
_ => 0,
};
+ ///
+ /// Reads a pixel row with the pixel data being 16 bit half values.
+ ///
+ /// The decompressed pixel data.
+ /// The channel data as float.
+ /// The width of a row in pixels.
+ /// The bytes read.
private static int ReadPixelRowChannelHalfSingle(Span decompressedPixelData, Span channelData, int width)
{
int offset = 0;
@@ -339,6 +408,13 @@ internal sealed class ExrDecoderCore : ImageDecoderCore
return offset;
}
+ ///
+ /// Reads a pixel row with 32 bit float pixel data.
+ ///
+ /// The decompressed pixel data.
+ /// The pixel data as float.
+ /// The width in pixels of a row.
+ /// The bytes read.
private static int ReadPixelRowChannelSingle(Span decompressedPixelData, Span channelData, int width)
{
int offset = 0;
@@ -352,6 +428,13 @@ internal sealed class ExrDecoderCore : ImageDecoderCore
return offset;
}
+ ///
+ /// Reads a pixel row with the pixel typ UINT.
+ ///
+ /// The decompressed pixel bytes.
+ /// The uint pixel data.
+ /// The width of a row in pixels.
+ /// The bytes read.
private static int ReadPixelRowChannelUnsignedInt(Span decompressedPixelData, Span channelData, int width)
{
int offset = 0;
@@ -364,14 +447,10 @@ internal sealed class ExrDecoderCore : ImageDecoderCore
return offset;
}
- ///
- protected override ImageInfo Identify(BufferedReadStream stream, CancellationToken cancellationToken)
- {
- ExrHeaderAttributes header = this.ReadExrHeader(stream);
-
- return new ImageInfo(new Size(header.DataWindow.XMax, header.DataWindow.YMax), this.metadata);
- }
-
+ ///
+ /// Validates that all image channels have the same type and are among the supported pixel types.
+ ///
+ /// The pixel type.
private ExrPixelType ValidateChannels()
{
if (this.Channels.Count == 0)
@@ -380,12 +459,42 @@ internal sealed class ExrDecoderCore : ImageDecoderCore
}
// Find pixel the type of any channel which is R, G, B or A.
- ExrPixelType pixelType = this.FindPixelType();
+ ExrPixelType? pixelType = null;
+ for (int i = 0; i < this.Channels.Count; i++)
+ {
+ if (this.Channels[i].ChannelName.Equals(ExrConstants.ChannelNames.Blue, StringComparison.Ordinal) ||
+ this.Channels[i].ChannelName.Equals(ExrConstants.ChannelNames.Green, StringComparison.Ordinal) ||
+ this.Channels[i].ChannelName.Equals(ExrConstants.ChannelNames.Red, StringComparison.Ordinal) ||
+ this.Channels[i].ChannelName.Equals(ExrConstants.ChannelNames.Alpha, StringComparison.Ordinal) ||
+ this.Channels[i].ChannelName.Equals(ExrConstants.ChannelNames.Luminance, StringComparison.Ordinal))
+ {
+ if (!pixelType.HasValue)
+ {
+ pixelType = this.Channels[i].PixelType;
+ }
+ else
+ {
+ if (pixelType != this.Channels[i].PixelType)
+ {
+ ExrThrowHelper.ThrowNotSupported("Pixel channel data is expected to be the same for all channels.");
+ }
+ }
+ }
+ }
- return pixelType;
+ if (!pixelType.HasValue)
+ {
+ ExrThrowHelper.ThrowNotSupported("Pixel channel data is unknown! Only R, G, B, A and Y are supported.");
+ }
+
+ return pixelType.Value;
}
- private ExrImageDataType ReadImageDataType()
+ ///
+ /// Determines the type image from the channel information.
+ ///
+ /// The image data type.
+ private ExrImageDataType DetermineImageDataType()
{
bool hasRedChannel = false;
bool hasGreenChannel = false;
@@ -438,6 +547,12 @@ internal sealed class ExrDecoderCore : ImageDecoderCore
return ExrImageDataType.Unknown;
}
+ ///
+ /// Reads the exr image header.
+ ///
+ ///
+ /// The stream.
+ /// The image header attributes.
private ExrHeaderAttributes ReadExrHeader(BufferedReadStream stream)
{
// Skip over the magick bytes, we already know its an EXR image.
@@ -471,7 +586,7 @@ internal sealed class ExrDecoderCore : ImageDecoderCore
this.Channels = this.HeaderAttributes.Channels;
this.Compression = this.HeaderAttributes.Compression;
this.PixelType = this.ValidateChannels();
- this.ImageDataType = this.ReadImageDataType();
+ this.ImageDataType = this.DetermineImageDataType();
this.metadata = new ImageMetadata();
@@ -483,6 +598,11 @@ internal sealed class ExrDecoderCore : ImageDecoderCore
return this.HeaderAttributes;
}
+ ///
+ /// Parses the image header attributes.
+ ///
+ /// The stream to read from.
+ /// The image header attributes.
private ExrHeaderAttributes ParseHeaderAttributes(BufferedReadStream stream)
{
ExrAttribute attribute = this.ReadAttribute(stream);
@@ -599,6 +719,11 @@ internal sealed class ExrDecoderCore : ImageDecoderCore
return header;
}
+ ///
+ /// Reads a attrbute from the stream, which consist of a name, a type and a size in bytes.
+ ///
+ /// The stream to read from.
+ /// A attribute.
private ExrAttribute ReadAttribute(BufferedReadStream stream)
{
string attributeName = ReadString(stream);
@@ -608,12 +733,16 @@ internal sealed class ExrDecoderCore : ImageDecoderCore
}
string attributeType = ReadString(stream);
-
int attributeSize = this.ReadSignedInteger(stream);
return new ExrAttribute(attributeName, attributeType, attributeSize);
}
+ ///
+ /// Reads a box attribute, which is a xMin, xMax and yMin, yMax value.
+ ///
+ /// The stream to reaad from.
+ /// A box struct.
private ExrBox2i ReadBoxInteger(BufferedReadStream stream)
{
int xMin = this.ReadSignedInteger(stream);
@@ -624,6 +753,12 @@ internal sealed class ExrDecoderCore : ImageDecoderCore
return new ExrBox2i(xMin, yMin, xMax, yMax);
}
+ ///
+ /// Reads the channel list from the stream.
+ ///
+ /// The stream to read from.
+ /// The size in bytes of the channel list attribute.
+ /// The channel list.
private List ReadChannelList(BufferedReadStream stream, int attributeSize)
{
List channels = [];
@@ -637,12 +772,18 @@ internal sealed class ExrDecoderCore : ImageDecoderCore
// Last byte should be a null byte.
if (stream.ReadByte() == -1)
{
- ExrThrowHelper.ThrowInvalidImageContentException("Could not read enough data to read exr channel list!");
+ ExrThrowHelper.ThrowInvalidImageContentException("Could not read enough data to read the exr channel list!");
}
return channels;
}
+ ///
+ /// Reads the channel information from the stream.
+ ///
+ /// The stream to read from.
+ /// The bytes read.
+ /// Channel info.
private ExrChannelInfo ReadChannelInfo(BufferedReadStream stream, out int bytesRead)
{
string channelName = ReadString(stream);
@@ -670,6 +811,11 @@ internal sealed class ExrDecoderCore : ImageDecoderCore
return new ExrChannelInfo(channelName, pixelType, pLinear, xSampling, ySampling);
}
+ ///
+ /// Reads a the string from the stream.
+ ///
+ /// The stream to read from.
+ /// A string.
private static string ReadString(BufferedReadStream stream)
{
StringBuilder str = new();
@@ -694,45 +840,20 @@ internal sealed class ExrDecoderCore : ImageDecoderCore
return str.ToString();
}
- private ExrPixelType FindPixelType()
- {
- ExrPixelType? pixelType = null;
- for (int i = 0; i < this.Channels.Count; i++)
- {
- if (this.Channels[i].ChannelName.Equals(ExrConstants.ChannelNames.Blue, StringComparison.Ordinal) ||
- this.Channels[i].ChannelName.Equals(ExrConstants.ChannelNames.Green, StringComparison.Ordinal) ||
- this.Channels[i].ChannelName.Equals(ExrConstants.ChannelNames.Red, StringComparison.Ordinal) ||
- this.Channels[i].ChannelName.Equals(ExrConstants.ChannelNames.Alpha, StringComparison.Ordinal) ||
- this.Channels[i].ChannelName.Equals(ExrConstants.ChannelNames.Luminance, StringComparison.Ordinal))
- {
- if (!pixelType.HasValue)
- {
- pixelType = this.Channels[i].PixelType;
- }
- else
- {
- if (pixelType != this.Channels[i].PixelType)
- {
- ExrThrowHelper.ThrowNotSupported("Pixel channel data is expected to be the same for all channels.");
- }
- }
- }
- }
-
- if (!pixelType.HasValue)
- {
- ExrThrowHelper.ThrowNotSupported("Pixel channel data is unknown! Only R, G, B, A and Y are supported.");
- }
-
- return pixelType.Value;
- }
-
+ ///
+ /// Determines whether the compression is supported.
+ ///
+ /// True if the compression is supported; otherwise, false>.
private bool IsSupportedCompression() => this.Compression switch
{
ExrCompression.None or ExrCompression.Zip or ExrCompression.Zips or ExrCompression.RunLengthEncoded or ExrCompression.B44 => true,
_ => false,
};
+ ///
+ /// Determines whether this image has alpha channel.
+ ///
+ /// True if this image has a alpha channel; otherwise, false.
private bool HasAlpha()
{
foreach (ExrChannelInfo channelInfo in this.Channels)
diff --git a/src/ImageSharp/Formats/Exr/ExrEncoderCore.cs b/src/ImageSharp/Formats/Exr/ExrEncoderCore.cs
index 9f86e79e65..56584132b8 100644
--- a/src/ImageSharp/Formats/Exr/ExrEncoderCore.cs
+++ b/src/ImageSharp/Formats/Exr/ExrEncoderCore.cs
@@ -147,6 +147,18 @@ internal sealed class ExrEncoderCore
}
}
+ ///
+ /// Encodes and writes pixel data with float pixel data to the stream.
+ ///
+ /// The type of the pixels.
+ /// The stream to write to.
+ /// The pixel bufer.
+ /// The width of the image in pixels.
+ /// The height of the image in pixels.
+ /// The imagechannels.
+ /// The compression to use.
+ /// The cancellation token.
+ /// The array of pixel row offsets.
private ulong[] EncodeFloatingPointPixelData(
Stream stream,
Buffer2D pixels,
@@ -227,6 +239,18 @@ internal sealed class ExrEncoderCore
return rowOffsets;
}
+ ///
+ /// Encodes and writes pixel data with the unsigned int pixel type to the stream.
+ ///
+ /// The type of the pixels.
+ /// The stream to write to.
+ /// The pixel bufer.
+ /// The width of the image in pixels.
+ /// The height of the image in pixels.
+ /// The imagechannels.
+ /// The compression to use.
+ /// The cancellation token.
+ /// The array of pixel row offsets.
private ulong[] EncodeUnsignedIntPixelData(
Stream stream,
Buffer2D pixels,
@@ -301,6 +325,11 @@ internal sealed class ExrEncoderCore
return rowOffsets;
}
+ ///
+ /// Writes the image header to the stream.
+ ///
+ /// The stream to write to.
+ /// The header.
private void WriteHeader(Stream stream, ExrHeaderAttributes header)
{
this.WriteChannels(stream, header.Channels);
@@ -314,6 +343,15 @@ internal sealed class ExrEncoderCore
stream.WriteByte(0);
}
+ ///
+ /// Writes a row of pixels with the FLOAT pixel type to a buffer.
+ ///
+ /// The buffer to write to.
+ /// The width of a row in pixels.
+ /// The alpha channel buffer.
+ /// The blue channel buffer.
+ /// The green channel buffer.
+ /// The red channel buffer.
private static void WriteSingleRow(Span buffer, int width, Span alphaBuffer, Span blueBuffer, Span greenBuffer, Span redBuffer)
{
int offset = 0;
@@ -342,6 +380,15 @@ internal sealed class ExrEncoderCore
}
}
+ ///
+ /// Writes a row of pixels with the HALF pixel type to a buffer.
+ ///
+ /// The buffer to write to.
+ /// The width of a row in pixels.
+ /// The alpha channel buffer.
+ /// The blue channel buffer.
+ /// The green channel buffer.
+ /// The red channel buffer.
private static void WriteHalfSingleRow(Span buffer, int width, Span alphaBuffer, Span blueBuffer, Span greenBuffer, Span redBuffer)
{
int offset = 0;
@@ -370,6 +417,15 @@ internal sealed class ExrEncoderCore
}
}
+ ///
+ /// Writes a row of pixels with unsigned int pixel data to a buffer.
+ ///
+ /// The buffer to write to.
+ /// The width of the row in pixels.
+ /// The alpha channel buffer.
+ /// The blue channel buffer.
+ /// The green channel buffer.
+ /// The red channel buffer.
private static void WriteUnsignedIntRow(Span buffer, int width, Span alphaBuffer, Span blueBuffer, Span greenBuffer, Span redBuffer)
{
int offset = 0;
@@ -398,6 +454,12 @@ internal sealed class ExrEncoderCore
}
}
+ ///
+ /// Writes the row offsets to the stream.
+ ///
+ /// The stream to write to.
+ /// The height in pixels of the image.
+ /// The row offsets.
private void WriteRowOffsets(Stream stream, int height, ulong[] rowOffsets)
{
for (int i = 0; i < height; i++)
@@ -407,6 +469,11 @@ internal sealed class ExrEncoderCore
}
}
+ ///
+ /// Writes the channel infos to the stream.
+ ///
+ /// The stream to write to.
+ /// The channels.
private void WriteChannels(Stream stream, IList channels)
{
int attributeSize = 0;
@@ -429,24 +496,70 @@ internal sealed class ExrEncoderCore
stream.WriteByte(0);
}
+ ///
+ /// Writes info about a single channel to the stream.
+ ///
+ /// The stream to write to.
+ /// The channel information.
+ private void WriteChannelInfo(Stream stream, ExrChannelInfo channelInfo)
+ {
+ WriteString(stream, channelInfo.ChannelName);
+
+ BinaryPrimitives.WriteInt32LittleEndian(this.buffer, (int)channelInfo.PixelType);
+ stream.Write(this.buffer.AsSpan(0, 4));
+
+ stream.WriteByte(channelInfo.Linear);
+
+ // 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));
+
+ BinaryPrimitives.WriteInt32LittleEndian(this.buffer, channelInfo.YSampling);
+ stream.Write(this.buffer.AsSpan(0, 4));
+ }
+
+ ///
+ /// Writes the compression type to the stream.
+ ///
+ /// The stream to write to.
+ /// The compression type.
private void WriteCompression(Stream stream, ExrCompression compression)
{
this.WriteAttributeInformation(stream, ExrConstants.AttributeNames.Compression, ExrConstants.AttibuteTypes.Compression, 1);
stream.WriteByte((byte)compression);
}
+ ///
+ /// Writes the pixel aspect ratio to the stream.
+ ///
+ /// The stream to write to.
+ /// The aspect ratio.
private void WritePixelAspectRatio(Stream stream, float aspectRatio)
{
this.WriteAttributeInformation(stream, ExrConstants.AttributeNames.PixelAspectRatio, ExrConstants.AttibuteTypes.Float, 4);
this.WriteSingle(stream, aspectRatio);
}
+ ///
+ /// Writes the line order to the stream.
+ ///
+ /// The stream to write to.
+ /// The line order.
private void WriteLineOrder(Stream stream, ExrLineOrder lineOrder)
{
this.WriteAttributeInformation(stream, ExrConstants.AttributeNames.LineOrder, ExrConstants.AttibuteTypes.LineOrder, 1);
stream.WriteByte((byte)lineOrder);
}
+ ///
+ /// Writes the screen window center to the stream.
+ ///
+ /// The stream to write to.
+ /// The screen window center.
private void WriteScreenWindowCenter(Stream stream, PointF screenWindowCenter)
{
this.WriteAttributeInformation(stream, ExrConstants.AttributeNames.ScreenWindowCenter, ExrConstants.AttibuteTypes.TwoFloat, 8);
@@ -454,24 +567,46 @@ internal sealed class ExrEncoderCore
this.WriteSingle(stream, screenWindowCenter.Y);
}
+ ///
+ /// Writes the screen width to the stream.
+ ///
+ /// The stream to write to.
+ /// Width of the screen window.
private void WriteScreenWindowWidth(Stream stream, float screenWindowWidth)
{
this.WriteAttributeInformation(stream, ExrConstants.AttributeNames.ScreenWindowWidth, ExrConstants.AttibuteTypes.Float, 4);
this.WriteSingle(stream, screenWindowWidth);
}
+ ///
+ /// Writes the data window to the stream.
+ ///
+ /// The stream to write to.
+ /// The data window.
private void WriteDataWindow(Stream stream, ExrBox2i dataWindow)
{
this.WriteAttributeInformation(stream, ExrConstants.AttributeNames.DataWindow, ExrConstants.AttibuteTypes.BoxInt, 16);
this.WriteBoxInteger(stream, dataWindow);
}
+ ///
+ /// Writes the display window to the stream.
+ ///
+ /// The stream to write to.
+ /// The display window.
private void WriteDisplayWindow(Stream stream, ExrBox2i displayWindow)
{
this.WriteAttributeInformation(stream, ExrConstants.AttributeNames.DisplayWindow, ExrConstants.AttibuteTypes.BoxInt, 16);
this.WriteBoxInteger(stream, displayWindow);
}
+ ///
+ /// Writes attribute information to the stream.
+ ///
+ /// The stream to write to.
+ /// The name of the attribute.
+ /// The type of the attribute.
+ /// The size in bytes of the attribute.
private void WriteAttributeInformation(Stream stream, string name, string type, int size)
{
// Write attribute name.
@@ -485,27 +620,11 @@ internal sealed class ExrEncoderCore
stream.Write(this.buffer.AsSpan(0, 4));
}
- private void WriteChannelInfo(Stream stream, ExrChannelInfo channelInfo)
- {
- WriteString(stream, channelInfo.ChannelName);
-
- BinaryPrimitives.WriteInt32LittleEndian(this.buffer, (int)channelInfo.PixelType);
- stream.Write(this.buffer.AsSpan(0, 4));
-
- 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));
-
- BinaryPrimitives.WriteInt32LittleEndian(this.buffer, channelInfo.YSampling);
- stream.Write(this.buffer.AsSpan(0, 4));
- }
-
+ ///
+ /// Writes a string to the stream.
+ ///
+ /// The stream to write to.
+ /// The string to write.
private static void WriteString(Stream stream, string str)
{
foreach (char c in str)
@@ -517,6 +636,11 @@ internal sealed class ExrEncoderCore
stream.WriteByte(0);
}
+ ///
+ /// Writes box struct with xmin, xmax, ymin and y max to the stream.
+ ///
+ /// The stream to write to.
+ /// The box to write.
private void WriteBoxInteger(Stream stream, ExrBox2i box)
{
BinaryPrimitives.WriteInt32LittleEndian(this.buffer, box.XMin);
@@ -532,6 +656,11 @@ internal sealed class ExrEncoderCore
stream.Write(this.buffer.AsSpan(0, 4));
}
+ ///
+ /// Writes 32 bit float value to the stream.
+ ///
+ /// The stream to write to.
+ /// The float value to write.
[MethodImpl(InliningOptions.ShortMethod)]
private unsafe void WriteSingle(Stream stream, float value)
{
@@ -539,9 +668,19 @@ internal sealed class ExrEncoderCore
stream.Write(this.buffer.AsSpan(0, 4));
}
+ ///
+ /// Writes a 32 bit float value to a buffer.
+ ///
+ /// The buffer to write to.
+ /// The float value to write.
[MethodImpl(InliningOptions.ShortMethod)]
private static unsafe void WriteSingleToBuffer(Span buffer, float value) => BinaryPrimitives.WriteInt32LittleEndian(buffer, *(int*)&value);
+ ///
+ /// Writes a 16 bit float value to a buffer.
+ ///
+ /// The buffer to write to.
+ /// The float value to write.
[MethodImpl(InliningOptions.ShortMethod)]
private static void WriteHalfSingleToBuffer(Span buffer, float value)
{
@@ -549,6 +688,11 @@ internal sealed class ExrEncoderCore
BinaryPrimitives.WriteUInt16LittleEndian(buffer, valueAsShort);
}
+ ///
+ /// Writes one unsigned int to a buffer.
+ ///
+ /// The buffer to write to.
+ /// The uint value to write.
[MethodImpl(InliningOptions.ShortMethod)]
private static void WriteUnsignedIntToBuffer(Span buffer, uint value) => BinaryPrimitives.WriteUInt32LittleEndian(buffer, value);
}
diff --git a/src/ImageSharp/Formats/Exr/ExrHeaderAttributes.cs b/src/ImageSharp/Formats/Exr/ExrHeaderAttributes.cs
index cdcddd1175..9a6ce7056f 100644
--- a/src/ImageSharp/Formats/Exr/ExrHeaderAttributes.cs
+++ b/src/ImageSharp/Formats/Exr/ExrHeaderAttributes.cs
@@ -11,6 +11,20 @@ namespace SixLabors.ImageSharp.Formats.Exr;
///
internal class ExrHeaderAttributes
{
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The image channels.
+ /// The compression used.
+ /// The data window.
+ /// The display window.
+ /// The line order.
+ /// The aspect ratio.
+ /// Width of the screen window.
+ /// The screen window center.
+ /// Size of the tile in x dimension.
+ /// Size of the tile in y dimension.
+ /// The chunk count.
public ExrHeaderAttributes(
IList channels,
ExrCompression compression,