Browse Source

Use common zlib class for tiff deflate compressor. Stop using SubStream class for tiff compressors.

pull/1570/head
Ildar Khayrutdinov 5 years ago
parent
commit
b4fd1bd360
  1. 40
      src/ImageSharp/Formats/Tiff/Compression/DeflateTiffCompression.cs
  2. 7
      src/ImageSharp/Formats/Tiff/Compression/LzwTiffCompression.cs
  3. 3
      src/ImageSharp/Formats/Tiff/Compression/ModifiedHuffmanTiffCompression.cs
  4. 5
      src/ImageSharp/Formats/Tiff/Compression/NoneTiffCompression.cs
  5. 3
      src/ImageSharp/Formats/Tiff/Compression/PackBitsTiffCompression.cs
  6. 3
      src/ImageSharp/Formats/Tiff/Compression/T4TiffCompression.cs
  7. 28
      src/ImageSharp/Formats/Tiff/Compression/TiffBaseCompression.cs
  8. 10
      src/ImageSharp/Formats/Tiff/Compression/TiffCompressionFactory.cs
  9. 6
      src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs
  10. 4
      src/ImageSharp/Formats/Tiff/TiffThrowHelper.cs
  11. 176
      src/ImageSharp/Formats/Tiff/Utils/SubStream.cs
  12. 4
      src/ImageSharp/Formats/Tiff/Utils/TiffWriter.cs
  13. 10
      tests/ImageSharp.Tests/Formats/Tiff/Compression/DeflateTiffCompressionTests.cs
  14. 9
      tests/ImageSharp.Tests/Formats/Tiff/Compression/LzwTiffCompressionTests.cs
  15. 8
      tests/ImageSharp.Tests/Formats/Tiff/Compression/NoneTiffCompressionTests.cs
  16. 5
      tests/ImageSharp.Tests/Formats/Tiff/Compression/PackBitsTiffCompressionTests.cs
  17. 328
      tests/ImageSharp.Tests/Formats/Tiff/Utils/SubStreamTests.cs

40
src/ImageSharp/Formats/Tiff/Compression/DeflateTiffCompression.cs

