Browse Source

Decode EXR images with 32 bit float pixel data

pull/3096/head
Brian Popow 4 years ago
parent
commit
d3993f7bc0
  1. 2
      src/ImageSharp/Formats/OpenExr/ExrCompression.cs
  2. 72
      src/ImageSharp/Formats/OpenExr/ExrDecoderCore.cs

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

@ -3,7 +3,7 @@
namespace SixLabors.ImageSharp.Formats.OpenExr
{
internal enum ExrCompression : int
internal enum ExrCompression
{
None = 0
}

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

@ -66,19 +66,25 @@ namespace SixLabors.ImageSharp.Formats.OpenExr
private IList<ExrChannelInfo> Channels { get; set; }
private ExrCompression Compression { get; set; }
/// <inheritdoc />
public Image<TPixel> Decode<TPixel>(BufferedReadStream stream, CancellationToken cancellationToken)
where TPixel : unmanaged, IPixel<TPixel>
{
ExrHeader header = this.ReadExrHeader(stream);
if (this.Compression != ExrCompression.None)
{
ExrThrowHelper.ThrowNotSupported("Only uncompressed EXR images are supported");
}
int bitsPerPixel = CalculateBitsPerPixel(header.Channels);
var image = new Image<TPixel>(this.Configuration, this.Width, this.Height, this.metadata);
Buffer2D<TPixel> pixels = image.GetRootFramePixelBuffer();
// TODO: we for now assume the image pixel type is HalfSingle.
using IMemoryOwner<float> rowBuffer = this.memoryAllocator.Allocate<float>(this.Width * 3);
Span<float> redPixelData = rowBuffer.GetSpan().Slice(0, this.Width);
Span<float> bluePixelData = rowBuffer.GetSpan().Slice(this.Width, this.Width);
@ -102,36 +108,52 @@ namespace SixLabors.ImageSharp.Formats.OpenExr
for (int channelIdx = 0; channelIdx < this.Channels.Count; channelIdx++)
{
switch (this.Channels[channelIdx].ChannelName)
ExrChannelInfo channel = this.Channels[channelIdx];
switch (channel.ChannelName)
{
case "R":
for (int x = 0; x < this.Width; x++)
switch (channel.PixelType)
{
redPixelData[x] = stream.ReadHalfSingle(this.buffer);
case ExrPixelType.Half:
this.ReadPixelRowChannelHalfSingle(stream, redPixelData);
break;
case ExrPixelType.Float:
this.ReadPixelRowChannelSingle(stream, redPixelData);
break;
}
break;
case "B":
for (int x = 0; x < this.Width; x++)
switch (channel.PixelType)
{
bluePixelData[x] = stream.ReadHalfSingle(this.buffer);
case ExrPixelType.Half:
this.ReadPixelRowChannelHalfSingle(stream, bluePixelData);
break;
case ExrPixelType.Float:
this.ReadPixelRowChannelSingle(stream, bluePixelData);
break;
}
break;
case "G":
for (int x = 0; x < this.Width; x++)
switch (channel.PixelType)
{
greenPixelData[x] = stream.ReadHalfSingle(this.buffer);
case ExrPixelType.Half:
this.ReadPixelRowChannelHalfSingle(stream, greenPixelData);
break;
case ExrPixelType.Float:
this.ReadPixelRowChannelSingle(stream, greenPixelData);
break;
}
break;
default:
// Skip unknown channel.
// TODO: can we assume the same data size as the others here?
stream.Position += this.Width * 2;
int channelDataSizeInBytes = channel.PixelType is ExrPixelType.Float or ExrPixelType.Uint ? 4 : 2;
stream.Position += this.Width * channelDataSizeInBytes;
break;
}
}
@ -149,6 +171,22 @@ namespace SixLabors.ImageSharp.Formats.OpenExr
return image;
}
private void ReadPixelRowChannelHalfSingle(BufferedReadStream stream, Span<float> channelData)
{
for (int x = 0; x < this.Width; x++)
{
channelData[x] = stream.ReadHalfSingle(this.buffer);
}
}
private void ReadPixelRowChannelSingle(BufferedReadStream stream, Span<float> channelData)
{
for (int x = 0; x < this.Width; x++)
{
channelData[x] = stream.ReadSingle(this.buffer);
}
}
/// <inheritdoc />
public IImageInfo Identify(BufferedReadStream stream, CancellationToken cancellationToken)
{
@ -182,14 +220,10 @@ namespace SixLabors.ImageSharp.Formats.OpenExr
ExrThrowHelper.ThrowInvalidImageHeader();
}
if (header.Channels.Count != 3)
{
ExrThrowHelper.ThrowNotSupported("Only 3 channels are supported!");
}
this.Width = header.DataWindow.Value.xMax - header.DataWindow.Value.xMin + 1;
this.Height = header.DataWindow.Value.yMax - header.DataWindow.Value.yMin + 1;
this.Channels = header.Channels;
this.Compression = header.Compression.GetValueOrDefault();
this.metadata = new ImageMetadata();
@ -210,13 +244,7 @@ namespace SixLabors.ImageSharp.Formats.OpenExr
header.Channels = channels;
break;
case "compression":
var compression = (ExrCompression)stream.ReadByte();
if (compression != ExrCompression.None)
{
ExrThrowHelper.ThrowNotSupported("Only uncompressed EXR images are supported");
}
header.Compression = compression;
header.Compression = (ExrCompression)stream.ReadByte();
break;
case "dataWindow":
ExrBox2i dataWindow = this.ReadBox2i(stream);

Loading…
Cancel
Save