Browse Source

Fix issue decoding last row block with zip compression

pull/3096/head
Brian Popow 6 months ago
parent
commit
7cc73d9c15
  1. 14
      src/ImageSharp/Formats/Exr/ExrDecoderCore.cs
  2. 43
      src/ImageSharp/Formats/Exr/ExrEncoderCore.cs

14
src/ImageSharp/Formats/Exr/ExrDecoderCore.cs

@ -149,7 +149,8 @@ internal sealed class ExrDecoderCore : ImageDecoderCore
using ExrBaseDecompressor decompressor = ExrDecompressorFactory.Create(this.Compression, this.memoryAllocator, width, bytesPerBlock, bytesPerRow, rowsPerBlock, channelCount);
for (uint y = 0; y < height; y += rowsPerBlock)
int decodedRows = 0;
while (decodedRows < height)
{
ulong rowOffset = this.ReadUnsignedLong(stream);
long nextRowOffsetPosition = stream.Position;
@ -175,6 +176,8 @@ internal sealed class ExrDecoderCore : ImageDecoderCore
HalfVector4 pixelValue = new(redPixelData[x], greenPixelData[x], bluePixelData[x], hasAlpha ? alphaPixelData[x] : 1.0f);
pixelRow[x] = TPixel.FromVector4(pixelValue.ToVector4());
}
decodedRows++;
}
stream.Position = nextRowOffsetPosition;
@ -202,7 +205,8 @@ internal sealed class ExrDecoderCore : ImageDecoderCore
using ExrBaseDecompressor decompressor = ExrDecompressorFactory.Create(this.Compression, this.memoryAllocator, width, bytesPerBlock, bytesPerRow, rowsPerBlock, channelCount);
for (uint y = 0; y < height; y += rowsPerBlock)
int decodedRows = 0;
while (decodedRows < height)
{
ulong rowOffset = this.ReadUnsignedLong(stream);
long nextRowOffsetPosition = stream.Position;
@ -223,13 +227,15 @@ internal sealed class ExrDecoderCore : ImageDecoderCore
offset += this.ReadUnsignedIntChannelData(stream, channel, decompressedPixelData.Slice(offset), redPixelData, greenPixelData, bluePixelData, alphaPixelData, width);
}
stream.Position = nextRowOffsetPosition;
for (int x = 0; x < width; x++)
{
pixelRow[x] = ColorScaleTo32Bit<TPixel>(redPixelData[x], greenPixelData[x], bluePixelData[x], hasAlpha ? alphaPixelData[x] : uint.MaxValue);
}
decodedRows++;
}
stream.Position = nextRowOffsetPosition;
}
}

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