@ -5,9 +5,11 @@ using System;
using System.IO;
using System.IO.Compression;
using SixLabors.ImageSharp.Compression.Zlib;
using SixLabors.ImageSharp.Formats.Experimental.Tiff.Constants;
using SixLabors.ImageSharp.Formats.Experimental.Tiff.Utils;
using SixLabors.ImageSharp.Formats.Tiff.Compression;
using SixLabors.ImageSharp.IO;
using SixLabors.ImageSharp.Memory;
namespace SixLabors.ImageSharp.Formats.Experimental.Tiff.Compression
@ -33,34 +35,20 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff.Compression
}
/// <inheritdoc/>
public override void Decompress(Stream stream, int byteCount, Span<byte> buffer)
protected override void Decompress(BufferedReadStream stream, int byteCount, Span<byte> buffer)
{
// Read the 'zlib' header information
int cmf = stream.ReadByte();
int flag = stream.ReadByte();
if ((cmf & 0x0f) != 8)
{
TiffThrowHelper.ThrowBadZlibHeader(cmf);
}
// If the 'fdict' flag is set then we should skip the next four bytes
bool fdict = (flag & 32) != 0;
if (fdict)
{
stream.ReadByte();
stream.ReadByte();
stream.ReadByte();
stream.ReadByte();
}
// The subsequent data is the Deflate compressed data (except for the last four bytes of checksum)
int headerLength = fdict ? 10 : 6;
var subStream = new SubStream(stream, byteCount - headerLength);
using (var deflateStream = new DeflateStream(subStream, CompressionMode.Decompress, true))
long pos = stream.Position;
using (var deframeStream = new ZlibInflateStream(
stream,
() =>
{
int left = (int)(byteCount - (stream.Position - pos));
return left > 0 ? left : 0;
}))
{
deflateStream.Read(buffer, 0, buffer.Length);
deframeStream.AllocateNewBytes(byteCount, true);
DeflateStream dataStream = deframeStream.CompressedStream;
dataStream.Read(buffer, 0, buffer.Length);
}
if (this.Predictor == TiffPredictor.Horizontal)

7
src/ImageSharp/Formats/Tiff/Compression/LzwTiffCompression.cs

@ -3,9 +3,11 @@
using System;
using System.IO;
using SixLabors.ImageSharp.Formats.Experimental.Tiff.Constants;
using SixLabors.ImageSharp.Formats.Experimental.Tiff.Utils;
using SixLabors.ImageSharp.Formats.Tiff.Compression;
using SixLabors.ImageSharp.IO;
using SixLabors.ImageSharp.Memory;
namespace SixLabors.ImageSharp.Formats.Experimental.Tiff.Compression
@ -28,10 +30,9 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff.Compression
}
/// <inheritdoc/>
public override void Decompress(Stream stream, int byteCount, Span<byte> buffer)
protected override void Decompress(BufferedReadStream stream, int byteCount, Span<byte> buffer)
{
var subStream = new SubStream(stream, byteCount);
var decoder = new TiffLzwDecoder(subStream, this.Allocator);
var decoder = new TiffLzwDecoder(stream, this.Allocator);
decoder.DecodePixels(buffer.Length, 8, buffer);
if (this.Predictor == TiffPredictor.Horizontal)

3
src/ImageSharp/Formats/Tiff/Compression/ModifiedHuffmanTiffCompression.cs

@ -5,6 +5,7 @@ using System;
using System.IO;
using SixLabors.ImageSharp.Formats.Experimental.Tiff.Constants;
using SixLabors.ImageSharp.IO;
using SixLabors.ImageSharp.Memory;
namespace SixLabors.ImageSharp.Formats.Experimental.Tiff.Compression
@ -26,7 +27,7 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff.Compression
}
/// <inheritdoc/>
public override void Decompress(Stream stream, int byteCount, Span<byte> buffer)
protected override void Decompress(BufferedReadStream stream, int byteCount, Span<byte> buffer)
{
bool isWhiteZero = this.PhotometricInterpretation == TiffPhotometricInterpretation.WhiteIsZero;
byte whiteValue = (byte)(isWhiteZero ? 0 : 1);

5
src/ImageSharp/Formats/Tiff/Compression/NoneTiffCompression.cs

@ -5,6 +5,7 @@ using System;
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
@ -24,9 +25,9 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff.Compression
}
/// <inheritdoc/>
public override void Decompress(Stream stream, int byteCount, Span<byte> buffer)
protected override void Decompress(BufferedReadStream stream, int byteCount, Span<byte> buffer)
{
stream.Read(buffer, 0, byteCount);
_ = stream.Read(buffer, 0, byteCount);
}
}
}

3
src/ImageSharp/Formats/Tiff/Compression/PackBitsTiffCompression.cs

