diff --git a/src/ImageSharp/Formats/ImageExtensions.Save.cs b/src/ImageSharp/Formats/ImageExtensions.Save.cs
index 315b942c64..55fd00cf95 100644
--- a/src/ImageSharp/Formats/ImageExtensions.Save.cs
+++ b/src/ImageSharp/Formats/ImageExtensions.Save.cs
@@ -848,14 +848,13 @@ namespace SixLabors.ImageSharp
encoder ?? source.GetConfiguration().ImageFormatsManager.FindEncoder(TiffFormat.Instance),
cancellationToken);
- // foo
///
/// Saves the image to the given stream with the Open Exr format.
///
/// The image this method extends.
/// The file path to save the image to.
/// Thrown if the path is null.
- public static void SaveAsExr(this Image source, string path) => SaveAsExr(source, path, null);
+ public static void SaveAsOpenExr(this Image source, string path) => SaveAsOpenExr(source, path, null);
///
/// Saves the image to the given stream with the Open Exr format.
@@ -864,7 +863,7 @@ namespace SixLabors.ImageSharp
/// The file path to save the image to.
/// Thrown if the path is null.
/// A representing the asynchronous operation.
- public static Task SaveAsExrAsync(this Image source, string path) => SaveAsExrAsync(source, path, null);
+ public static Task SaveAsOpenExrAsync(this Image source, string path) => SaveAsOpenExrAsync(source, path, null);
///
/// Saves the image to the given stream with the Open Exr format.
@@ -874,8 +873,8 @@ namespace SixLabors.ImageSharp
/// The token to monitor for cancellation requests.
/// Thrown if the path is null.
/// A representing the asynchronous operation.
- public static Task SaveAsExrAsync(this Image source, string path, CancellationToken cancellationToken)
- => SaveAsExrAsync(source, path, null, cancellationToken);
+ public static Task SaveAsOpenExrAsync(this Image source, string path, CancellationToken cancellationToken)
+ => SaveAsOpenExrAsync(source, path, null, cancellationToken);
///
/// Saves the image to the given stream with the Open Exr format.
@@ -884,7 +883,7 @@ namespace SixLabors.ImageSharp
/// The file path to save the image to.
/// The encoder to save the image with.
/// Thrown if the path is null.
- public static void SaveAsExr(this Image source, string path, ExrEncoder encoder) =>
+ public static void SaveAsOpenExr(this Image source, string path, ExrEncoder encoder) =>
source.Save(
path,
encoder ?? source.GetConfiguration().ImageFormatsManager.FindEncoder(ExrFormat.Instance));
@@ -898,7 +897,7 @@ namespace SixLabors.ImageSharp
/// The token to monitor for cancellation requests.
/// Thrown if the path is null.
/// A representing the asynchronous operation.
- public static Task SaveAsExrAsync(this Image source, string path, ExrEncoder encoder, CancellationToken cancellationToken = default) =>
+ public static Task SaveAsOpenExrAsync(this Image source, string path, ExrEncoder encoder, CancellationToken cancellationToken = default) =>
source.SaveAsync(
path,
encoder ?? source.GetConfiguration().ImageFormatsManager.FindEncoder(ExrFormat.Instance),
@@ -910,8 +909,8 @@ namespace SixLabors.ImageSharp
/// The image this method extends.
/// The stream to save the image to.
/// Thrown if the stream is null.
- public static void SaveAsExr(this Image source, Stream stream)
- => SaveAsExr(source, stream, null);
+ public static void SaveAsOpenExr(this Image source, Stream stream)
+ => SaveAsOpenExr(source, stream, null);
///
/// Saves the image to the given stream with the Open Exr format.
@@ -921,8 +920,8 @@ namespace SixLabors.ImageSharp
/// The token to monitor for cancellation requests.
/// Thrown if the stream is null.
/// A representing the asynchronous operation.
- public static Task SaveAsExrAsync(this Image source, Stream stream, CancellationToken cancellationToken = default)
- => SaveAsExrAsync(source, stream, null, cancellationToken);
+ public static Task SaveAsOpenExrAsync(this Image source, Stream stream, CancellationToken cancellationToken = default)
+ => SaveAsOpenExrAsync(source, stream, null, cancellationToken);
///
/// Saves the image to the given stream with the Open Exr format.
@@ -932,7 +931,7 @@ namespace SixLabors.ImageSharp
/// The encoder to save the image with.
/// Thrown if the stream is null.
/// A representing the asynchronous operation.
- public static void SaveAsExr(this Image source, Stream stream, ExrEncoder encoder)
+ public static void SaveAsOpenExr(this Image source, Stream stream, ExrEncoder encoder)
=> source.Save(
stream,
encoder ?? source.GetConfiguration().ImageFormatsManager.FindEncoder(ExrFormat.Instance));
@@ -946,7 +945,7 @@ namespace SixLabors.ImageSharp
/// The token to monitor for cancellation requests.
/// Thrown if the stream is null.
/// A representing the asynchronous operation.
- public static Task SaveAsExrAsync(this Image source, Stream stream, ExrEncoder encoder, CancellationToken cancellationToken = default) =>
+ public static Task SaveAsOpenExrAsync(this Image source, Stream stream, ExrEncoder encoder, CancellationToken cancellationToken = default) =>
source.SaveAsync(
stream,
encoder ?? source.GetConfiguration().ImageFormatsManager.FindEncoder(ExrFormat.Instance),
diff --git a/src/ImageSharp/Formats/OpenExr/ExrBox2i.cs b/src/ImageSharp/Formats/OpenExr/ExrBox2i.cs
index 6fd610026b..89424b4259 100644
--- a/src/ImageSharp/Formats/OpenExr/ExrBox2i.cs
+++ b/src/ImageSharp/Formats/OpenExr/ExrBox2i.cs
@@ -1,8 +1,11 @@
// Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0.
+using System.Diagnostics;
+
namespace SixLabors.ImageSharp.Formats.OpenExr
{
+ [DebuggerDisplay("xMin: {XMin}, yMin: {YMin}, xMax: {XMax}, yMax: {YMax}")]
internal struct ExrBox2i
{
public ExrBox2i(int xMin, int yMin, int xMax, int yMax)
diff --git a/src/ImageSharp/Formats/OpenExr/ExrConstants.cs b/src/ImageSharp/Formats/OpenExr/ExrConstants.cs
index b3f1a34245..40c34cce23 100644
--- a/src/ImageSharp/Formats/OpenExr/ExrConstants.cs
+++ b/src/ImageSharp/Formats/OpenExr/ExrConstants.cs
@@ -24,5 +24,42 @@ namespace SixLabors.ImageSharp.Formats.OpenExr
/// The magick bytes identifying an OpenExr image.
///
public static readonly int MagickBytes = 20000630;
+
+ ///
+ /// EXR attribute names.
+ ///
+ internal static class AttributeNames
+ {
+ public const string Channels = "channels";
+
+ public const string Compression = "compression";
+
+ public const string DataWindow = "dataWindow";
+
+ public const string DisplayWindow = "displayWindow";
+
+ public const string LineOrder = "lineOrder";
+
+ public const string PixelAspectRatio = "pixelAspectRatio";
+
+ public const string ScreenWindowCenter = "screenWindowCenter";
+
+ public const string ScreenWindowWidth = "screenWindowWidth";
+ }
+
+ internal static class AttibuteTypes
+ {
+ public const string ChannelList = "chlist";
+
+ public const string Compression = "compression";
+
+ public const string Float = "float";
+
+ public const string LineOrder = "lineOrder";
+
+ public const string TwoFloat = "v2f";
+
+ public const string BoxInt = "box2i";
+ }
}
}
diff --git a/src/ImageSharp/Formats/OpenExr/ExrDecoderCore.cs b/src/ImageSharp/Formats/OpenExr/ExrDecoderCore.cs
index b0424857ce..46d3941f36 100644
--- a/src/ImageSharp/Formats/OpenExr/ExrDecoderCore.cs
+++ b/src/ImageSharp/Formats/OpenExr/ExrDecoderCore.cs
@@ -381,35 +381,35 @@ namespace SixLabors.ImageSharp.Formats.OpenExr
{
switch (attribute.Name)
{
- case "channels":
+ case ExrConstants.AttributeNames.Channels:
IList channels = this.ReadChannelList(stream, attribute.Length);
header.Channels = channels;
break;
- case "compression":
+ case ExrConstants.AttributeNames.Compression:
header.Compression = (ExrCompression)stream.ReadByte();
break;
- case "dataWindow":
+ case ExrConstants.AttributeNames.DataWindow:
ExrBox2i dataWindow = this.ReadBox2i(stream);
header.DataWindow = dataWindow;
break;
- case "displayWindow":
+ case ExrConstants.AttributeNames.DisplayWindow:
ExrBox2i displayWindow = this.ReadBox2i(stream);
header.DisplayWindow = displayWindow;
break;
- case "lineOrder":
+ case ExrConstants.AttributeNames.LineOrder:
var lineOrder = (ExrLineOrder)stream.ReadByte();
header.LineOrder = lineOrder;
break;
- case "pixelAspectRatio":
+ case ExrConstants.AttributeNames.PixelAspectRatio:
float aspectRatio = stream.ReadSingle(this.buffer);
header.AspectRatio = aspectRatio;
break;
- case "screenWindowCenter":
+ case ExrConstants.AttributeNames.ScreenWindowCenter:
float screenWindowCenterX = stream.ReadSingle(this.buffer);
float screenWindowCenterY = stream.ReadSingle(this.buffer);
header.ScreenWindowCenter = new PointF(screenWindowCenterX, screenWindowCenterY);
break;
- case "screenWindowWidth":
+ case ExrConstants.AttributeNames.ScreenWindowWidth:
float screenWindowWidth = stream.ReadSingle(this.buffer);
header.ScreenWindowWidth = screenWindowWidth;
break;
diff --git a/src/ImageSharp/Formats/OpenExr/ExrEncoderCore.cs b/src/ImageSharp/Formats/OpenExr/ExrEncoderCore.cs
index 35b381e9be..e3c4376708 100644
--- a/src/ImageSharp/Formats/OpenExr/ExrEncoderCore.cs
+++ b/src/ImageSharp/Formats/OpenExr/ExrEncoderCore.cs
@@ -7,7 +7,6 @@ using System.Buffers.Binary;
using System.Collections.Generic;
using System.IO;
using System.Threading;
-using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.Metadata;
using SixLabors.ImageSharp.PixelFormats;
@@ -29,11 +28,6 @@ namespace SixLabors.ImageSharp.Formats.OpenExr
///
private readonly MemoryAllocator memoryAllocator;
- ///
- /// The global configuration.
- ///
- private Configuration configuration;
-
///
/// The pixel type of the image.
///
@@ -63,14 +57,11 @@ namespace SixLabors.ImageSharp.Formats.OpenExr
Guard.NotNull(image, nameof(image));
Guard.NotNull(stream, nameof(stream));
- this.configuration = image.GetConfiguration();
ImageMetadata metadata = image.Metadata;
ExrMetadata exrMetadata = metadata.GetExrMetadata();
this.pixelType ??= exrMetadata.PixelType;
-
int width = image.Width;
int height = image.Height;
- ExrPixelType pixelType = ExrPixelType.Float;
var header = new ExrHeader()
{
Compression = ExrCompression.None,
@@ -82,9 +73,9 @@ namespace SixLabors.ImageSharp.Formats.OpenExr
ScreenWindowWidth = 1,
Channels = new List()
{
- new("B", pixelType, 0, 1, 1),
- new("G", pixelType, 0, 1, 1),
- new("R", pixelType, 0, 1, 1),
+ new("B", this.pixelType.Value, 0, 1, 1),
+ new("G", this.pixelType.Value, 0, 1, 1),
+ new("R", this.pixelType.Value, 0, 1, 1),
}
};
@@ -112,7 +103,9 @@ namespace SixLabors.ImageSharp.Formats.OpenExr
Span greenBuffer = rgbBuffer.GetSpan().Slice(width * 2, width);
// Write offsets to each pixel row.
- uint rowSizeBytes = (uint)(width * 3 * 4);
+ int bytesPerPixel = this.pixelType == ExrPixelType.Half ? 2 : 4;
+ int numberOfChannels = 3;
+ uint rowSizeBytes = (uint)(width * numberOfChannels * bytesPerPixel);
this.WriteRowOffsets(stream, height, rowSizeBytes);
for (int y = 0; y < height; y++)
{
@@ -134,19 +127,14 @@ namespace SixLabors.ImageSharp.Formats.OpenExr
BinaryPrimitives.WriteUInt32LittleEndian(this.buffer, rowSizeBytes);
stream.Write(this.buffer.AsSpan(0, 4));
- for (int x = 0; x < width; x++)
- {
- this.WriteSingle(stream, blueBuffer[x]);
- }
-
- for (int x = 0; x < width; x++)
+ switch (this.pixelType)
{
- this.WriteSingle(stream, greenBuffer[x]);
- }
-
- for (int x = 0; x < width; x++)
- {
- 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;
}
}
}
@@ -164,6 +152,42 @@ namespace SixLabors.ImageSharp.Formats.OpenExr
stream.WriteByte(0);
}
+ private void WriteSingleRow(Stream stream, int width, Span blueBuffer, Span greenBuffer, Span redBuffer)
+ {
+ for (int x = 0; x < width; x++)
+ {
+ this.WriteSingle(stream, blueBuffer[x]);
+ }
+
+ for (int x = 0; x < width; x++)
+ {
+ this.WriteSingle(stream, greenBuffer[x]);
+ }
+
+ for (int x = 0; x < width; x++)
+ {
+ this.WriteSingle(stream, redBuffer[x]);
+ }
+ }
+
+ private void WriteHalfSingleRow(Stream stream, int width, Span blueBuffer, Span greenBuffer, Span redBuffer)
+ {
+ for (int x = 0; x < width; x++)
+ {
+ this.WriteHalfSingle(stream, blueBuffer[x]);
+ }
+
+ for (int x = 0; x < width; x++)
+ {
+ this.WriteHalfSingle(stream, greenBuffer[x]);
+ }
+
+ for (int x = 0; x < width; x++)
+ {
+ this.WriteHalfSingle(stream, redBuffer[x]);
+ }
+ }
+
private void WriteRowOffsets(Stream stream, int height, uint rowSizeBytes)
{
ulong startOfPixelData = (ulong)stream.Position + (8 * (ulong)height);
@@ -187,7 +211,7 @@ namespace SixLabors.ImageSharp.Formats.OpenExr
// Last zero byte.
attributeSize++;
- this.WriteAttributeInformation(stream, "channels", "chlist", attributeSize);
+ this.WriteAttributeInformation(stream, ExrConstants.AttributeNames.Channels, ExrConstants.AttibuteTypes.ChannelList, attributeSize);
foreach (ExrChannelInfo channelInfo in channels)
{
@@ -200,45 +224,45 @@ namespace SixLabors.ImageSharp.Formats.OpenExr
private void WriteCompression(Stream stream, ExrCompression compression)
{
- this.WriteAttributeInformation(stream, "compression", "compression", 1);
+ this.WriteAttributeInformation(stream, ExrConstants.AttributeNames.Compression, ExrConstants.AttibuteTypes.Compression, 1);
stream.WriteByte((byte)compression);
}
private void WritePixelAspectRatio(Stream stream, float aspectRatio)
{
- this.WriteAttributeInformation(stream, "pixelAspectRatio", "float", 4);
+ this.WriteAttributeInformation(stream, ExrConstants.AttributeNames.PixelAspectRatio, ExrConstants.AttibuteTypes.Float, 4);
this.WriteSingle(stream, aspectRatio);
}
private void WriteLineOrder(Stream stream, ExrLineOrder lineOrder)
{
- this.WriteAttributeInformation(stream, "lineOrder", "lineOrder", 1);
+ this.WriteAttributeInformation(stream, ExrConstants.AttributeNames.LineOrder, ExrConstants.AttibuteTypes.LineOrder, 1);
stream.WriteByte((byte)lineOrder);
}
private void WriteScreenWindowCenter(Stream stream, PointF screenWindowCenter)
{
- this.WriteAttributeInformation(stream, "screenWindowCenter", "v2f", 8);
+ this.WriteAttributeInformation(stream, ExrConstants.AttributeNames.ScreenWindowCenter, ExrConstants.AttibuteTypes.TwoFloat, 8);
this.WriteSingle(stream, screenWindowCenter.X);
this.WriteSingle(stream, screenWindowCenter.Y);
}
private void WriteScreenWindowWidth(Stream stream, float screenWindowWidth)
{
- this.WriteAttributeInformation(stream, "screenWindowWidth", "float", 4);
+ this.WriteAttributeInformation(stream, ExrConstants.AttributeNames.ScreenWindowWidth, ExrConstants.AttibuteTypes.Float, 4);
this.WriteSingle(stream, screenWindowWidth);
}
private void WriteDataWindow(Stream stream, ExrBox2i dataWindow)
{
- this.WriteAttributeInformation(stream, "dataWindow", "box2i", 16);
- this.WriteBox2i(stream, dataWindow);
+ this.WriteAttributeInformation(stream, ExrConstants.AttributeNames.DataWindow, ExrConstants.AttibuteTypes.BoxInt, 16);
+ this.WriteBoxInteger(stream, dataWindow);
}
private void WriteDisplayWindow(Stream stream, ExrBox2i displayWindow)
{
- this.WriteAttributeInformation(stream, "displayWindow", "box2i", 16);
- this.WriteBox2i(stream, displayWindow);
+ this.WriteAttributeInformation(stream, ExrConstants.AttributeNames.DisplayWindow, ExrConstants.AttibuteTypes.BoxInt, 16);
+ this.WriteBoxInteger(stream, displayWindow);
}
private void WriteAttributeInformation(Stream stream, string name, string type, int size)
@@ -286,7 +310,7 @@ namespace SixLabors.ImageSharp.Formats.OpenExr
stream.WriteByte(0);
}
- private void WriteBox2i(Stream stream, ExrBox2i box)
+ private void WriteBoxInteger(Stream stream, ExrBox2i box)
{
BinaryPrimitives.WriteInt32LittleEndian(this.buffer, box.XMin);
stream.Write(this.buffer.AsSpan(0, 4));
@@ -306,5 +330,12 @@ namespace SixLabors.ImageSharp.Formats.OpenExr
BinaryPrimitives.WriteInt32LittleEndian(this.buffer, *(int*)&value);
stream.Write(this.buffer.AsSpan(0, 4));
}
+
+ private void WriteHalfSingle(Stream stream, float value)
+ {
+ ushort valueAsShort = HalfTypeHelper.Pack(value);
+ BinaryPrimitives.WriteUInt16LittleEndian(this.buffer, valueAsShort);
+ stream.Write(this.buffer.AsSpan(0, 2));
+ }
}
}
diff --git a/src/ImageSharp/Formats/OpenExr/ExrMetadata.cs b/src/ImageSharp/Formats/OpenExr/ExrMetadata.cs
index 1e6eaf2bb6..7af01a38f0 100644
--- a/src/ImageSharp/Formats/OpenExr/ExrMetadata.cs
+++ b/src/ImageSharp/Formats/OpenExr/ExrMetadata.cs
@@ -24,7 +24,7 @@ namespace SixLabors.ImageSharp.Formats.OpenExr
///
/// Gets or sets the pixel format.
///
- public ExrPixelType PixelType { get; set; } = ExrPixelType.Half;
+ public ExrPixelType PixelType { get; set; } = ExrPixelType.Float;
///
public IDeepCloneable DeepClone() => new ExrMetadata(this);
diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/HalfVector4.cs b/src/ImageSharp/PixelFormats/PixelImplementations/HalfVector4.cs
index 3d4298d803..94051e263e 100644
--- a/src/ImageSharp/PixelFormats/PixelImplementations/HalfVector4.cs
+++ b/src/ImageSharp/PixelFormats/PixelImplementations/HalfVector4.cs
@@ -4,7 +4,6 @@
using System;
using System.Numerics;
using System.Runtime.CompilerServices;
-using System.Runtime.InteropServices;
namespace SixLabors.ImageSharp.PixelFormats
{
@@ -14,29 +13,8 @@ namespace SixLabors.ImageSharp.PixelFormats
/// Ranges from [-1, -1, -1, -1] to [1, 1, 1, 1] in vector form.
///
///
- [StructLayout(LayoutKind.Sequential)]
public partial struct HalfVector4 : IPixel, IPackedVector
{
- ///
- /// Gets or sets the red component.
- ///
- public float R;
-
- ///
- /// Gets or sets the green component.
- ///
- public float G;
-
- ///
- /// Gets or sets the blue component.
- ///
- public float B;
-
- ///
- /// Gets or sets the alpha component.
- ///
- public float A;
-
///
/// Initializes a new instance of the struct.
///
@@ -45,43 +23,18 @@ namespace SixLabors.ImageSharp.PixelFormats
/// The z-component.
/// The w-component.
public HalfVector4(float x, float y, float z, float w)
+ : this(new Vector4(x, y, z, w))
{
- this.R = x;
- this.G = y;
- this.B = z;
- this.A = w;
}
///
/// Initializes a new instance of the struct.
///
/// A vector containing the initial values for the components
- public HalfVector4(Vector4 vector)
- {
- this.R = vector.X;
- this.G = vector.Y;
- this.B = vector.Z;
- this.A = vector.W;
- }
-
- ///
- /// Gets or sets the packed representation of the HalfVector4 struct.
- ///
- public ulong HalfVector
- {
- [MethodImpl(InliningOptions.ShortMethod)]
- readonly get => Unsafe.As(ref Unsafe.AsRef(this));
-
- [MethodImpl(InliningOptions.ShortMethod)]
- set => Unsafe.As(ref this) = value;
- }
+ public HalfVector4(Vector4 vector) => this.PackedValue = Pack(ref vector);
///
- public ulong PackedValue
- {
- readonly get => this.HalfVector;
- set => this.HalfVector = value;
- }
+ public ulong PackedValue { get; set; }
///
/// Compares two objects for equality.
@@ -133,7 +86,11 @@ namespace SixLabors.ImageSharp.PixelFormats
///
[MethodImpl(InliningOptions.ShortMethod)]
- public readonly Vector4 ToVector4() => new(this.R, this.G, this.B, this.A);
+ public readonly Vector4 ToVector4() => new(
+ HalfTypeHelper.Unpack((ushort)this.PackedValue),
+ HalfTypeHelper.Unpack((ushort)(this.PackedValue >> 0x10)),
+ HalfTypeHelper.Unpack((ushort)(this.PackedValue >> 0x20)),
+ HalfTypeHelper.Unpack((ushort)(this.PackedValue >> 0x30)));
///
[MethodImpl(InliningOptions.ShortMethod)]