// Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0.
using System;
using System.Buffers;
using System.IO;
using SixLabors.ImageSharp.Formats.Experimental.Tiff.Utils;
using SixLabors.ImageSharp.IO;
using SixLabors.ImageSharp.Memory;
namespace SixLabors.ImageSharp.Formats.Experimental.Tiff.Compression
{
///
/// Class to handle cases where TIFF image data is compressed using PackBits compression.
///
internal class PackBitsTiffCompression : TiffBaseCompression
{
///
/// Initializes a new instance of the class.
///
/// The memoryAllocator to use for buffer allocations.
public PackBitsTiffCompression(MemoryAllocator memoryAllocator)
: base(memoryAllocator)
{
}
///
protected override void Decompress(BufferedReadStream stream, int byteCount, Span buffer)
{
using IMemoryOwner compressedDataMemory = this.Allocator.Allocate(byteCount);
Span compressedData = compressedDataMemory.GetSpan();
stream.Read(compressedData, 0, byteCount);
int compressedOffset = 0;
int decompressedOffset = 0;
while (compressedOffset < byteCount)
{
byte headerByte = compressedData[compressedOffset];
if (headerByte <= (byte)127)
{
int literalOffset = compressedOffset + 1;
int literalLength = compressedData[compressedOffset] + 1;
compressedData.Slice(literalOffset, literalLength).CopyTo(buffer.Slice(decompressedOffset));
compressedOffset += literalLength + 1;
decompressedOffset += literalLength;
}
else if (headerByte == (byte)0x80)
{
compressedOffset += 1;
}
else
{
byte repeatData = compressedData[compressedOffset + 1];
int repeatLength = 257 - headerByte;
ArrayCopyRepeat(repeatData, buffer, decompressedOffset, repeatLength);
compressedOffset += 2;
decompressedOffset += repeatLength;
}
}
}
private static void ArrayCopyRepeat(byte value, Span destinationArray, int destinationIndex, int length)
{
for (int i = 0; i < length; i++)
{
destinationArray[i + destinationIndex] = value;
}
}
}
}