@ -6,6 +6,7 @@ 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
@ -25,7 +26,7 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff.Compression
}
/// <inheritdoc/>
public override void Decompress(Stream stream, int byteCount, Span<byte> buffer)
protected override void Decompress(BufferedReadStream stream, int byteCount, Span<byte> buffer)
{
using IMemoryOwner<byte> compressedDataMemory = this.Allocator.Allocate<byte>(byteCount);

3
src/ImageSharp/Formats/Tiff/Compression/T4TiffCompression.cs

@ -5,6 +5,7 @@ using System;
using System.IO;
using SixLabors.ImageSharp.Formats.Experimental.Tiff.Constants;
using SixLabors.ImageSharp.IO;
using SixLabors.ImageSharp.Memory;
namespace SixLabors.ImageSharp.Formats.Experimental.Tiff.Compression
@ -26,7 +27,7 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff.Compression
}
/// <inheritdoc/>
public override void Decompress(Stream stream, int byteCount, Span<byte> buffer)
protected override void Decompress(BufferedReadStream stream, int byteCount, Span<byte> buffer)
{
bool isWhiteZero = this.PhotometricInterpretation == TiffPhotometricInterpretation.WhiteIsZero;
byte whiteValue = (byte)(isWhiteZero ? 0 : 1);

28
src/ImageSharp/Formats/Tiff/Compression/TiffBaseCompression.cs

@ -6,6 +6,7 @@ using System.IO;
using SixLabors.ImageSharp.Formats.Experimental.Tiff.Constants;
using SixLabors.ImageSharp.Formats.Tiff.Compression;
using SixLabors.ImageSharp.IO;
using SixLabors.ImageSharp.Memory;
namespace SixLabors.ImageSharp.Formats.Experimental.Tiff.Compression
@ -55,9 +56,32 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff.Compression
/// <summary>
/// Decompresses image data into the supplied buffer.
/// </summary>
/// <param name="stream">The <see cref="Stream"/> to read image data from.</param>
/// <param name="stream">The <see cref="Stream" /> to read image data from.</param>
/// <param name="stripOffset">The strip offset of stream.</param>
/// <param name="stripByteCount">The number of bytes to read from the input stream.</param>
/// <param name="buffer">The output buffer for uncompressed data.</param>
public void Decompress(BufferedReadStream stream, uint stripOffset, uint stripByteCount, Span<byte> buffer)
{
if (stripByteCount > int.MaxValue)
{
TiffThrowHelper.ThrowImageFormatException("Too big value of StripByteCount.");
}
stream.Seek(stripOffset, SeekOrigin.Begin);
this.Decompress(stream, (int)stripByteCount, buffer);
if (stripOffset + stripByteCount < stream.Position)
{
TiffThrowHelper.ThrowImageFormatException("Out of range when reading a strip.");
}
}
/// <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>
public abstract void Decompress(Stream stream, int byteCount, Span<byte> buffer);
protected abstract void Decompress(BufferedReadStream stream, int byteCount, Span<byte> buffer);
}
}

10
src/ImageSharp/Formats/Tiff/Compression/TiffCompressionFactory.cs

@ -13,17 +13,27 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff.Compression
switch (compressionType)
{
case TiffDecoderCompressionType.None:
DebugGuard.IsTrue(predictor == TiffPredictor.None, "predictor");
return new NoneTiffCompression(allocator);
case TiffDecoderCompressionType.PackBits:
DebugGuard.IsTrue(predictor == TiffPredictor.None, "predictor");
return new PackBitsTiffCompression(allocator);
case TiffDecoderCompressionType.Deflate:
return new DeflateTiffCompression(allocator, width, bitsPerPixel, predictor);
case TiffDecoderCompressionType.Lzw:
return new LzwTiffCompression(allocator, width, bitsPerPixel, predictor);
case TiffDecoderCompressionType.T4:
DebugGuard.IsTrue(predictor == TiffPredictor.None, "predictor");
return new T4TiffCompression(allocator, photometricInterpretation, width);
case TiffDecoderCompressionType.HuffmanRle:
DebugGuard.IsTrue(predictor == TiffPredictor.None, "predictor");
return new ModifiedHuffmanTiffCompression(allocator, photometricInterpretation, width);
default:
throw TiffThrowHelper.NotSupportedCompression(nameof(compressionType));
}

6
src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs

@ -347,8 +347,7 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff
{
int stripIndex = (i * stripsPerPixel) + planeIndex;
this.inputStream.Seek(stripOffsets[stripIndex], SeekOrigin.Begin);
decompressor.Decompress(this.inputStream, (int)stripByteCounts[stripIndex], stripBuffers[planeIndex].GetSpan());
decompressor.Decompress(this.inputStream, stripOffsets[stripIndex], stripByteCounts[stripIndex], stripBuffers[planeIndex].GetSpan());
}
colorDecoder.Decode(stripBuffers, pixels, 0, rowsPerStrip * i, frame.Width, stripHeight);
@ -385,8 +384,7 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff
{
int stripHeight = stripIndex < stripOffsets.Length - 1 || frame.Height % rowsPerStrip == 0 ? rowsPerStrip : frame.Height % rowsPerStrip;
this.inputStream.Seek(stripOffsets[stripIndex], SeekOrigin.Begin);
decompressor.Decompress(this.inputStream, (int)stripByteCounts[stripIndex], stripBuffer.GetSpan());
decompressor.Decompress(this.inputStream, stripOffsets[stripIndex], stripByteCounts[stripIndex], stripBuffer.GetSpan());
colorDecoder.Decode(stripBuffer.GetSpan(), pixels, 0, rowsPerStrip * stripIndex, frame.Width, stripHeight);
}

