mirror of https://github.com/SixLabors/ImageSharp
5 changed files with 126 additions and 28 deletions
@ -0,0 +1,94 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
using System; |
|||
using System.Buffers; |
|||
using SixLabors.ImageSharp.IO; |
|||
using SixLabors.ImageSharp.Memory; |
|||
|
|||
namespace SixLabors.ImageSharp.Formats.OpenExr.Compression.Compressors |
|||
{ |
|||
internal class RunLengthCompression : ExrBaseDecompressor |
|||
{ |
|||
private readonly IMemoryOwner<byte> tmpBuffer; |
|||
|
|||
public RunLengthCompression(MemoryAllocator allocator, uint uncompressedBytes) |
|||
: base(allocator, uncompressedBytes) => this.tmpBuffer = allocator.Allocate<byte>((int)uncompressedBytes); |
|||
|
|||
public override void Decompress(BufferedReadStream stream, uint compressedBytes, Span<byte> buffer) |
|||
{ |
|||
Span<byte> uncompressed = this.tmpBuffer.GetSpan(); |
|||
int maxLength = (int)this.UncompressedBytes; |
|||
int offset = 0; |
|||
while (compressedBytes > 0) |
|||
{ |
|||
byte nextByte = ReadNextByte(stream); |
|||
|
|||
sbyte input = (sbyte)nextByte; |
|||
if (input < 0) |
|||
{ |
|||
int count = -input; |
|||
compressedBytes -= (uint)(count + 1); |
|||
|
|||
if ((maxLength -= count) < 0) |
|||
{ |
|||
return; |
|||
} |
|||
|
|||
// Check the input buffer is big enough to contain 'count' bytes of remaining data.
|
|||
if (compressedBytes < 0) |
|||
{ |
|||
return; |
|||
} |
|||
|
|||
for (int i = 0; i < count; i++) |
|||
{ |
|||
uncompressed[offset + i] = ReadNextByte(stream); |
|||
} |
|||
|
|||
offset += count; |
|||
} |
|||
else |
|||
{ |
|||
int count = input; |
|||
byte value = ReadNextByte(stream); |
|||
compressedBytes -= 2; |
|||
|
|||
if ((maxLength -= count + 1) < 0) |
|||
{ |
|||
return; |
|||
} |
|||
|
|||
// Check the input buffer is big enough to contain byte to be duplicated.
|
|||
if (compressedBytes < 0) |
|||
{ |
|||
return; |
|||
} |
|||
|
|||
for (int i = 0; i < count + 1; i++) |
|||
{ |
|||
uncompressed[offset + i] = value; |
|||
} |
|||
|
|||
offset += count + 1; |
|||
} |
|||
} |
|||
|
|||
Reconstruct(uncompressed, this.UncompressedBytes); |
|||
Interleave(uncompressed, this.UncompressedBytes, buffer); |
|||
} |
|||
|
|||
private static byte ReadNextByte(BufferedReadStream stream) |
|||
{ |
|||
int nextByte = stream.ReadByte(); |
|||
if (nextByte == -1) |
|||
{ |
|||
ExrThrowHelper.ThrowInvalidImageContentException("Not enough data to decompress RLE image!"); |
|||
} |
|||
|
|||
return (byte)nextByte; |
|||
} |
|||
|
|||
protected override void Dispose(bool disposing) => this.tmpBuffer.Dispose(); |
|||
} |
|||
} |
|||
Loading…
Reference in new issue