Browse Source

Encode EXR image with HalfSingle pixel data

pull/3096/head
Brian Popow 5 years ago
parent
commit
4cf95a52df
  1. 25
      src/ImageSharp/Formats/ImageExtensions.Save.cs
  2. 3
      src/ImageSharp/Formats/OpenExr/ExrBox2i.cs
  3. 37
      src/ImageSharp/Formats/OpenExr/ExrConstants.cs
  4. 16
      src/ImageSharp/Formats/OpenExr/ExrDecoderCore.cs
  5. 99
      src/ImageSharp/Formats/OpenExr/ExrEncoderCore.cs
  6. 2
      src/ImageSharp/Formats/OpenExr/ExrMetadata.cs
  7. 59
      src/ImageSharp/PixelFormats/PixelImplementations/HalfVector4.cs

25
src/ImageSharp/Formats/ImageExtensions.Save.cs

@ -848,14 +848,13 @@ namespace SixLabors.ImageSharp
encoder ?? source.GetConfiguration().ImageFormatsManager.FindEncoder(TiffFormat.Instance), encoder ?? source.GetConfiguration().ImageFormatsManager.FindEncoder(TiffFormat.Instance),
cancellationToken); cancellationToken);
// foo
/// <summary> /// <summary>
/// Saves the image to the given stream with the Open Exr format. /// Saves the image to the given stream with the Open Exr format.
/// </summary> /// </summary>
/// <param name="source">The image this method extends.</param> /// <param name="source">The image this method extends.</param>
/// <param name="path">The file path to save the image to.</param> /// <param name="path">The file path to save the image to.</param>
/// <exception cref="System.ArgumentNullException">Thrown if the path is null.</exception> /// <exception cref="System.ArgumentNullException">Thrown if the path is null.</exception>
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);
/// <summary> /// <summary>
/// Saves the image to the given stream with the Open Exr format. /// Saves the image to the given stream with the Open Exr format.
@ -864,7 +863,7 @@ namespace SixLabors.ImageSharp
/// <param name="path">The file path to save the image to.</param> /// <param name="path">The file path to save the image to.</param>
/// <exception cref="System.ArgumentNullException">Thrown if the path is null.</exception> /// <exception cref="System.ArgumentNullException">Thrown if the path is null.</exception>
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns> /// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
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);
/// <summary> /// <summary>
/// Saves the image to the given stream with the Open Exr format. /// Saves the image to the given stream with the Open Exr format.
@ -874,8 +873,8 @@ namespace SixLabors.ImageSharp
/// <param name="cancellationToken">The token to monitor for cancellation requests.</param> /// <param name="cancellationToken">The token to monitor for cancellation requests.</param>
/// <exception cref="System.ArgumentNullException">Thrown if the path is null.</exception> /// <exception cref="System.ArgumentNullException">Thrown if the path is null.</exception>
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns> /// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
public static Task SaveAsExrAsync(this Image source, string path, CancellationToken cancellationToken) public static Task SaveAsOpenExrAsync(this Image source, string path, CancellationToken cancellationToken)
=> SaveAsExrAsync(source, path, null, cancellationToken); => SaveAsOpenExrAsync(source, path, null, cancellationToken);
/// <summary> /// <summary>
/// Saves the image to the given stream with the Open Exr format. /// Saves the image to the given stream with the Open Exr format.
@ -884,7 +883,7 @@ namespace SixLabors.ImageSharp
/// <param name="path">The file path to save the image to.</param> /// <param name="path">The file path to save the image to.</param>
/// <param name="encoder">The encoder to save the image with.</param> /// <param name="encoder">The encoder to save the image with.</param>
/// <exception cref="System.ArgumentNullException">Thrown if the path is null.</exception> /// <exception cref="System.ArgumentNullException">Thrown if the path is null.</exception>
public static void SaveAsExr(this Image source, string path, ExrEncoder encoder) => public static void SaveAsOpenExr(this Image source, string path, ExrEncoder encoder) =>
source.Save( source.Save(
path, path,
encoder ?? source.GetConfiguration().ImageFormatsManager.FindEncoder(ExrFormat.Instance)); encoder ?? source.GetConfiguration().ImageFormatsManager.FindEncoder(ExrFormat.Instance));
@ -898,7 +897,7 @@ namespace SixLabors.ImageSharp
/// <param name="cancellationToken">The token to monitor for cancellation requests.</param> /// <param name="cancellationToken">The token to monitor for cancellation requests.</param>
/// <exception cref="System.ArgumentNullException">Thrown if the path is null.</exception> /// <exception cref="System.ArgumentNullException">Thrown if the path is null.</exception>
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns> /// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
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( source.SaveAsync(
path, path,
encoder ?? source.GetConfiguration().ImageFormatsManager.FindEncoder(ExrFormat.Instance), encoder ?? source.GetConfiguration().ImageFormatsManager.FindEncoder(ExrFormat.Instance),
@ -910,8 +909,8 @@ namespace SixLabors.ImageSharp
/// <param name="source">The image this method extends.</param> /// <param name="source">The image this method extends.</param>
/// <param name="stream">The stream to save the image to.</param> /// <param name="stream">The stream to save the image to.</param>
/// <exception cref="System.ArgumentNullException">Thrown if the stream is null.</exception> /// <exception cref="System.ArgumentNullException">Thrown if the stream is null.</exception>
public static void SaveAsExr(this Image source, Stream stream) public static void SaveAsOpenExr(this Image source, Stream stream)
=> SaveAsExr(source, stream, null); => SaveAsOpenExr(source, stream, null);
/// <summary> /// <summary>
/// Saves the image to the given stream with the Open Exr format. /// Saves the image to the given stream with the Open Exr format.
@ -921,8 +920,8 @@ namespace SixLabors.ImageSharp
/// <param name="cancellationToken">The token to monitor for cancellation requests.</param> /// <param name="cancellationToken">The token to monitor for cancellation requests.</param>
/// <exception cref="System.ArgumentNullException">Thrown if the stream is null.</exception> /// <exception cref="System.ArgumentNullException">Thrown if the stream is null.</exception>
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns> /// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
public static Task SaveAsExrAsync(this Image source, Stream stream, CancellationToken cancellationToken = default) public static Task SaveAsOpenExrAsync(this Image source, Stream stream, CancellationToken cancellationToken = default)
=> SaveAsExrAsync(source, stream, null, cancellationToken); => SaveAsOpenExrAsync(source, stream, null, cancellationToken);
/// <summary> /// <summary>
/// Saves the image to the given stream with the Open Exr format. /// Saves the image to the given stream with the Open Exr format.
@ -932,7 +931,7 @@ namespace SixLabors.ImageSharp
/// <param name="encoder">The encoder to save the image with.</param> /// <param name="encoder">The encoder to save the image with.</param>
/// <exception cref="System.ArgumentNullException">Thrown if the stream is null.</exception> /// <exception cref="System.ArgumentNullException">Thrown if the stream is null.</exception>
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns> /// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
public static void SaveAsExr(this Image source, Stream stream, ExrEncoder encoder) public static void SaveAsOpenExr(this Image source, Stream stream, ExrEncoder encoder)
=> source.Save( => source.Save(
stream, stream,
encoder ?? source.GetConfiguration().ImageFormatsManager.FindEncoder(ExrFormat.Instance)); encoder ?? source.GetConfiguration().ImageFormatsManager.FindEncoder(ExrFormat.Instance));
@ -946,7 +945,7 @@ namespace SixLabors.ImageSharp
/// <param name="cancellationToken">The token to monitor for cancellation requests.</param> /// <param name="cancellationToken">The token to monitor for cancellation requests.</param>
/// <exception cref="System.ArgumentNullException">Thrown if the stream is null.</exception> /// <exception cref="System.ArgumentNullException">Thrown if the stream is null.</exception>
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns> /// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
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( source.SaveAsync(
stream, stream,
encoder ?? source.GetConfiguration().ImageFormatsManager.FindEncoder(ExrFormat.Instance), encoder ?? source.GetConfiguration().ImageFormatsManager.FindEncoder(ExrFormat.Instance),

3
src/ImageSharp/Formats/OpenExr/ExrBox2i.cs

@ -1,8 +1,11 @@
// Copyright (c) Six Labors. // Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
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 internal struct ExrBox2i
{ {
public ExrBox2i(int xMin, int yMin, int xMax, int yMax) public ExrBox2i(int xMin, int yMin, int xMax, int yMax)

37
src/ImageSharp/Formats/OpenExr/ExrConstants.cs

@ -24,5 +24,42 @@ namespace SixLabors.ImageSharp.Formats.OpenExr
/// The magick bytes identifying an OpenExr image. /// The magick bytes identifying an OpenExr image.
/// </summary> /// </summary>
public static readonly int MagickBytes = 20000630; public static readonly int MagickBytes = 20000630;
/// <summary>
/// EXR attribute names.
/// </summary>
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";
}
} }
} }

16
src/ImageSharp/Formats/OpenExr/ExrDecoderCore.cs

@ -381,35 +381,35 @@ namespace SixLabors.ImageSharp.Formats.OpenExr
{ {
switch (attribute.Name) switch (attribute.Name)
{ {
case "channels": case ExrConstants.AttributeNames.Channels:
IList<ExrChannelInfo> channels = this.ReadChannelList(stream, attribute.Length); IList<ExrChannelInfo> channels = this.ReadChannelList(stream, attribute.Length);
header.Channels = channels; header.Channels = channels;
break; break;
case "compression": case ExrConstants.AttributeNames.Compression:
header.Compression = (ExrCompression)stream.ReadByte(); header.Compression = (ExrCompression)stream.ReadByte();
break; break;
case "dataWindow": case ExrConstants.AttributeNames.DataWindow:
ExrBox2i dataWindow = this.ReadBox2i(stream); ExrBox2i dataWindow = this.ReadBox2i(stream);
header.DataWindow = dataWindow; header.DataWindow = dataWindow;
break; break;
case "displayWindow": case ExrConstants.AttributeNames.DisplayWindow:
ExrBox2i displayWindow = this.ReadBox2i(stream); ExrBox2i displayWindow = this.ReadBox2i(stream);
header.DisplayWindow = displayWindow; header.DisplayWindow = displayWindow;
break; break;
case "lineOrder": case ExrConstants.AttributeNames.LineOrder:
var lineOrder = (ExrLineOrder)stream.ReadByte(); var lineOrder = (ExrLineOrder)stream.ReadByte();
header.LineOrder = lineOrder; header.LineOrder = lineOrder;
break; break;
case "pixelAspectRatio": case ExrConstants.AttributeNames.PixelAspectRatio:
float aspectRatio = stream.ReadSingle(this.buffer); float aspectRatio = stream.ReadSingle(this.buffer);
header.AspectRatio = aspectRatio; header.AspectRatio = aspectRatio;
break; break;
case "screenWindowCenter": case ExrConstants.AttributeNames.ScreenWindowCenter:
float screenWindowCenterX = stream.ReadSingle(this.buffer); float screenWindowCenterX = stream.ReadSingle(this.buffer);
float screenWindowCenterY = stream.ReadSingle(this.buffer); float screenWindowCenterY = stream.ReadSingle(this.buffer);
header.ScreenWindowCenter = new PointF(screenWindowCenterX, screenWindowCenterY); header.ScreenWindowCenter = new PointF(screenWindowCenterX, screenWindowCenterY);
break; break;
case "screenWindowWidth": case ExrConstants.AttributeNames.ScreenWindowWidth:
float screenWindowWidth = stream.ReadSingle(this.buffer); float screenWindowWidth = stream.ReadSingle(this.buffer);
header.ScreenWindowWidth = screenWindowWidth; header.ScreenWindowWidth = screenWindowWidth;
break; break;

99
src/ImageSharp/Formats/OpenExr/ExrEncoderCore.cs

@ -7,7 +7,6 @@ using System.Buffers.Binary;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Threading; using System.Threading;
using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.Metadata; using SixLabors.ImageSharp.Metadata;
using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
@ -29,11 +28,6 @@ namespace SixLabors.ImageSharp.Formats.OpenExr
/// </summary> /// </summary>
private readonly MemoryAllocator memoryAllocator; private readonly MemoryAllocator memoryAllocator;
/// <summary>
/// The global configuration.
/// </summary>
private Configuration configuration;
/// <summary> /// <summary>
/// The pixel type of the image. /// The pixel type of the image.
/// </summary> /// </summary>
@ -63,14 +57,11 @@ namespace SixLabors.ImageSharp.Formats.OpenExr
Guard.NotNull(image, nameof(image)); Guard.NotNull(image, nameof(image));
Guard.NotNull(stream, nameof(stream)); Guard.NotNull(stream, nameof(stream));
this.configuration = image.GetConfiguration();
ImageMetadata metadata = image.Metadata; ImageMetadata metadata = image.Metadata;
ExrMetadata exrMetadata = metadata.GetExrMetadata(); ExrMetadata exrMetadata = metadata.GetExrMetadata();
this.pixelType ??= exrMetadata.PixelType; this.pixelType ??= exrMetadata.PixelType;
int width = image.Width; int width = image.Width;
int height = image.Height; int height = image.Height;
ExrPixelType pixelType = ExrPixelType.Float;
var header = new ExrHeader() var header = new ExrHeader()
{ {
Compression = ExrCompression.None, Compression = ExrCompression.None,
@ -82,9 +73,9 @@ namespace SixLabors.ImageSharp.Formats.OpenExr
ScreenWindowWidth = 1, ScreenWindowWidth = 1,
Channels = new List<ExrChannelInfo>() Channels = new List<ExrChannelInfo>()
{ {
new("B", pixelType, 0, 1, 1), new("B", this.pixelType.Value, 0, 1, 1),
new("G", pixelType, 0, 1, 1), new("G", this.pixelType.Value, 0, 1, 1),
new("R", pixelType, 0, 1, 1), new("R", this.pixelType.Value, 0, 1, 1),
} }
}; };
@ -112,7 +103,9 @@ namespace SixLabors.ImageSharp.Formats.OpenExr
Span<float> greenBuffer = rgbBuffer.GetSpan().Slice(width * 2, width); Span<float> greenBuffer = rgbBuffer.GetSpan().Slice(width * 2, width);
// Write offsets to each pixel row. // 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); this.WriteRowOffsets(stream, height, rowSizeBytes);
for (int y = 0; y < height; y++) for (int y = 0; y < height; y++)
{ {
@ -134,6 +127,33 @@ namespace SixLabors.ImageSharp.Formats.OpenExr
BinaryPrimitives.WriteUInt32LittleEndian(this.buffer, rowSizeBytes); BinaryPrimitives.WriteUInt32LittleEndian(this.buffer, rowSizeBytes);
stream.Write(this.buffer.AsSpan(0, 4)); 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;
}
}
}
private void WriteHeader(Stream stream, ExrHeader 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++) for (int x = 0; x < width; x++)
{ {
this.WriteSingle(stream, blueBuffer[x]); this.WriteSingle(stream, blueBuffer[x]);
@ -149,19 +169,23 @@ namespace SixLabors.ImageSharp.Formats.OpenExr
this.WriteSingle(stream, redBuffer[x]); this.WriteSingle(stream, redBuffer[x]);
} }
} }
private void WriteHalfSingleRow(Stream stream, int width, Span<float> blueBuffer, Span<float> greenBuffer, Span<float> redBuffer)
{
for (int x = 0; x < width; x++)
{
this.WriteHalfSingle(stream, blueBuffer[x]);
} }
private void WriteHeader(Stream stream, ExrHeader header) for (int x = 0; x < width; x++)
{ {
this.WriteChannels(stream, header.Channels); this.WriteHalfSingle(stream, greenBuffer[x]);
this.WriteCompression(stream, header.Compression.Value); }
this.WriteDataWindow(stream, header.DataWindow.Value);
this.WriteDisplayWindow(stream, header.DisplayWindow.Value); for (int x = 0; x < width; x++)
this.WritePixelAspectRatio(stream, header.AspectRatio.Value); {
this.WriteLineOrder(stream, header.LineOrder.Value); this.WriteHalfSingle(stream, redBuffer[x]);
this.WriteScreenWindowCenter(stream, header.ScreenWindowCenter.Value); }
this.WriteScreenWindowWidth(stream, header.ScreenWindowWidth.Value);
stream.WriteByte(0);
} }
private void WriteRowOffsets(Stream stream, int height, uint rowSizeBytes) private void WriteRowOffsets(Stream stream, int height, uint rowSizeBytes)
@ -187,7 +211,7 @@ namespace SixLabors.ImageSharp.Formats.OpenExr
// Last zero byte. // Last zero byte.
attributeSize++; attributeSize++;
this.WriteAttributeInformation(stream, "channels", "chlist", attributeSize); this.WriteAttributeInformation(stream, ExrConstants.AttributeNames.Channels, ExrConstants.AttibuteTypes.ChannelList, attributeSize);
foreach (ExrChannelInfo channelInfo in channels) foreach (ExrChannelInfo channelInfo in channels)
{ {
@ -200,45 +224,45 @@ namespace SixLabors.ImageSharp.Formats.OpenExr
private void WriteCompression(Stream stream, ExrCompression compression) 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); stream.WriteByte((byte)compression);
} }
private void WritePixelAspectRatio(Stream stream, float aspectRatio) 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); this.WriteSingle(stream, aspectRatio);
} }
private void WriteLineOrder(Stream stream, ExrLineOrder lineOrder) 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); stream.WriteByte((byte)lineOrder);
} }
private void WriteScreenWindowCenter(Stream stream, PointF screenWindowCenter) 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.X);
this.WriteSingle(stream, screenWindowCenter.Y); this.WriteSingle(stream, screenWindowCenter.Y);
} }
private void WriteScreenWindowWidth(Stream stream, float screenWindowWidth) 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); this.WriteSingle(stream, screenWindowWidth);
} }
private void WriteDataWindow(Stream stream, ExrBox2i dataWindow) private void WriteDataWindow(Stream stream, ExrBox2i dataWindow)
{ {
this.WriteAttributeInformation(stream, "dataWindow", "box2i", 16); this.WriteAttributeInformation(stream, ExrConstants.AttributeNames.DataWindow, ExrConstants.AttibuteTypes.BoxInt, 16);
this.WriteBox2i(stream, dataWindow); this.WriteBoxInteger(stream, dataWindow);
} }
private void WriteDisplayWindow(Stream stream, ExrBox2i displayWindow) private void WriteDisplayWindow(Stream stream, ExrBox2i displayWindow)
{ {
this.WriteAttributeInformation(stream, "displayWindow", "box2i", 16); this.WriteAttributeInformation(stream, ExrConstants.AttributeNames.DisplayWindow, ExrConstants.AttibuteTypes.BoxInt, 16);
this.WriteBox2i(stream, displayWindow); this.WriteBoxInteger(stream, displayWindow);
} }
private void WriteAttributeInformation(Stream stream, string name, string type, int size) private void WriteAttributeInformation(Stream stream, string name, string type, int size)
@ -286,7 +310,7 @@ namespace SixLabors.ImageSharp.Formats.OpenExr
stream.WriteByte(0); stream.WriteByte(0);
} }
private void WriteBox2i(Stream stream, ExrBox2i box) private void WriteBoxInteger(Stream stream, ExrBox2i box)
{ {
BinaryPrimitives.WriteInt32LittleEndian(this.buffer, box.XMin); BinaryPrimitives.WriteInt32LittleEndian(this.buffer, box.XMin);
stream.Write(this.buffer.AsSpan(0, 4)); stream.Write(this.buffer.AsSpan(0, 4));
@ -306,5 +330,12 @@ namespace SixLabors.ImageSharp.Formats.OpenExr
BinaryPrimitives.WriteInt32LittleEndian(this.buffer, *(int*)&value); BinaryPrimitives.WriteInt32LittleEndian(this.buffer, *(int*)&value);
stream.Write(this.buffer.AsSpan(0, 4)); 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));
}
} }
} }