4
src/ImageSharp/Formats/Tiff/TiffThrowHelper.cs

@ -18,9 +18,7 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff
/// <param name="errorMessage">The error message for the exception.</param>
[MethodImpl(MethodImplOptions.NoInlining)]
public static void ThrowImageFormatException(string errorMessage)
{
throw new ImageFormatException(errorMessage);
}
=> throw new ImageFormatException(errorMessage);
[MethodImpl(InliningOptions.ColdPath)]
public static Exception TagNotFound(string tagName)

176
src/ImageSharp/Formats/Tiff/Utils/SubStream.cs

@ -1,176 +0,0 @@
// Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0.
using System;
using System.IO;
namespace SixLabors.ImageSharp.Formats.Experimental.Tiff.Utils
{
/// <summary>
/// Utility class to encapsulate a sub-portion of another <see cref="Stream"/>.
/// </summary>
/// <remarks>
/// Note that disposing of the <see cref="SubStream"/> does not dispose the underlying
/// <see cref="Stream"/>.
/// </remarks>
internal class SubStream : Stream
{
private Stream innerStream;
private long offset;
private long endOffset;
private long length;
/// <summary>
/// Initializes a new instance of the <see cref="SubStream"/> class.
/// </summary>
/// <param name="innerStream">The underlying <see cref="Stream"/> to wrap.</param>
/// <param name="length">The length of the sub-stream.</param>
/// <remarks>
/// Note that calling the sub-stream with start from the current offset of the
/// underlying <see cref="Stream"/>
/// </remarks>
public SubStream(Stream innerStream, long length)
{
this.innerStream = innerStream;
this.offset = this.innerStream.Position;
this.endOffset = this.offset + length;
this.length = length;
}
/// <summary>
/// Initializes a new instance of the <see cref="SubStream"/> class.
/// </summary>
/// <param name="innerStream">The underlying <see cref="Stream"/> to wrap.</param>
/// <param name="offset">The offset of the sub-stream within the underlying <see cref="Stream"/>.</param>
/// <param name="length">The length of the sub-stream.</param>
/// <remarks>
/// Note that calling the constructor will immediately move the underlying
/// <see cref="Stream"/> to the specified offset.
/// </remarks>
public SubStream(Stream innerStream, long offset, long length)
{
this.innerStream = innerStream;
this.offset = offset;
this.endOffset = offset + length;
this.length = length;
innerStream.Seek(offset, SeekOrigin.Begin);
}
/// <inheritdoc/>
public override bool CanRead
{
get
{
return true;
}
}
/// <inheritdoc/>
public override bool CanWrite
{
get
{
return false;
}
}
/// <inheritdoc/>
public override bool CanSeek
{
get
{
return this.innerStream.CanSeek;
}
}
/// <inheritdoc/>
public override long Length
{
get
{
return this.length;
}
}
/// <inheritdoc/>
public override long Position
{
get
{
return this.innerStream.Position - this.offset;
}
set
{
this.Seek(value, SeekOrigin.Begin);
}
}
/// <inheritdoc/>
public override void Flush()
{
throw new NotSupportedException();
}
/// <inheritdoc/>
public override int Read(byte[] buffer, int offset, int count)
{
long bytesRemaining = this.endOffset - this.innerStream.Position;
if (bytesRemaining < count)
{
count = (int)bytesRemaining;
}
return this.innerStream.Read(buffer, offset, count);
}
/// <inheritdoc/>
public override int ReadByte()
{
if (this.innerStream.Position < this.endOffset)
{
return this.innerStream.ReadByte();
}
else
{
return -1;
}
}
/// <inheritdoc/>
public override void Write(byte[] array, int offset, int count)
{
throw new NotSupportedException();
}
/// <inheritdoc/>
public override void WriteByte(byte value)
{
throw new NotSupportedException();
}
/// <inheritdoc/>
public override long Seek(long offset, SeekOrigin origin)
{
switch (origin)
{
case SeekOrigin.Current:
return this.innerStream.Seek(offset, SeekOrigin.Current) - this.offset;
case SeekOrigin.Begin:
return this.innerStream.Seek(this.offset + offset, SeekOrigin.Begin) - this.offset;
case SeekOrigin.End:
return this.innerStream.Seek(this.endOffset - offset, SeekOrigin.Begin) - this.offset;
default:
throw new ArgumentException("Invalid seek origin.");
}
}
/// <inheritdoc/>
public override void SetLength(long value)
{
throw new NotSupportedException();
}
}
}

