Browse Source

Use memory allocator in t4 bitreader

pull/1570/head
Brian Popow 6 years ago
parent
commit
3e4b5b262a
  1. 66
      src/ImageSharp/Formats/Tiff/Compression/T4BitReader.cs
  2. 7
      src/ImageSharp/Formats/Tiff/Compression/T4TiffCompression.cs
  3. 3
      src/ImageSharp/Formats/Tiff/README.md

66
src/ImageSharp/Formats/Tiff/Compression/T4BitReader.cs

@ -2,15 +2,17 @@
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using System; using System;
using System.Buffers;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using SixLabors.ImageSharp.Memory;
namespace SixLabors.ImageSharp.Formats.Tiff.Compression namespace SixLabors.ImageSharp.Formats.Tiff.Compression
{ {
/// <summary> /// <summary>
/// Bitreader for reading compressed CCITT T4 1D data. /// Bitreader for reading compressed CCITT T4 1D data.
/// </summary> /// </summary>
internal class T4BitReader internal class T4BitReader : IDisposable
{ {
/// <summary> /// <summary>
/// Number of bits read. /// Number of bits read.
@ -42,6 +44,9 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Compression
/// </summary> /// </summary>
private bool isFirstScanLine; private bool isFirstScanLine;
/// <summary>
/// Indicates whether we have found a termination code which signals the end of a run.
/// </summary>
private bool terminationCodeFound; private bool terminationCodeFound;
/// <summary> /// <summary>
@ -49,16 +54,24 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Compression
/// </summary> /// </summary>
private uint runLength; private uint runLength;
private readonly int dataLength;
private const int MinCodeLength = 2; private const int MinCodeLength = 2;
private const int MaxCodeLength = 13; private const int MaxCodeLength = 13;
public T4BitReader(Stream input, int bytesToRead) /// <summary>
/// Initializes a new instance of the <see cref="T4BitReader" /> class.
/// </summary>
/// <param name="input">The compressed input stream.</param>
/// <param name="bytesToRead">The number of bytes to read from the stream.</param>
/// <param name="allocator">The memory allocator.</param>
public T4BitReader(Stream input, int bytesToRead, MemoryAllocator allocator)
{ {
// TODO: use memory allocator this.Data = allocator.Allocate<byte>(bytesToRead);
this.Data = new byte[bytesToRead]; this.ReadImageDataFromStream(input, bytesToRead, allocator);
this.ReadImageDataFromStream(input, bytesToRead);
this.dataLength = bytesToRead;
this.bitsRead = 0; this.bitsRead = 0;
this.value = 0; this.value = 0;
this.curValueBitsRead = 0; this.curValueBitsRead = 0;
@ -72,7 +85,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Compression
/// <summary> /// <summary>
/// Gets the compressed image data. /// Gets the compressed image data.
/// </summary> /// </summary>
public byte[] Data { get; } public IMemoryOwner<byte> Data { get; }
/// <summary> /// <summary>
/// Gets a value indicating whether there is more data to read left. /// Gets a value indicating whether there is more data to read left.
@ -81,7 +94,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Compression
{ {
get 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; this.isFirstScanLine = false;
} }
/// <inheritdoc/>
public void Dispose()
{
this.Data.Dispose();
}
private uint WhiteTerminatingCodeRunLength() private uint WhiteTerminatingCodeRunLength()
{ {
switch (this.curValueBitsRead) switch (this.curValueBitsRead)
@ -401,6 +420,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Compression
case 0x2: case 0x2:
return 3; return 3;
} }
break; break;
} }
@ -959,31 +979,31 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Compression
{ {
case 2: case 2:
{ {
uint[] codes = {0x3, 0x2}; uint[] codes = { 0x3, 0x2 };
return codes.Contains(this.value); return codes.Contains(this.value);
} }
case 3: case 3:
{ {
uint[] codes = {0x02, 0x03}; uint[] codes = { 0x02, 0x03 };
return codes.Contains(this.value); return codes.Contains(this.value);
} }
case 4: case 4:
{ {
uint[] codes = {0x03, 0x02}; uint[] codes = { 0x03, 0x02 };
return codes.Contains(this.value); return codes.Contains(this.value);
} }
case 5: case 5:
{ {
uint[] codes = {0x03}; uint[] codes = { 0x03 };
return codes.Contains(this.value); return codes.Contains(this.value);
} }
case 6: case 6:
{ {
uint[] codes = {0x5, 0x4}; uint[] codes = { 0x5, 0x4 };
return codes.Contains(this.value); return codes.Contains(this.value);
} }
@ -1067,8 +1087,9 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Compression
this.LoadNewByte(); this.LoadNewByte();
} }
Span<byte> dataSpan = this.Data.GetSpan();
int shift = 8 - this.bitsRead - 1; 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++; this.bitsRead++;
return bit; return bit;
@ -1079,24 +1100,23 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Compression
this.position++; this.position++;
this.bitsRead = 0; 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"); 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]; int bufferLength = 4096;
IMemoryOwner<byte> buffer = allocator.Allocate<byte>(bufferLength);
Span<byte> bufferSpan = buffer.AsSpan(); Span<byte> bufferSpan = buffer.GetSpan();
Span<byte> dataSpan = this.Data.AsSpan(); Span<byte> dataSpan = this.Data.GetSpan();
int read; int read;
while (bytesToRead > 0 && while (bytesToRead > 0 && (read = input.Read(bufferSpan, 0, Math.Min(bufferLength, bytesToRead))) > 0)
(read = input.Read(buffer, 0, Math.Min(bufferSpan.Length, bytesToRead))) > 0)
{ {
buffer.AsSpan(0, read).CopyTo(dataSpan); buffer.Slice(0, read).CopyTo(dataSpan);
bytesToRead -= read; bytesToRead -= read;
dataSpan = dataSpan.Slice(read); dataSpan = dataSpan.Slice(read);
} }
@ -1106,5 +1126,5 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Compression
TiffThrowHelper.ThrowImageFormatException("tiff image file has insufficient data"); TiffThrowHelper.ThrowImageFormatException("tiff image file has insufficient data");
} }
} }
} }
} }

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