2
src/ImageSharp/Formats/OpenExr/ExrMetadata.cs

@ -24,7 +24,7 @@ namespace SixLabors.ImageSharp.Formats.OpenExr
/// <summary> /// <summary>
/// Gets or sets the pixel format. /// Gets or sets the pixel format.
/// </summary> /// </summary>
public ExrPixelType PixelType { get; set; } = ExrPixelType.Half; public ExrPixelType PixelType { get; set; } = ExrPixelType.Float;
/// <inheritdoc/> /// <inheritdoc/>
public IDeepCloneable DeepClone() => new ExrMetadata(this); public IDeepCloneable DeepClone() => new ExrMetadata(this);

59
src/ImageSharp/PixelFormats/PixelImplementations/HalfVector4.cs

@ -4,7 +4,6 @@
using System; using System;
using System.Numerics; using System.Numerics;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace SixLabors.ImageSharp.PixelFormats 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. /// Ranges from [-1, -1, -1, -1] to [1, 1, 1, 1] in vector form.
/// </para> /// </para>
/// </summary> /// </summary>
[StructLayout(LayoutKind.Sequential)]
public partial struct HalfVector4 : IPixel<HalfVector4>, IPackedVector<ulong> public partial struct HalfVector4 : IPixel<HalfVector4>, IPackedVector<ulong>
{ {
/// <summary>
/// Gets or sets the red component.
/// </summary>
public float R;
/// <summary>
/// Gets or sets the green component.
/// </summary>
public float G;
/// <summary>
/// Gets or sets the blue component.
/// </summary>
public float B;
/// <summary>
/// Gets or sets the alpha component.
/// </summary>
public float A;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="HalfVector4"/> struct. /// Initializes a new instance of the <see cref="HalfVector4"/> struct.
/// </summary> /// </summary>
@ -45,43 +23,18 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <param name="z">The z-component.</param> /// <param name="z">The z-component.</param>
/// <param name="w">The w-component.</param> /// <param name="w">The w-component.</param>
public HalfVector4(float x, float y, float z, float w) 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;
} }
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="HalfVector4"/> struct. /// Initializes a new instance of the <see cref="HalfVector4"/> struct.
/// </summary> /// </summary>
/// <param name="vector">A vector containing the initial values for the components</param> /// <param name="vector">A vector containing the initial values for the components</param>
public HalfVector4(Vector4 vector) public HalfVector4(Vector4 vector) => this.PackedValue = Pack(ref vector);
{
this.R = vector.X;
this.G = vector.Y;
this.B = vector.Z;
this.A = vector.W;
}
/// <summary>
/// Gets or sets the packed representation of the HalfVector4 struct.
/// </summary>
public ulong HalfVector
{
[MethodImpl(InliningOptions.ShortMethod)]
readonly get => Unsafe.As<HalfVector4, ulong>(ref Unsafe.AsRef(this));
[MethodImpl(InliningOptions.ShortMethod)]
set => Unsafe.As<HalfVector4, ulong>(ref this) = value;
}
/// <inheritdoc/> /// <inheritdoc/>
public ulong PackedValue public ulong PackedValue { get; set; }
{
readonly get => this.HalfVector;
set => this.HalfVector = value;
}
/// <summary> /// <summary>
/// Compares two <see cref="HalfVector4"/> objects for equality. /// Compares two <see cref="HalfVector4"/> objects for equality.
@ -133,7 +86,11 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)] [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)));
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]

Loading…
Cancel
Save