4
src/ImageSharp/Formats/Tiff/Utils/TiffWriter.cs

@ -186,7 +186,7 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff.Utils
{
int bytesWritten = 0;
using var memoryStream = new MemoryStream();
using var deflateStream = new ZlibDeflateStream(this.memoryAllocator, memoryStream, compressionLevel); // TODO: move zlib compression from png to a common place?
using var deflateStream = new ZlibDeflateStream(this.memoryAllocator, memoryStream, compressionLevel);
for (int y = 0; y < image.Height; y++)
{
@ -534,7 +534,7 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff.Utils
{
int bytesWritten = 0;
using var memoryStream = new MemoryStream();
using var deflateStream = new ZlibDeflateStream(this.memoryAllocator, memoryStream, compressionLevel); // TODO: move zlib compression from png to a common place?
using var deflateStream = new ZlibDeflateStream(this.memoryAllocator, memoryStream, compressionLevel);
for (int y = 0; y < image.Height; y++)
{

10
tests/ImageSharp.Tests/Formats/Tiff/Compression/DeflateTiffCompressionTests.cs

@ -5,6 +5,8 @@ using System.IO;
using SixLabors.ImageSharp.Compression.Zlib;
using SixLabors.ImageSharp.Formats.Experimental.Tiff.Compression;
using SixLabors.ImageSharp.Formats.Experimental.Tiff.Constants;
using SixLabors.ImageSharp.IO;
using Xunit;
namespace SixLabors.ImageSharp.Tests.Formats.Tiff.Compression
@ -20,17 +22,17 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff.Compression
[InlineData(new byte[] { 1, 2, 42, 53, 42, 53, 42, 53, 42, 53, 42, 53, 3, 4 })] // Repeated sequence
public void Compress_Decompress_Roundtrip_Works(byte[] data)
{
using (Stream stream = CreateCompressedStream(data))
using (BufferedReadStream stream = CreateCompressedStream(data))
{
var buffer = new byte[data.Length];
new DeflateTiffCompression(Configuration.Default.MemoryAllocator, 10, 8, TiffPredictor.None).Decompress(stream, (int)stream.Length, buffer);
new DeflateTiffCompression(Configuration.Default.MemoryAllocator, 10, 8, TiffPredictor.None).Decompress(stream, 0, (uint)stream.Length, buffer);
Assert.Equal(data, buffer);
}
}
private static Stream CreateCompressedStream(byte[] data)
private static BufferedReadStream CreateCompressedStream(byte[] data)
{
Stream compressedStream = new MemoryStream();
@ -41,7 +43,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff.Compression
}
compressedStream.Seek(0, SeekOrigin.Begin);
return compressedStream;
return new BufferedReadStream(Configuration.Default, compressedStream);
}
}
}

9
tests/ImageSharp.Tests/Formats/Tiff/Compression/LzwTiffCompressionTests.cs

@ -7,6 +7,7 @@ using System.IO;
using SixLabors.ImageSharp.Formats.Experimental.Tiff.Compression;
using SixLabors.ImageSharp.Formats.Experimental.Tiff.Constants;
using SixLabors.ImageSharp.Formats.Experimental.Tiff.Utils;
using SixLabors.ImageSharp.IO;
using SixLabors.ImageSharp.Memory;
using Xunit;
@ -36,15 +37,15 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff.Compression
public void Compress_Decompress_Roundtrip_Works(byte[] data)
{
using Stream stream = CreateCompressedStream(data);
using BufferedReadStream stream = CreateCompressedStream(data);
var buffer = new byte[data.Length];
new LzwTiffCompression(Configuration.Default.MemoryAllocator, 10, 8, TiffPredictor.None).Decompress(stream, (int)stream.Length, buffer);
new LzwTiffCompression(Configuration.Default.MemoryAllocator, 10, 8, TiffPredictor.None).Decompress(stream, 0, (uint)stream.Length, buffer);
Assert.Equal(data, buffer);
}
private static Stream CreateCompressedStream(byte[] inputData)
private static BufferedReadStream CreateCompressedStream(byte[] inputData)
{
Stream compressedStream = new MemoryStream();
using System.Buffers.IMemoryOwner<byte> data = Configuration.Default.MemoryAllocator.Allocate<byte>(inputData.Length);
@ -57,7 +58,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff.Compression
compressedStream.Seek(0, SeekOrigin.Begin);
return compressedStream;
return new BufferedReadStream(Configuration.Default, compressedStream);
}
}
}