@ -201,10 +201,10 @@ internal sealed class ExrEncoderCore
switch (this.pixelType)
{
case ExrPixelType.Float:
this.WriteSingleRow(rowBlockSpan, width, blueBuffer, greenBuffer, redBuffer);
WriteSingleRow(rowBlockSpan, width, blueBuffer, greenBuffer, redBuffer);
break;
case ExrPixelType.Half:
this.WriteHalfSingleRow(rowBlockSpan, width, blueBuffer, greenBuffer, redBuffer);
WriteHalfSingleRow(rowBlockSpan, width, blueBuffer, greenBuffer, redBuffer);
break;
}
@ -277,7 +277,7 @@ internal sealed class ExrEncoderCore
// Write row data to row block buffer.
Span<byte> rowBlockSpan = rowBlockBuffer.GetSpan().Slice((int)(rowsInBlockCount * bytesPerRow), (int)bytesPerRow);
this.WriteUnsignedIntRow(rowBlockSpan, width, blueBuffer, greenBuffer, redBuffer);
WriteUnsignedIntRow(rowBlockSpan, width, blueBuffer, greenBuffer, redBuffer);
rowsInBlockCount++;
}
@ -308,68 +308,68 @@ internal sealed class ExrEncoderCore
stream.WriteByte(0);
}
private 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> blueBuffer, Span<float> greenBuffer, Span<float> redBuffer)
{
int offset = 0;
for (int x = 0; x < width; x++)
{
this.WriteSingle(buffer.Slice(offset), blueBuffer[x]);
WriteSingleToBuffer(buffer.Slice(offset, 4), blueBuffer[x]);
offset += 4;
}
for (int x = 0; x < width; x++)
{
this.WriteSingle(buffer.Slice(offset), greenBuffer[x]);
WriteSingleToBuffer(buffer.Slice(offset, 4), greenBuffer[x]);
offset += 4;
}
for (int x = 0; x < width; x++)
{
this.WriteSingle(buffer.Slice(offset), redBuffer[x]);
WriteSingleToBuffer(buffer.Slice(offset, 4), redBuffer[x]);
offset += 4;
}
}
private 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> blueBuffer, Span<float> greenBuffer, Span<float> redBuffer)
{
int offset = 0;
for (int x = 0; x < width; x++)
{
WriteHalfSingle(buffer.Slice(offset), blueBuffer[x]);
WriteHalfSingleToBuffer(buffer.Slice(offset, 2), blueBuffer[x]);
offset += 2;
}
for (int x = 0; x < width; x++)
{
WriteHalfSingle(buffer.Slice(offset), greenBuffer[x]);
WriteHalfSingleToBuffer(buffer.Slice(offset, 2), greenBuffer[x]);
offset += 2;
}
for (int x = 0; x < width; x++)
{
WriteHalfSingle(buffer.Slice(offset), redBuffer[x]);
WriteHalfSingleToBuffer(buffer.Slice(offset, 2), redBuffer[x]);
offset += 2;
}
}
private 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> blueBuffer, Span<uint> greenBuffer, Span<uint> redBuffer)
{
int offset = 0;
for (int x = 0; x < width; x++)
{
WriteUnsignedInt(buffer.Slice(offset), blueBuffer[x]);
WriteUnsignedIntToBuffer(buffer.Slice(offset, 4), blueBuffer[x]);
offset += 4;
}
for (int x = 0; x < width; x++)
{
WriteUnsignedInt(buffer.Slice(offset), greenBuffer[x]);
WriteUnsignedIntToBuffer(buffer.Slice(offset, 4), greenBuffer[x]);
offset += 4;
}
for (int x = 0; x < width; x++)
{
WriteUnsignedInt(buffer.Slice(offset), redBuffer[x]);
WriteUnsignedIntToBuffer(buffer.Slice(offset, 4), redBuffer[x]);
offset += 4;
}
}
@ -518,22 +518,15 @@ internal sealed class ExrEncoderCore
}
[MethodImpl(InliningOptions.ShortMethod)]
private unsafe void WriteSingle(Span<byte> buffer, float value) => BinaryPrimitives.WriteInt32LittleEndian(buffer, *(int*)&value);
private static unsafe void WriteSingleToBuffer(Span<byte> buffer, float value) => BinaryPrimitives.WriteInt32LittleEndian(buffer, *(int*)&value);
[MethodImpl(InliningOptions.ShortMethod)]
private static void WriteHalfSingle(Span<byte> buffer, float value)
private static void WriteHalfSingleToBuffer(Span<byte> buffer, float value)
{
ushort valueAsShort = HalfTypeHelper.Pack(value);
BinaryPrimitives.WriteUInt16LittleEndian(buffer, valueAsShort);
}
[MethodImpl(InliningOptions.ShortMethod)]
private void WriteUnsignedInt(Stream stream, uint value)
{
BinaryPrimitives.WriteUInt32LittleEndian(this.buffer, value);
stream.Write(this.buffer.AsSpan(0, 4));
}
[MethodImpl(InliningOptions.ShortMethod)]
private static void WriteUnsignedInt(Span<byte> buffer, uint value) => BinaryPrimitives.WriteUInt32LittleEndian(buffer, value);
private static void WriteUnsignedIntToBuffer(Span<byte> buffer, uint value) => BinaryPrimitives.WriteUInt32LittleEndian(buffer, value);
}

Loading…
Cancel
Save