Skip to content

Commit 15701e5

Browse files
committed
Write alpha channel when encoding exr images
1 parent 3722997 commit 15701e5

File tree

1 file changed

+33
-10
lines changed

1 file changed

+33
-10
lines changed

src/ImageSharp/Formats/Exr/ExrEncoderCore.cs

Lines changed: 33 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ public void Encode<TPixel>(Image<TPixel> image, Stream stream, CancellationToken
9090
int screenWindowWidth = 1;
9191
List<ExrChannelInfo> channels =
9292
[
93+
new(ExrConstants.ChannelNames.Alpha, this.pixelType.Value, 0, 1, 1),
9394
new(ExrConstants.ChannelNames.Blue, this.pixelType.Value, 0, 1, 1),
9495
new(ExrConstants.ChannelNames.Green, this.pixelType.Value, 0, 1, 1),
9596
new(ExrConstants.ChannelNames.Red, this.pixelType.Value, 0, 1, 1),
@@ -160,11 +161,12 @@ private ulong[] EncodeFloatingPointPixelData<TPixel>(
160161
uint rowsPerBlock = ExrUtils.RowsPerBlock(compression);
161162
uint bytesPerBlock = bytesPerRow * rowsPerBlock;
162163

163-
using IMemoryOwner<float> rgbBuffer = this.memoryAllocator.Allocate<float>(width * 3, AllocationOptions.Clean);
164+
using IMemoryOwner<float> rgbBuffer = this.memoryAllocator.Allocate<float>(width * 4, AllocationOptions.Clean);
164165
using IMemoryOwner<byte> rowBlockBuffer = this.memoryAllocator.Allocate<byte>((int)bytesPerBlock, AllocationOptions.Clean);
165166
Span<float> redBuffer = rgbBuffer.GetSpan()[..width];
166167
Span<float> greenBuffer = rgbBuffer.GetSpan().Slice(width, width);
167168
Span<float> blueBuffer = rgbBuffer.GetSpan().Slice(width * 2, width);
169+
Span<float> alphaBuffer = rgbBuffer.GetSpan().Slice(width * 3, width);
168170

169171
using ExrBaseCompressor compressor = ExrCompressorFactory.Create(compression, this.memoryAllocator, stream, bytesPerBlock, bytesPerRow);
170172

@@ -191,17 +193,18 @@ private ulong[] EncodeFloatingPointPixelData<TPixel>(
191193
redBuffer[x] = vector4.X;
192194
greenBuffer[x] = vector4.Y;
193195
blueBuffer[x] = vector4.Z;
196+
alphaBuffer[x] = vector4.W;
194197
}
195198

196199
// Write pixel data to row block buffer.
197200
Span<byte> rowBlockSpan = rowBlockBuffer.GetSpan().Slice((int)(rowsInBlockCount * bytesPerRow), (int)bytesPerRow);
198201
switch (this.pixelType)
199202
{
200203
case ExrPixelType.Float:
201-
WriteSingleRow(rowBlockSpan, width, blueBuffer, greenBuffer, redBuffer);
204+
WriteSingleRow(rowBlockSpan, width, alphaBuffer, blueBuffer, greenBuffer, redBuffer);
202205
break;
203206
case ExrPixelType.Half:
204-
WriteHalfSingleRow(rowBlockSpan, width, blueBuffer, greenBuffer, redBuffer);
207+
WriteHalfSingleRow(rowBlockSpan, width, alphaBuffer, blueBuffer, greenBuffer, redBuffer);
205208
break;
206209
}
207210

@@ -238,15 +241,16 @@ private ulong[] EncodeUnsignedIntPixelData<TPixel>(
238241
uint rowsPerBlock = ExrUtils.RowsPerBlock(compression);
239242
uint bytesPerBlock = bytesPerRow * rowsPerBlock;
240243

241-
using IMemoryOwner<uint> rgbBuffer = this.memoryAllocator.Allocate<uint>(width * 3, AllocationOptions.Clean);
244+
using IMemoryOwner<uint> rgbBuffer = this.memoryAllocator.Allocate<uint>(width * 4, AllocationOptions.Clean);
242245
using IMemoryOwner<byte> rowBlockBuffer = this.memoryAllocator.Allocate<byte>((int)bytesPerBlock, AllocationOptions.Clean);
243246
Span<uint> redBuffer = rgbBuffer.GetSpan()[..width];
244247
Span<uint> greenBuffer = rgbBuffer.GetSpan().Slice(width, width);
245248
Span<uint> blueBuffer = rgbBuffer.GetSpan().Slice(width * 2, width);
249+
Span<uint> alphaBuffer = rgbBuffer.GetSpan().Slice(width * 3, width);
246250

247251
using ExrBaseCompressor compressor = ExrCompressorFactory.Create(compression, this.memoryAllocator, stream, bytesPerBlock, bytesPerRow);
248252

249-
Rgb96 rgb = default;
253+
Rgba128 rgb = default;
250254
ulong[] rowOffsets = new ulong[height];
251255
for (uint y = 0; y < height; y += rowsPerBlock)
252256
{
@@ -267,16 +271,17 @@ private ulong[] EncodeUnsignedIntPixelData<TPixel>(
267271
for (int x = 0; x < width; x++)
268272
{
269273
Vector4 vector4 = pixelRowSpan[x].ToVector4();
270-
rgb = Rgb96.FromVector4(vector4);
274+
rgb = Rgba128.FromVector4(vector4);
271275

272276
redBuffer[x] = rgb.R;
273277
greenBuffer[x] = rgb.G;
274278
blueBuffer[x] = rgb.B;
279+
alphaBuffer[x] = rgb.A;
275280
}
276281

277282
// Write row data to row block buffer.
278283
Span<byte> rowBlockSpan = rowBlockBuffer.GetSpan().Slice((int)(rowsInBlockCount * bytesPerRow), (int)bytesPerRow);
279-
WriteUnsignedIntRow(rowBlockSpan, width, blueBuffer, greenBuffer, redBuffer);
284+
WriteUnsignedIntRow(rowBlockSpan, width, alphaBuffer, blueBuffer, greenBuffer, redBuffer);
280285
rowsInBlockCount++;
281286
}
282287

@@ -309,9 +314,15 @@ private void WriteHeader(Stream stream, ExrHeaderAttributes header)
309314
stream.WriteByte(0);
310315
}
311316

312-
private static void WriteSingleRow(Span<byte> buffer, int width, Span<float> blueBuffer, Span<float> greenBuffer, Span<float> redBuffer)
317+
private static void WriteSingleRow(Span<byte> buffer, int width, Span<float> alphaBuffer, Span<float> blueBuffer, Span<float> greenBuffer, Span<float> redBuffer)
313318
{
314319
int offset = 0;
320+
for (int x = 0; x < width; x++)
321+
{
322+
WriteSingleToBuffer(buffer.Slice(offset, 4), alphaBuffer[x]);
323+
offset += 4;
324+
}
325+
315326
for (int x = 0; x < width; x++)
316327
{
317328
WriteSingleToBuffer(buffer.Slice(offset, 4), blueBuffer[x]);
@@ -331,9 +342,15 @@ private static void WriteSingleRow(Span<byte> buffer, int width, Span<float> blu
331342
}
332343
}
333344

334-
private static void WriteHalfSingleRow(Span<byte> buffer, int width, Span<float> blueBuffer, Span<float> greenBuffer, Span<float> redBuffer)
345+
private static void WriteHalfSingleRow(Span<byte> buffer, int width, Span<float> alphaBuffer, Span<float> blueBuffer, Span<float> greenBuffer, Span<float> redBuffer)
335346
{
336347
int offset = 0;
348+
for (int x = 0; x < width; x++)
349+
{
350+
WriteHalfSingleToBuffer(buffer.Slice(offset, 2), alphaBuffer[x]);
351+
offset += 2;
352+
}
353+
337354
for (int x = 0; x < width; x++)
338355
{
339356
WriteHalfSingleToBuffer(buffer.Slice(offset, 2), blueBuffer[x]);
@@ -353,9 +370,15 @@ private static void WriteHalfSingleRow(Span<byte> buffer, int width, Span<float>
353370
}
354371
}
355372

356-
private static void WriteUnsignedIntRow(Span<byte> buffer, int width, Span<uint> blueBuffer, Span<uint> greenBuffer, Span<uint> redBuffer)
373+
private static void WriteUnsignedIntRow(Span<byte> buffer, int width, Span<uint> alphaBuffer, Span<uint> blueBuffer, Span<uint> greenBuffer, Span<uint> redBuffer)
357374
{
358375
int offset = 0;
376+
for (int x = 0; x < width; x++)
377+
{
378+
WriteUnsignedIntToBuffer(buffer.Slice(offset, 4), alphaBuffer[x]);
379+
offset += 4;
380+
}
381+
359382
for (int x = 0; x < width; x++)
360383
{
361384
WriteUnsignedIntToBuffer(buffer.Slice(offset, 4), blueBuffer[x]);

0 commit comments

Comments
 (0)