8
tests/ImageSharp.Tests/Formats/Tiff/Compression/NoneTiffCompressionTests.cs

@ -3,6 +3,8 @@
using System.IO;
using SixLabors.ImageSharp.Formats.Experimental.Tiff.Compression;
using SixLabors.ImageSharp.IO;
using Xunit;
namespace SixLabors.ImageSharp.Tests.Formats.Tiff.Compression
@ -13,12 +15,12 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff.Compression
[Theory]
[InlineData(new byte[] { 10, 15, 20, 25, 30, 35, 40, 45 }, 8, new byte[] { 10, 15, 20, 25, 30, 35, 40, 45 })]
[InlineData(new byte[] { 10, 15, 20, 25, 30, 35, 40, 45 }, 5, new byte[] { 10, 15, 20, 25, 30 })]
public void Decompress_ReadsData(byte[] inputData, int byteCount, byte[] expectedResult)
public void Decompress_ReadsData(byte[] inputData, uint byteCount, byte[] expectedResult)
{
Stream stream = new MemoryStream(inputData);
var stream = new BufferedReadStream(Configuration.Default, new MemoryStream(inputData));
var buffer = new byte[expectedResult.Length];
new NoneTiffCompression(null).Decompress(stream, byteCount, buffer);
new NoneTiffCompression(null).Decompress(stream, 0, byteCount, buffer);
Assert.Equal(expectedResult, buffer);
}

5
tests/ImageSharp.Tests/Formats/Tiff/Compression/PackBitsTiffCompressionTests.cs

@ -5,6 +5,7 @@ using System;
using System.IO;
using SixLabors.ImageSharp.Formats.Experimental.Tiff.Compression;
using SixLabors.ImageSharp.IO;
using SixLabors.ImageSharp.Memory;
using Xunit;
@ -25,10 +26,10 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff.Compression
[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);
var stream = new BufferedReadStream(Configuration.Default, new MemoryStream(inputData));
var buffer = new byte[expectedResult.Length];
new PackBitsTiffCompression(new ArrayPoolMemoryAllocator()).Decompress(stream, inputData.Length, buffer);
new PackBitsTiffCompression(new ArrayPoolMemoryAllocator()).Decompress(stream, 0, (uint)inputData.Length, buffer);
Assert.Equal(expectedResult, buffer);
}

328
tests/ImageSharp.Tests/Formats/Tiff/Utils/SubStreamTests.cs

