mirror of https://github.com/SixLabors/ImageSharp
5 changed files with 131 additions and 3 deletions
@ -0,0 +1,79 @@ |
|||
// <copyright file="PackBitsTiffCompression.cs" company="James Jackson-South">
|
|||
// Copyright (c) James Jackson-South and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
|
|||
namespace ImageSharp.Formats.Tiff |
|||
{ |
|||
using System; |
|||
using System.Buffers; |
|||
using System.IO; |
|||
using System.Runtime.CompilerServices; |
|||
|
|||
/// <summary>
|
|||
/// Class to handle cases where TIFF image data is compressed using PackBits compression.
|
|||
/// </summary>
|
|||
internal static class PackBitsTiffCompression |
|||
{ |
|||
/// <summary>
|
|||
/// Decompresses image data into the supplied buffer.
|
|||
/// </summary>
|
|||
/// <param name="stream">The <see cref="Stream"/> to read image data from.</param>
|
|||
/// <param name="byteCount">The number of bytes to read from the input stream.</param>
|
|||
/// <param name="buffer">The output buffer for uncompressed data.</param>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static void Decompress(Stream stream, int byteCount, byte[] buffer) |
|||
{ |
|||
byte[] compressedData = ArrayPool<byte>.Shared.Rent(byteCount); |
|||
|
|||
try |
|||
{ |
|||
stream.ReadFull(compressedData, 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; |
|||
|
|||
Array.Copy(compressedData, literalOffset, buffer, decompressedOffset, literalLength); |
|||
|
|||
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; |
|||
} |
|||
} |
|||
} |
|||
finally |
|||
{ |
|||
ArrayPool<byte>.Shared.Return(compressedData); |
|||
} |
|||
} |
|||
|
|||
private static void ArrayCopyRepeat(byte value, byte[] destinationArray, int destinationIndex, int length) |
|||
{ |
|||
for (int i = 0; i < length; i++) |
|||
{ |
|||
destinationArray[i + destinationIndex] = value; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,35 @@ |
|||
// <copyright file="PackBitsTiffCompressionTests.cs" company="James Jackson-South">
|
|||
// Copyright (c) James Jackson-South and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
|
|||
namespace ImageSharp.Tests |
|||
{ |
|||
using System.IO; |
|||
using Xunit; |
|||
|
|||
using ImageSharp.Formats.Tiff; |
|||
|
|||
public class PackBitsTiffCompressionTests |
|||
{ |
|||
[Theory] |
|||
[InlineData(new byte[] { }, new byte[] { })] |
|||
[InlineData(new byte[] { 0x00, 0x2A }, new byte[] { 0x2A })] // Read one byte
|
|||
[InlineData(new byte[] { 0x01, 0x15, 0x32 }, new byte[] { 0x15, 0x32 })] // Read two bytes
|
|||
[InlineData(new byte[] { 0xFF, 0x2A }, new byte[] { 0x2A, 0x2A })] // Repeat two bytes
|
|||
[InlineData(new byte[] { 0xFE, 0x2A }, new byte[] { 0x2A, 0x2A, 0x2A })] // Repeat three bytes
|
|||
[InlineData(new byte[] { 0x80 }, new byte[] { })] // Read a 'No operation' byte
|
|||
[InlineData(new byte[] { 0x01, 0x15, 0x32, 0x80, 0xFF, 0xA2 }, new byte[] { 0x15, 0x32, 0xA2, 0xA2 })] // Read two bytes, nop, repeat two bytes
|
|||
[InlineData(new byte[] { 0xFE, 0xAA, 0x02, 0x80, 0x00, 0x2A, 0xFD, 0xAA, 0x03, 0x80, 0x00, 0x2A, 0x22, 0xF7, 0xAA }, |
|||
new byte[] { 0xAA, 0xAA, 0xAA, 0x80, 0x00, 0x2A, 0xAA, 0xAA, 0xAA, 0xAA, 0x80, 0x00, 0x2A, 0x22, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA })] // Apple PackBits sample
|
|||
public void Decompress_ReadsData(byte[] inputData, byte[] expectedResult) |
|||
{ |
|||
Stream stream = new MemoryStream(inputData); |
|||
byte[] buffer = new byte[expectedResult.Length]; |
|||
|
|||
PackBitsTiffCompression.Decompress(stream, inputData.Length, buffer); |
|||
|
|||
Assert.Equal(expectedResult, buffer); |
|||
} |
|||
} |
|||
} |
|||
Loading…
Reference in new issue