Browse Source

Write alpha channel when encoding exr images

pull/3096/head
Brian Popow 4 weeks ago
parent
commit
15701e5e84
  1. 43
      src/ImageSharp/Formats/Exr/ExrEncoderCore.cs

43
src/ImageSharp/Formats/Exr/ExrEncoderCore.cs

@ -90,6 +90,7 @@ internal sealed class ExrEncoderCore
int screenWindowWidth = 1; int screenWindowWidth = 1;
List<ExrChannelInfo> channels = List<ExrChannelInfo> channels =
[ [
new(ExrConstants.ChannelNames.Alpha, this.pixelType.Value, 0, 1, 1),
new(ExrConstants.ChannelNames.Blue, this.pixelType.Value, 0, 1, 1), new(ExrConstants.ChannelNames.Blue, this.pixelType.Value, 0, 1, 1),
new(ExrConstants.ChannelNames.Green, this.pixelType.Value, 0, 1, 1), new(ExrConstants.ChannelNames.Green, this.pixelType.Value, 0, 1, 1),
new(ExrConstants.ChannelNames.Red, this.pixelType.Value, 0, 1, 1), new(ExrConstants.ChannelNames.Red, this.pixelType.Value, 0, 1, 1),
@ -160,11 +161,12 @@ internal sealed class ExrEncoderCore
uint rowsPerBlock = ExrUtils.RowsPerBlock(compression); uint rowsPerBlock = ExrUtils.RowsPerBlock(compression);
uint bytesPerBlock = bytesPerRow * rowsPerBlock; uint bytesPerBlock = bytesPerRow * rowsPerBlock;
using IMemoryOwner<float> rgbBuffer = this.memoryAllocator.Allocate<float>(width * 3, AllocationOptions.Clean); using IMemoryOwner<float> rgbBuffer = this.memoryAllocator.Allocate<float>(width * 4, AllocationOptions.Clean);
using IMemoryOwner<byte> rowBlockBuffer = this.memoryAllocator.Allocate<byte>((int)bytesPerBlock, AllocationOptions.Clean); using IMemoryOwner<byte> rowBlockBuffer = this.memoryAllocator.Allocate<byte>((int)bytesPerBlock, AllocationOptions.Clean);
Span<float> redBuffer = rgbBuffer.GetSpan()[..width]; Span<float> redBuffer = rgbBuffer.GetSpan()[..width];
Span<float> greenBuffer = rgbBuffer.GetSpan().Slice(width, width); Span<float> greenBuffer = rgbBuffer.GetSpan().Slice(width, width);
Span<float> blueBuffer = rgbBuffer.GetSpan().Slice(width * 2, width); Span<float> blueBuffer = rgbBuffer.GetSpan().Slice(width * 2, width);
Span<float> alphaBuffer = rgbBuffer.GetSpan().Slice(width * 3, width);
using ExrBaseCompressor compressor = ExrCompressorFactory.Create(compression, this.memoryAllocator, stream, bytesPerBlock, bytesPerRow); using ExrBaseCompressor compressor = ExrCompressorFactory.Create(compression, this.memoryAllocator, stream, bytesPerBlock, bytesPerRow);
@ -191,6 +193,7 @@ internal sealed class ExrEncoderCore
redBuffer[x] = vector4.X; redBuffer[x] = vector4.X;
greenBuffer[x] = vector4.Y; greenBuffer[x] = vector4.Y;
blueBuffer[x] = vector4.Z; blueBuffer[x] = vector4.Z;
alphaBuffer[x] = vector4.W;
} }
// Write pixel data to row block buffer. // Write pixel data to row block buffer.
@ -198,10 +201,10 @@ internal sealed class ExrEncoderCore
switch (this.pixelType) switch (this.pixelType)
{ {
case ExrPixelType.Float: case ExrPixelType.Float:
WriteSingleRow(rowBlockSpan, width, blueBuffer, greenBuffer, redBuffer); WriteSingleRow(rowBlockSpan, width, alphaBuffer, blueBuffer, greenBuffer, redBuffer);
break; break;
case ExrPixelType.Half: case ExrPixelType.Half:
WriteHalfSingleRow(rowBlockSpan, width, blueBuffer, greenBuffer, redBuffer); WriteHalfSingleRow(rowBlockSpan, width, alphaBuffer, blueBuffer, greenBuffer, redBuffer);
break; break;
} }
@ -238,15 +241,16 @@ internal sealed class ExrEncoderCore
uint rowsPerBlock = ExrUtils.RowsPerBlock(compression); uint rowsPerBlock = ExrUtils.RowsPerBlock(compression);
uint bytesPerBlock = bytesPerRow * rowsPerBlock; uint bytesPerBlock = bytesPerRow * rowsPerBlock;
using IMemoryOwner<uint> rgbBuffer = this.memoryAllocator.Allocate<uint>(width * 3, AllocationOptions.Clean); using IMemoryOwner<uint> rgbBuffer = this.memoryAllocator.Allocate<uint>(width * 4, AllocationOptions.Clean);
using IMemoryOwner<byte> rowBlockBuffer = this.memoryAllocator.Allocate<byte>((int)bytesPerBlock, AllocationOptions.Clean); using IMemoryOwner<byte> rowBlockBuffer = this.memoryAllocator.Allocate<byte>((int)bytesPerBlock, AllocationOptions.Clean);
Span<uint> redBuffer = rgbBuffer.GetSpan()[..width]; Span<uint> redBuffer = rgbBuffer.GetSpan()[..width];
Span<uint> greenBuffer = rgbBuffer.GetSpan().Slice(width, width); Span<uint> greenBuffer = rgbBuffer.GetSpan().Slice(width, width);
Span<uint> blueBuffer = rgbBuffer.GetSpan().Slice(width * 2, width); Span<uint> blueBuffer = rgbBuffer.GetSpan().Slice(width * 2, width);
Span<uint> alphaBuffer = rgbBuffer.GetSpan().Slice(width * 3, width);
using ExrBaseCompressor compressor = ExrCompressorFactory.Create(compression, this.memoryAllocator, stream, bytesPerBlock, bytesPerRow); using ExrBaseCompressor compressor = ExrCompressorFactory.Create(compression, this.memoryAllocator, stream, bytesPerBlock, bytesPerRow);
Rgb96 rgb = default; Rgba128 rgb = default;
ulong[] rowOffsets = new ulong[height]; ulong[] rowOffsets = new ulong[height];
for (uint y = 0; y < height; y += rowsPerBlock) for (uint y = 0; y < height; y += rowsPerBlock)
{ {
@ -267,16 +271,17 @@ internal sealed class ExrEncoderCore
for (int x = 0; x < width; x++) for (int x = 0; x < width; x++)
{ {
Vector4 vector4 = pixelRowSpan[x].ToVector4(); Vector4 vector4 = pixelRowSpan[x].ToVector4();
rgb = Rgb96.FromVector4(vector4); rgb = Rgba128.FromVector4(vector4);
redBuffer[x] = rgb.R; redBuffer[x] = rgb.R;
greenBuffer[x] = rgb.G; greenBuffer[x] = rgb.G;
blueBuffer[x] = rgb.B; blueBuffer[x] = rgb.B;
alphaBuffer[x] = rgb.A;
} }
// Write row data to row block buffer. // Write row data to row block buffer.
Span<byte> rowBlockSpan = rowBlockBuffer.GetSpan().Slice((int)(rowsInBlockCount * bytesPerRow), (int)bytesPerRow); Span<byte> rowBlockSpan = rowBlockBuffer.GetSpan().Slice((int)(rowsInBlockCount * bytesPerRow), (int)bytesPerRow);
WriteUnsignedIntRow(rowBlockSpan, width, blueBuffer, greenBuffer, redBuffer); WriteUnsignedIntRow(rowBlockSpan, width, alphaBuffer, blueBuffer, greenBuffer, redBuffer);
rowsInBlockCount++; rowsInBlockCount++;
} }
@ -309,9 +314,15 @@ internal sealed class ExrEncoderCore
stream.WriteByte(0); stream.WriteByte(0);
} }
private static void WriteSingleRow(Span<byte> buffer, int width, Span<float> blueBuffer, Span<float> greenBuffer, Span<float> redBuffer) private static void WriteSingleRow(Span<byte> buffer, int width, Span<float> alphaBuffer, Span<float> blueBuffer, Span<float> greenBuffer, Span<float> redBuffer)
{ {
int offset = 0; int offset = 0;
for (int x = 0; x < width; x++)
{
WriteSingleToBuffer(buffer.Slice(offset, 4), alphaBuffer[x]);
offset += 4;
}
for (int x = 0; x < width; x++) for (int x = 0; x < width; x++)
{ {
WriteSingleToBuffer(buffer.Slice(offset, 4), blueBuffer[x]); WriteSingleToBuffer(buffer.Slice(offset, 4), blueBuffer[x]);
@ -331,9 +342,15 @@ internal sealed class ExrEncoderCore
} }
} }
private static void WriteHalfSingleRow(Span<byte> buffer, int width, Span<float> blueBuffer, Span<float> greenBuffer, Span<float> redBuffer) private static void WriteHalfSingleRow(Span<byte> buffer, int width, Span<float> alphaBuffer, Span<float> blueBuffer, Span<float> greenBuffer, Span<float> redBuffer)
{ {
int offset = 0; int offset = 0;
for (int x = 0; x < width; x++)
{
WriteHalfSingleToBuffer(buffer.Slice(offset, 2), alphaBuffer[x]);
offset += 2;
}
for (int x = 0; x < width; x++) for (int x = 0; x < width; x++)
{ {
WriteHalfSingleToBuffer(buffer.Slice(offset, 2), blueBuffer[x]); WriteHalfSingleToBuffer(buffer.Slice(offset, 2), blueBuffer[x]);
@ -353,9 +370,15 @@ internal sealed class ExrEncoderCore
} }
} }
private static void WriteUnsignedIntRow(Span<byte> buffer, int width, Span<uint> blueBuffer, Span<uint> greenBuffer, Span<uint> redBuffer) private static void WriteUnsignedIntRow(Span<byte> buffer, int width, Span<uint> alphaBuffer, Span<uint> blueBuffer, Span<uint> greenBuffer, Span<uint> redBuffer)
{ {
int offset = 0; int offset = 0;
for (int x = 0; x < width; x++)
{
WriteUnsignedIntToBuffer(buffer.Slice(offset, 4), alphaBuffer[x]);
offset += 4;
}
for (int x = 0; x < width; x++) for (int x = 0; x < width; x++)
{ {
WriteUnsignedIntToBuffer(buffer.Slice(offset, 4), blueBuffer[x]); WriteUnsignedIntToBuffer(buffer.Slice(offset, 4), blueBuffer[x]);

Loading…
Cancel
Save