mirror of https://github.com/SixLabors/ImageSharp
4 changed files with 105 additions and 1 deletions
@ -0,0 +1,102 @@ |
|||||
|
// Copyright (c) Six Labors.
|
||||
|
// Licensed under the Six Labors Split License.
|
||||
|
|
||||
|
using System.Buffers; |
||||
|
using System.IO.Compression; |
||||
|
using System.Runtime.InteropServices; |
||||
|
using SixLabors.ImageSharp.Compression.Zlib; |
||||
|
using SixLabors.ImageSharp.IO; |
||||
|
using SixLabors.ImageSharp.Memory; |
||||
|
|
||||
|
namespace SixLabors.ImageSharp.Formats.Exr.Compression.Decompressors; |
||||
|
|
||||
|
internal class Pxr24Compression : ExrBaseDecompressor |
||||
|
{ |
||||
|
private readonly IMemoryOwner<byte> tmpBuffer; |
||||
|
|
||||
|
private readonly uint rowsPerBlock; |
||||
|
|
||||
|
private readonly int channelCount; |
||||
|
|
||||
|
private readonly int width; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Initializes a new instance of the <see cref="Pxr24Compression" /> class.
|
||||
|
/// </summary>
|
||||
|
/// <param name="allocator">The memory allocator.</param>
|
||||
|
/// <param name="bytesPerBlock">The bytes per pixel row block.</param>
|
||||
|
/// <param name="bytesPerRow">The bytes per pixel row.</param>
|
||||
|
public Pxr24Compression(MemoryAllocator allocator, uint bytesPerBlock, uint bytesPerRow, uint rowsPerBlock, int width, int channelCount) |
||||
|
: base(allocator, bytesPerBlock, bytesPerRow) |
||||
|
{ |
||||
|
this.tmpBuffer = allocator.Allocate<byte>((int)bytesPerBlock); |
||||
|
this.rowsPerBlock = rowsPerBlock; |
||||
|
this.width = width; |
||||
|
this.channelCount = channelCount; |
||||
|
} |
||||
|
|
||||
|
/// <inheritdoc/>
|
||||
|
public override void Decompress(BufferedReadStream stream, uint compressedBytes, Span<byte> buffer) |
||||
|
{ |
||||
|
Span<byte> uncompressed = this.tmpBuffer.GetSpan(); |
||||
|
Span<ushort> outputBuffer = MemoryMarshal.Cast<byte, ushort>(buffer); |
||||
|
|
||||
|
long pos = stream.Position; |
||||
|
using ZlibInflateStream inflateStream = new( |
||||
|
stream, |
||||
|
() => |
||||
|
{ |
||||
|
int left = (int)(compressedBytes - (stream.Position - pos)); |
||||
|
return left > 0 ? left : 0; |
||||
|
}); |
||||
|
inflateStream.AllocateNewBytes((int)this.BytesPerBlock, true); |
||||
|
using DeflateStream dataStream = inflateStream.CompressedStream!; |
||||
|
|
||||
|
int totalRead = 0; |
||||
|
while (totalRead < buffer.Length) |
||||
|
{ |
||||
|
int bytesRead = dataStream.Read(uncompressed, totalRead, buffer.Length - totalRead); |
||||
|
if (bytesRead <= 0) |
||||
|
{ |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
totalRead += bytesRead; |
||||
|
} |
||||
|
|
||||
|
if (totalRead == 0) |
||||
|
{ |
||||
|
ExrThrowHelper.ThrowInvalidImageContentException("Could not read enough data for zip compressed image data!"); |
||||
|
} |
||||
|
|
||||
|
int lastIn = 0; |
||||
|
int outputOffset = 0; |
||||
|
for (int y = 0; y < this.rowsPerBlock; y++) |
||||
|
{ |
||||
|
for (int c = 0; c < this.channelCount; c++) |
||||
|
{ |
||||
|
int offsetT1 = lastIn; |
||||
|
lastIn += this.width; |
||||
|
int offsetT2 = lastIn; |
||||
|
lastIn += this.width; |
||||
|
uint pixel = 0; |
||||
|
for (int x = 0; x < this.width; x++) |
||||
|
{ |
||||
|
uint t1 = uncompressed[offsetT1]; |
||||
|
uint t2 = uncompressed[offsetT2]; |
||||
|
uint diff = (t1 << 8) | t2; |
||||
|
|
||||
|
pixel += diff; |
||||
|
outputBuffer[outputOffset] = (ushort)pixel; |
||||
|
|
||||
|
offsetT1++; |
||||
|
offsetT2++; |
||||
|
outputOffset++; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/// <inheritdoc/>
|
||||
|
protected override void Dispose(bool disposing) => this.tmpBuffer.Dispose(); |
||||
|
} |
||||
Loading…
Reference in new issue