diff --git a/src/ImageSharp/Formats/Tiff/Compression/Decompressors/ModifiedHuffmanBitReader.cs b/src/ImageSharp/Formats/Tiff/Compression/Decompressors/ModifiedHuffmanBitReader.cs
index de3f3569ea..8306e91a34 100644
--- a/src/ImageSharp/Formats/Tiff/Compression/Decompressors/ModifiedHuffmanBitReader.cs
+++ b/src/ImageSharp/Formats/Tiff/Compression/Decompressors/ModifiedHuffmanBitReader.cs
@@ -3,7 +3,6 @@
using SixLabors.ImageSharp.Formats.Tiff.Constants;
using SixLabors.ImageSharp.IO;
-using SixLabors.ImageSharp.Memory;
namespace SixLabors.ImageSharp.Formats.Tiff.Compression.Decompressors
{
@@ -19,14 +18,13 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Compression.Decompressors
/// The compressed input stream.
/// The logical order of bits within a byte.
/// The number of bytes to read from the stream.
- /// The memory allocator.
- public ModifiedHuffmanBitReader(BufferedReadStream input, TiffFillOrder fillOrder, int bytesToRead, MemoryAllocator allocator)
- : base(input, fillOrder, bytesToRead, allocator)
+ public ModifiedHuffmanBitReader(BufferedReadStream input, TiffFillOrder fillOrder, int bytesToRead)
+ : base(input, fillOrder, bytesToRead)
{
}
///
- public override bool HasMoreData => this.Position < (ulong)this.DataLength - 1 || ((uint)(this.BitsRead - 1) < (7 - 1));
+ public override bool HasMoreData => this.Position < (ulong)this.DataLength - 1 || (uint)(this.BitsRead - 1) < 6;
///
public override bool IsEndOfScanLine
@@ -53,7 +51,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Compression.Decompressors
{
base.StartNewRow();
- int remainder = this.BitsRead & 7; // bit-hack for % 8
+ int remainder = Numerics.Modulo8(this.BitsRead);
if (remainder != 0)
{
// Skip padding bits, move to next byte.
diff --git a/src/ImageSharp/Formats/Tiff/Compression/Decompressors/ModifiedHuffmanTiffCompression.cs b/src/ImageSharp/Formats/Tiff/Compression/Decompressors/ModifiedHuffmanTiffCompression.cs
index c45587a728..4ec989742c 100644
--- a/src/ImageSharp/Formats/Tiff/Compression/Decompressors/ModifiedHuffmanTiffCompression.cs
+++ b/src/ImageSharp/Formats/Tiff/Compression/Decompressors/ModifiedHuffmanTiffCompression.cs
@@ -42,11 +42,12 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Compression.Decompressors
///
protected override void Decompress(BufferedReadStream stream, int byteCount, int stripHeight, Span buffer)
{
- using var bitReader = new ModifiedHuffmanBitReader(stream, this.FillOrder, byteCount, this.Allocator);
+ var bitReader = new ModifiedHuffmanBitReader(stream, this.FillOrder, byteCount);
buffer.Clear();
int bitsWritten = 0;
uint pixelsWritten = 0;
+ nint rowsWritten = 0;
while (bitReader.HasMoreData)
{
bitReader.ReadNextRun();
@@ -68,7 +69,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Compression.Decompressors
if (pixelsWritten == this.Width)
{
- bitReader.StartNewRow();
+ rowsWritten++;
pixelsWritten = 0;
// Write padding bits, if necessary.
@@ -78,6 +79,13 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Compression.Decompressors
BitWriterUtils.WriteBits(buffer, bitsWritten, pad, 0);
bitsWritten += pad;
}
+
+ if (rowsWritten >= stripHeight)
+ {
+ break;
+ }
+
+ bitReader.StartNewRow();
}
if (pixelsWritten > this.Width)
diff --git a/src/ImageSharp/Formats/Tiff/Compression/Decompressors/T4BitReader.cs b/src/ImageSharp/Formats/Tiff/Compression/Decompressors/T4BitReader.cs
index 89dd7a50ec..c46066a3a8 100644
--- a/src/ImageSharp/Formats/Tiff/Compression/Decompressors/T4BitReader.cs
+++ b/src/ImageSharp/Formats/Tiff/Compression/Decompressors/T4BitReader.cs
@@ -1,22 +1,17 @@
// Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0.
-using System;
-using System.Buffers;
using System.Collections.Generic;
-using System.IO;
using System.Runtime.CompilerServices;
-using System.Runtime.InteropServices;
using SixLabors.ImageSharp.Formats.Tiff.Constants;
using SixLabors.ImageSharp.IO;
-using SixLabors.ImageSharp.Memory;
namespace SixLabors.ImageSharp.Formats.Tiff.Compression.Decompressors
{
///
/// Bitreader for reading compressed CCITT T4 1D data.
///
- internal class T4BitReader : IDisposable
+ internal class T4BitReader
{
///
/// The logical order of bits within a byte.
@@ -204,20 +199,22 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Compression.Decompressors
{ 0x54, 1408 }, { 0x55, 1472 }, { 0x5A, 1536 }, { 0x5B, 1600 }, { 0x64, 1664 }, { 0x65, 1728 }
};
+ ///
+ /// The compressed input stream.
+ ///
+ private readonly BufferedReadStream stream;
+
///
/// Initializes a new instance of the class.
///
/// The compressed input stream.
/// The logical order of bits within a byte.
/// The number of bytes to read from the stream.
- /// The memory allocator.
/// Indicates, if fill bits have been added as necessary before EOL codes such that EOL always ends on a byte boundary. Defaults to false.
- public T4BitReader(BufferedReadStream input, TiffFillOrder fillOrder, int bytesToRead, MemoryAllocator allocator, bool eolPadding = false)
+ public T4BitReader(BufferedReadStream input, TiffFillOrder fillOrder, int bytesToRead, bool eolPadding = false)
{
+ this.stream = input;
this.fillOrder = fillOrder;
- this.Data = allocator.Allocate(bytesToRead);
- this.ReadImageDataFromStream(input, bytesToRead);
-
this.DataLength = bytesToRead;
this.BitsRead = 0;
this.Value = 0;
@@ -230,8 +227,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Compression.Decompressors
this.RunLength = 0;
this.eolPadding = eolPadding;
- Span dataSpan = this.Data.GetSpan();
- this.DataAtPosition = dataSpan[(int)this.Position];
+ this.ReadNextByte();
if (this.eolPadding)
{
@@ -269,11 +265,6 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Compression.Decompressors
///
protected ulong Position { get; set; }
- ///
- /// Gets the compressed image data.
- ///
- public IMemoryOwner Data { get; }
-
///
/// Gets a value indicating whether there is more data to read left.
///
@@ -400,9 +391,6 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Compression.Decompressors
this.terminationCodeFound = false;
}
- ///
- public void Dispose() => this.Data.Dispose();
-
///
/// An EOL is expected before the first data.
///
@@ -465,14 +453,11 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Compression.Decompressors
///
/// Advances the position by one byte.
///
- /// True, if data could be advanced by one byte.
+ /// True, if data could be advanced by one byte, otherwise false.
protected bool AdvancePosition()
{
- this.LoadNewByte();
- if (this.Position < (ulong)this.DataLength)
+ if (this.LoadNewByte())
{
- Span dataSpan = this.Data.GetSpan();
- this.DataAtPosition = Unsafe.Add(ref MemoryMarshal.GetReference(dataSpan), (int)this.Position);
return true;
}
@@ -833,6 +818,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Compression.Decompressors
return false;
}
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
private uint GetBit()
{
if (this.BitsRead >= 8)
@@ -847,24 +833,34 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Compression.Decompressors
return bit;
}
- private void LoadNewByte()
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private bool LoadNewByte()
{
+ if (this.Position < (ulong)this.DataLength)
+ {
+ this.ReadNextByte();
+ this.Position++;
+ return true;
+ }
+
this.Position++;
- this.ResetBitsRead();
+ this.DataAtPosition = 0;
+ return false;
}
- private void ReadImageDataFromStream(Stream input, int bytesToRead)
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private void ReadNextByte()
{
- Span dataSpan = this.Data.GetSpan();
- input.Read(dataSpan, 0, bytesToRead);
-
- if (this.fillOrder == TiffFillOrder.LeastSignificantBitFirst)
+ int nextByte = this.stream.ReadByte();
+ if (nextByte == -1)
{
- for (int i = 0; i < dataSpan.Length; i++)
- {
- dataSpan[i] = ReverseBits(dataSpan[i]);
- }
+ TiffThrowHelper.ThrowImageFormatException("Tiff fax compression error: not enough data.");
}
+
+ this.ResetBitsRead();
+ this.DataAtPosition = this.fillOrder == TiffFillOrder.LeastSignificantBitFirst
+ ? ReverseBits((byte)nextByte)
+ : (byte)nextByte;
}
// http://graphics.stanford.edu/~seander/bithacks.html#ReverseByteWith64Bits
diff --git a/src/ImageSharp/Formats/Tiff/Compression/Decompressors/T4TiffCompression.cs b/src/ImageSharp/Formats/Tiff/Compression/Decompressors/T4TiffCompression.cs
index 9bb53e29ae..254cb2ab02 100644
--- a/src/ImageSharp/Formats/Tiff/Compression/Decompressors/T4TiffCompression.cs
+++ b/src/ImageSharp/Formats/Tiff/Compression/Decompressors/T4TiffCompression.cs
@@ -61,11 +61,12 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Compression.Decompressors
}
bool eolPadding = this.faxCompressionOptions.HasFlag(FaxCompressionOptions.EolPadding);
- using var bitReader = new T4BitReader(stream, this.FillOrder, byteCount, this.Allocator, eolPadding);
+ var bitReader = new T4BitReader(stream, this.FillOrder, byteCount, eolPadding);
buffer.Clear();
- uint bitsWritten = 0;
- uint pixelWritten = 0;
+ int bitsWritten = 0;
+ uint pixelsWritten = 0;
+ nint rowsWritten = 0;
while (bitReader.HasMoreData)
{
bitReader.ReadNextRun();
@@ -74,41 +75,47 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Compression.Decompressors
{
this.WritePixelRun(buffer, bitReader, bitsWritten);
- bitsWritten += bitReader.RunLength;
- pixelWritten += bitReader.RunLength;
+ bitsWritten += (int)bitReader.RunLength;
+ pixelsWritten += bitReader.RunLength;
}
if (bitReader.IsEndOfScanLine)
{
// Write padding bytes, if necessary.
- uint pad = 8 - (bitsWritten % 8);
+ int pad = 8 - Numerics.Modulo8(bitsWritten);
if (pad != 8)
{
- BitWriterUtils.WriteBits(buffer, (int)bitsWritten, (int)pad, 0);
+ BitWriterUtils.WriteBits(buffer, bitsWritten, pad, 0);
bitsWritten += pad;
}
- pixelWritten = 0;
+ pixelsWritten = 0;
+ rowsWritten++;
+
+ if (rowsWritten >= stripHeight)
+ {
+ break;
+ }
}
}
// Edge case for when we are at the last byte, but there are still some unwritten pixels left.
- if (pixelWritten > 0 && pixelWritten < this.width)
+ if (pixelsWritten > 0 && pixelsWritten < this.width)
{
bitReader.ReadNextRun();
this.WritePixelRun(buffer, bitReader, bitsWritten);
}
}
- private void WritePixelRun(Span buffer, T4BitReader bitReader, uint bitsWritten)
+ private void WritePixelRun(Span buffer, T4BitReader bitReader, int bitsWritten)
{
if (bitReader.IsWhiteRun)
{
- BitWriterUtils.WriteBits(buffer, (int)bitsWritten, (int)bitReader.RunLength, this.whiteValue);
+ BitWriterUtils.WriteBits(buffer, bitsWritten, (int)bitReader.RunLength, this.whiteValue);
}
else
{
- BitWriterUtils.WriteBits(buffer, (int)bitsWritten, (int)bitReader.RunLength, this.blackValue);
+ BitWriterUtils.WriteBits(buffer, bitsWritten, (int)bitReader.RunLength, this.blackValue);
}
}
diff --git a/src/ImageSharp/Formats/Tiff/Compression/Decompressors/T6BitReader.cs b/src/ImageSharp/Formats/Tiff/Compression/Decompressors/T6BitReader.cs
index 160dbd9fcb..a3ac0ca2b5 100644
--- a/src/ImageSharp/Formats/Tiff/Compression/Decompressors/T6BitReader.cs
+++ b/src/ImageSharp/Formats/Tiff/Compression/Decompressors/T6BitReader.cs
@@ -5,7 +5,6 @@ using System.Collections.Generic;
using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.Formats.Tiff.Constants;
using SixLabors.ImageSharp.IO;
-using SixLabors.ImageSharp.Memory;
namespace SixLabors.ImageSharp.Formats.Tiff.Compression.Decompressors
{
@@ -56,9 +55,8 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Compression.Decompressors
/// The compressed input stream.
/// The logical order of bits within a byte.
/// The number of bytes to read from the stream.
- /// The memory allocator.
- public T6BitReader(BufferedReadStream input, TiffFillOrder fillOrder, int bytesToRead, MemoryAllocator allocator)
- : base(input, fillOrder, bytesToRead, allocator)
+ public T6BitReader(BufferedReadStream input, TiffFillOrder fillOrder, int bytesToRead)
+ : base(input, fillOrder, bytesToRead)
{
}
diff --git a/src/ImageSharp/Formats/Tiff/Compression/Decompressors/T6TiffCompression.cs b/src/ImageSharp/Formats/Tiff/Compression/Decompressors/T6TiffCompression.cs
index 6a0bb00fc4..495fba0370 100644
--- a/src/ImageSharp/Formats/Tiff/Compression/Decompressors/T6TiffCompression.cs
+++ b/src/ImageSharp/Formats/Tiff/Compression/Decompressors/T6TiffCompression.cs
@@ -57,7 +57,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Compression.Decompressors
Span scanLine = scanLineBuffer.GetSpan().Slice(0, this.width);
Span referenceScanLineSpan = scanLineBuffer.GetSpan().Slice(this.width, this.width);
- using var bitReader = new T6BitReader(stream, this.FillOrder, byteCount, this.Allocator);
+ var bitReader = new T6BitReader(stream, this.FillOrder, byteCount);
var referenceScanLine = new CcittReferenceScanline(this.isWhiteZero, this.width);
int bitsWritten = 0;