@ -1,328 +0,0 @@
// Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0.
using System;
using System.IO;
using SixLabors.ImageSharp.Formats.Experimental.Tiff.Utils;
using Xunit;
namespace SixLabors.ImageSharp.Tests.Formats.Tiff
{
[Trait("Format", "Tiff")]
public class SubStreamTests
{
[Fact]
public void Constructor_PositionsStreamCorrectly_WithSpecifiedOffset()
{
Stream innerStream = new MemoryStream(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 });
innerStream.Position = 2;
SubStream stream = new SubStream(innerStream, 4, 6);
Assert.Equal(0, stream.Position);
Assert.Equal(6, stream.Length);
Assert.Equal(4, innerStream.Position);
}
[Fact]
public void Constructor_PositionsStreamCorrectly_WithCurrentOffset()
{
Stream innerStream = new MemoryStream(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 });
innerStream.Position = 2;
SubStream stream = new SubStream(innerStream, 6);
Assert.Equal(0, stream.Position);
Assert.Equal(6, stream.Length);
Assert.Equal(2, innerStream.Position);
}
[Fact]
public void CanRead_ReturnsTrue()
{
Stream innerStream = new MemoryStream(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 });
SubStream stream = new SubStream(innerStream, 2, 6);
Assert.True(stream.CanRead);
}
[Fact]
public void CanWrite_ReturnsFalse()
{
Stream innerStream = new MemoryStream(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 });
SubStream stream = new SubStream(innerStream, 2, 6);
Assert.False(stream.CanWrite);
}
[Fact]
public void CanSeek_ReturnsTrue()
{
Stream innerStream = new MemoryStream(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 });
SubStream stream = new SubStream(innerStream, 2, 6);
Assert.True(stream.CanSeek);
}
[Fact]
public void Length_ReturnsTheConstrainedLength()
{
Stream innerStream = new MemoryStream(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 });
SubStream stream = new SubStream(innerStream, 2, 6);
Assert.Equal(6, stream.Length);
}
[Fact]
public void Position_ReturnsZeroBeforeReading()
{
Stream innerStream = new MemoryStream(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 });
SubStream stream = new SubStream(innerStream, 2, 6);
Assert.Equal(0, stream.Position);
Assert.Equal(2, innerStream.Position);
}
[Fact]
public void Position_ReturnsPositionAfterReading()
{
Stream innerStream = new MemoryStream(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 });
SubStream stream = new SubStream(innerStream, 2, 6);
stream.Read(new byte[2], 0, 2);
Assert.Equal(2, stream.Position);
Assert.Equal(4, innerStream.Position);
}
[Fact]
public void Position_ReturnsPositionAfterReadingTwice()
{
Stream innerStream = new MemoryStream(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 });
SubStream stream = new SubStream(innerStream, 2, 6);
stream.Read(new byte[2], 0, 2);
stream.Read(new byte[2], 0, 2);
Assert.Equal(4, stream.Position);
Assert.Equal(6, innerStream.Position);
}
[Fact]
public void Position_SettingPropertySeeksToNewPosition()
{
Stream innerStream = new MemoryStream(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 });
SubStream stream = new SubStream(innerStream, 2, 6);
stream.Position = 3;
Assert.Equal(3, stream.Position);
Assert.Equal(5, innerStream.Position);
}
[Fact]
public void Flush_ThrowsNotSupportedException()
{
Stream innerStream = new MemoryStream(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 });
SubStream stream = new SubStream(innerStream, 2, 6);
Assert.Throws<NotSupportedException>(() => stream.Flush());
}
[Fact]
public void Read_Reads_FromStartOfSubStream()
{
Stream innerStream = new MemoryStream(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 });
SubStream stream = new SubStream(innerStream, 2, 6);
byte[] buffer = new byte[3];
var result = stream.Read(buffer, 0, 3);
Assert.Equal(new byte[] { 3, 4, 5 }, buffer);
Assert.Equal(3, result);
}
[Theory]
[InlineData(2, SeekOrigin.Begin)]
[InlineData(1, SeekOrigin.Current)]
[InlineData(4, SeekOrigin.End)]
public void Read_Reads_FromMiddleOfSubStream(long offset, SeekOrigin origin)
{
Stream innerStream = new MemoryStream(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 });
SubStream stream = new SubStream(innerStream, 2, 6);
stream.Position = 1;
stream.Seek(offset, origin);
byte[] buffer = new byte[3];
var result = stream.Read(buffer, 0, 3);
Assert.Equal(new byte[] { 5, 6, 7 }, buffer);
Assert.Equal(3, result);
}
[Theory]
[InlineData(3, SeekOrigin.Begin)]
[InlineData(2, SeekOrigin.Current)]
[InlineData(3, SeekOrigin.End)]
public void Read_Reads_FromEndOfSubStream(long offset, SeekOrigin origin)
{
Stream innerStream = new MemoryStream(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 });
SubStream stream = new SubStream(innerStream, 2, 6);
stream.Position = 1;
stream.Seek(offset, origin);
byte[] buffer = new byte[3];
var result = stream.Read(buffer, 0, 3);
Assert.Equal(new byte[] { 6, 7, 8 }, buffer);
Assert.Equal(3, result);
}
[Theory]
[InlineData(4, SeekOrigin.Begin)]
[InlineData(3, SeekOrigin.Current)]
[InlineData(2, SeekOrigin.End)]
public void Read_Reads_FromBeyondEndOfSubStream(long offset, SeekOrigin origin)
{
Stream innerStream = new MemoryStream(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 });
SubStream stream = new SubStream(innerStream, 2, 6);
stream.Position = 1;
stream.Seek(offset, origin);
byte[] buffer = new byte[3];
var result = stream.Read(buffer, 0, 3);
Assert.Equal(new byte[] { 7, 8, 0 }, buffer);
Assert.Equal(2, result);
}
[Fact]
public void ReadByte_Reads_FromStartOfSubStream()
{
Stream innerStream = new MemoryStream(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 });
SubStream stream = new SubStream(innerStream, 2, 6);
var result = stream.ReadByte();
Assert.Equal(3, result);
}
[Fact]
public void ReadByte_Reads_FromMiddleOfSubStream()
{
Stream innerStream = new MemoryStream(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 });
SubStream stream = new SubStream(innerStream, 2, 6);
stream.Position = 3;
var result = stream.ReadByte();
Assert.Equal(6, result);
}
[Fact]
public void ReadByte_Reads_FromEndOfSubStream()
{
Stream innerStream = new MemoryStream(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 });
SubStream stream = new SubStream(innerStream, 2, 6);
stream.Position = 5;
var result = stream.ReadByte();
Assert.Equal(8, result);
}
[Fact]
public void ReadByte_Reads_FromBeyondEndOfSubStream()
{
Stream innerStream = new MemoryStream(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 });
SubStream stream = new SubStream(innerStream, 2, 6);
stream.Position = 5;
stream.ReadByte();
var result = stream.ReadByte();
Assert.Equal(-1, result);
}
[Fact]
public void Write_ThrowsNotSupportedException()
{
Stream innerStream = new MemoryStream(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 });
SubStream stream = new SubStream(innerStream, 2, 6);
Assert.Throws<NotSupportedException>(() => stream.Write(new byte[] { 1, 2 }, 0, 2));
}
[Fact]
public void WriteByte_ThrowsNotSupportedException()
{
Stream innerStream = new MemoryStream(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 });
SubStream stream = new SubStream(innerStream, 2, 6);
Assert.Throws<NotSupportedException>(() => stream.WriteByte(42));
}
[Fact]
public void Seek_MovesToNewPosition_FromBegin()
{
Stream innerStream = new MemoryStream(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 });
SubStream stream = new SubStream(innerStream, 2, 6);
stream.Position = 1;
long result = stream.Seek(2, SeekOrigin.Begin);
Assert.Equal(2, result);
Assert.Equal(2, stream.Position);
Assert.Equal(4, innerStream.Position);
}
[Fact]
public void Seek_MovesToNewPosition_FromCurrent()
{
Stream innerStream = new MemoryStream(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 });
SubStream stream = new SubStream(innerStream, 2, 6);
stream.Position = 1;
long result = stream.Seek(2, SeekOrigin.Current);
Assert.Equal(3, result);
Assert.Equal(3, stream.Position);
Assert.Equal(5, innerStream.Position);
}
[Fact]
public void Seek_MovesToNewPosition_FromEnd()
{
Stream innerStream = new MemoryStream(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 });
SubStream stream = new SubStream(innerStream, 2, 6);
stream.Position = 1;
long result = stream.Seek(2, SeekOrigin.End);
Assert.Equal(4, result);
Assert.Equal(4, stream.Position);
Assert.Equal(6, innerStream.Position);
}
[Fact]
public void Seek_ThrowsException_WithInvalidOrigin()
{
Stream innerStream = new MemoryStream(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 });
SubStream stream = new SubStream(innerStream, 2, 6);
var e = Assert.Throws<ArgumentException>(() => stream.Seek(2, (SeekOrigin)99));
Assert.Equal("Invalid seek origin.", e.Message);
}
[Fact]
public void SetLength_ThrowsNotSupportedException()
{
Stream innerStream = new MemoryStream(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 });
SubStream stream = new SubStream(innerStream, 2, 6);
Assert.Throws<NotSupportedException>(() => stream.SetLength(5));
}
}
}
Loading…
Cancel
Save