diff --git a/src/ImageSharp/Formats/Tiff/Compression/T4BitReader.cs b/src/ImageSharp/Formats/Tiff/Compression/T4BitReader.cs
index c37de8031a..b09645a4b3 100644
--- a/src/ImageSharp/Formats/Tiff/Compression/T4BitReader.cs
+++ b/src/ImageSharp/Formats/Tiff/Compression/T4BitReader.cs
@@ -2,15 +2,17 @@
// Licensed under the Apache License, Version 2.0.
using System;
+using System.Buffers;
using System.IO;
using System.Linq;
+using SixLabors.ImageSharp.Memory;
namespace SixLabors.ImageSharp.Formats.Tiff.Compression
{
///
/// Bitreader for reading compressed CCITT T4 1D data.
///
- internal class T4BitReader
+ internal class T4BitReader : IDisposable
{
///
/// Number of bits read.
@@ -42,6 +44,9 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Compression
///
private bool isFirstScanLine;
+ ///
+ /// Indicates whether we have found a termination code which signals the end of a run.
+ ///
private bool terminationCodeFound;
///
@@ -49,16 +54,24 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Compression
///
private uint runLength;
+ private readonly int dataLength;
+
private const int MinCodeLength = 2;
private const int MaxCodeLength = 13;
- public T4BitReader(Stream input, int bytesToRead)
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The compressed input stream.
+ /// The number of bytes to read from the stream.
+ /// The memory allocator.
+ public T4BitReader(Stream input, int bytesToRead, MemoryAllocator allocator)
{
- // TODO: use memory allocator
- this.Data = new byte[bytesToRead];
- this.ReadImageDataFromStream(input, bytesToRead);
+ this.Data = allocator.Allocate(bytesToRead);
+ this.ReadImageDataFromStream(input, bytesToRead, allocator);
+ this.dataLength = bytesToRead;
this.bitsRead = 0;
this.value = 0;
this.curValueBitsRead = 0;
@@ -72,7 +85,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Compression
///
/// Gets the compressed image data.
///
- public byte[] Data { get; }
+ public IMemoryOwner Data { get; }
///
/// Gets a value indicating whether there is more data to read left.
@@ -81,7 +94,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Compression
{
get
{
- return this.position < (ulong)this.Data.Length - 1;
+ return this.position < (ulong)this.dataLength - 1;
}
}
@@ -207,6 +220,12 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Compression
this.isFirstScanLine = false;
}
+ ///
+ public void Dispose()
+ {
+ this.Data.Dispose();
+ }
+
private uint WhiteTerminatingCodeRunLength()
{
switch (this.curValueBitsRead)
@@ -401,6 +420,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Compression
case 0x2:
return 3;
}
+
break;
}
@@ -959,31 +979,31 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Compression
{
case 2:
{
- uint[] codes = {0x3, 0x2};
+ uint[] codes = { 0x3, 0x2 };
return codes.Contains(this.value);
}
case 3:
{
- uint[] codes = {0x02, 0x03};
+ uint[] codes = { 0x02, 0x03 };
return codes.Contains(this.value);
}
case 4:
{
- uint[] codes = {0x03, 0x02};
+ uint[] codes = { 0x03, 0x02 };
return codes.Contains(this.value);
}
case 5:
{
- uint[] codes = {0x03};
+ uint[] codes = { 0x03 };
return codes.Contains(this.value);
}
case 6:
{
- uint[] codes = {0x5, 0x4};
+ uint[] codes = { 0x5, 0x4 };
return codes.Contains(this.value);
}
@@ -1067,8 +1087,9 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Compression
this.LoadNewByte();
}
+ Span dataSpan = this.Data.GetSpan();
int shift = 8 - this.bitsRead - 1;
- var bit = (uint)((this.Data[this.position] & (1 << shift)) != 0 ? 1 : 0);
+ var bit = (uint)((dataSpan[(int)this.position] & (1 << shift)) != 0 ? 1 : 0);
this.bitsRead++;
return bit;
@@ -1079,24 +1100,23 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Compression
this.position++;
this.bitsRead = 0;
- if (this.position >= (ulong)this.Data.Length)
+ if (this.position >= (ulong)this.dataLength)
{
TiffThrowHelper.ThrowImageFormatException("tiff image has invalid t4 compressed data");
}
}
- private void ReadImageDataFromStream(Stream input, int bytesToRead)
+ private void ReadImageDataFromStream(Stream input, int bytesToRead, MemoryAllocator allocator)
{
- var buffer = new byte[4096];
-
- Span bufferSpan = buffer.AsSpan();
- Span dataSpan = this.Data.AsSpan();
+ int bufferLength = 4096;
+ IMemoryOwner buffer = allocator.Allocate(bufferLength);
+ Span bufferSpan = buffer.GetSpan();
+ Span dataSpan = this.Data.GetSpan();
int read;
- while (bytesToRead > 0 &&
- (read = input.Read(buffer, 0, Math.Min(bufferSpan.Length, bytesToRead))) > 0)
+ while (bytesToRead > 0 && (read = input.Read(bufferSpan, 0, Math.Min(bufferLength, bytesToRead))) > 0)
{
- buffer.AsSpan(0, read).CopyTo(dataSpan);
+ buffer.Slice(0, read).CopyTo(dataSpan);
bytesToRead -= read;
dataSpan = dataSpan.Slice(read);
}
@@ -1106,5 +1126,5 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Compression
TiffThrowHelper.ThrowImageFormatException("tiff image file has insufficient data");
}
}
-}
+ }
}
diff --git a/src/ImageSharp/Formats/Tiff/Compression/T4TiffCompression.cs b/src/ImageSharp/Formats/Tiff/Compression/T4TiffCompression.cs
index 52b11613b6..13f7eb7945 100644
--- a/src/ImageSharp/Formats/Tiff/Compression/T4TiffCompression.cs
+++ b/src/ImageSharp/Formats/Tiff/Compression/T4TiffCompression.cs
@@ -29,10 +29,9 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Compression
int whiteValue = isWhiteZero ? 0 : 1;
int blackValue = isWhiteZero ? 1 : 0;
- var bitReader = new T4BitReader(stream, byteCount);
+ using var bitReader = new T4BitReader(stream, byteCount, this.Allocator);
uint bitsWritten = 0;
- uint pixels = 0;
while (bitReader.HasMoreData)
{
bitReader.ReadNextRun();
@@ -54,17 +53,13 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Compression
{
this.WriteBits(buffer, (int)bitsWritten, bitReader.RunLength, whiteValue);
bitsWritten += bitReader.RunLength;
- pixels += bitReader.RunLength;
}
else
{
this.WriteBits(buffer, (int)bitsWritten, bitReader.RunLength, blackValue);
bitsWritten += bitReader.RunLength;
- pixels += bitReader.RunLength;
}
}
-
- int foo = 0;
}
private void WriteBits(Span buffer, int pos, uint count, int value)
diff --git a/src/ImageSharp/Formats/Tiff/README.md b/src/ImageSharp/Formats/Tiff/README.md
index 2eed880b62..ca9078ae1b 100644
--- a/src/ImageSharp/Formats/Tiff/README.md
+++ b/src/ImageSharp/Formats/Tiff/README.md
@@ -10,6 +10,7 @@
- [TIFF/EP Extension (Wikipedia)](https://en.wikipedia.org/wiki/TIFF/EP)
- [Adobe TIFF Pages](http://partners.adobe.com/public/developer/tiff/index.html)
- [Unofficial TIFF FAQ](http://www.awaresystems.be/imaging/tiff/faq.html)
+ - [CCITT T.4 Compression](https://www.itu.int/rec/T-REC-T.4-198811-S/_page.print)
- DNG
- [Adobe DNG Pages](https://helpx.adobe.com/photoshop/digital-negative.html)
@@ -41,7 +42,7 @@
|None | | Y | |
|Ccitt1D | | | |
|PackBits | | Y | |
-|CcittGroup3Fax | | | |
+|CcittGroup3Fax | | Y | |
|CcittGroup4Fax | | | |
|Lzw | | Y | Based on ImageSharp GIF LZW implementation - this code could be modified to be (i) shared, or (ii) optimised for each case |
|Old Jpeg | | | |