@ -29,10 +29,9 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Compression
int whiteValue = isWhiteZero ? 0 : 1; int whiteValue = isWhiteZero ? 0 : 1;
int blackValue = isWhiteZero ? 1 : 0; int blackValue = isWhiteZero ? 1 : 0;
var bitReader = new T4BitReader(stream, byteCount); using var bitReader = new T4BitReader(stream, byteCount, this.Allocator);
uint bitsWritten = 0; uint bitsWritten = 0;
uint pixels = 0;
while (bitReader.HasMoreData) while (bitReader.HasMoreData)
{ {
bitReader.ReadNextRun(); bitReader.ReadNextRun();
@ -54,17 +53,13 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Compression
{ {
this.WriteBits(buffer, (int)bitsWritten, bitReader.RunLength, whiteValue); this.WriteBits(buffer, (int)bitsWritten, bitReader.RunLength, whiteValue);
bitsWritten += bitReader.RunLength; bitsWritten += bitReader.RunLength;
pixels += bitReader.RunLength;
} }
else else
{ {
this.WriteBits(buffer, (int)bitsWritten, bitReader.RunLength, blackValue); this.WriteBits(buffer, (int)bitsWritten, bitReader.RunLength, blackValue);
bitsWritten += bitReader.RunLength; bitsWritten += bitReader.RunLength;
pixels += bitReader.RunLength;
} }
} }
int foo = 0;
} }
private void WriteBits(Span<byte> buffer, int pos, uint count, int value) private void WriteBits(Span<byte> buffer, int pos, uint count, int value)

3
src/ImageSharp/Formats/Tiff/README.md

@ -10,6 +10,7 @@
- [TIFF/EP Extension (Wikipedia)](https://en.wikipedia.org/wiki/TIFF/EP) - [TIFF/EP Extension (Wikipedia)](https://en.wikipedia.org/wiki/TIFF/EP)
- [Adobe TIFF Pages](http://partners.adobe.com/public/developer/tiff/index.html) - [Adobe TIFF Pages](http://partners.adobe.com/public/developer/tiff/index.html)
- [Unofficial TIFF FAQ](http://www.awaresystems.be/imaging/tiff/faq.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 - DNG
- [Adobe DNG Pages](https://helpx.adobe.com/photoshop/digital-negative.html) - [Adobe DNG Pages](https://helpx.adobe.com/photoshop/digital-negative.html)
@ -41,7 +42,7 @@
|None | | Y | | |None | | Y | |
|Ccitt1D | | | | |Ccitt1D | | | |
|PackBits | | Y | | |PackBits | | Y | |
|CcittGroup3Fax | | | | |CcittGroup3Fax | | Y | |
|CcittGroup4Fax | | | | |CcittGroup4Fax | | | |
|Lzw | | Y | Based on ImageSharp GIF LZW implementation - this code could be modified to be (i) shared, or (ii) optimised for each case | |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 | | | | |Old Jpeg | | | |

Loading…
Cancel
Save