Browse Source

Add support for de-compressing CCITT t4 tiffs

pull/1457/head
Brian Popow 6 years ago
parent
commit
3ff41c657c
  1. 1110
      src/ImageSharp/Formats/Tiff/Compression/T4BitReader.cs
  2. 95
      src/ImageSharp/Formats/Tiff/Compression/T4TiffCompression.cs
  3. 4
      src/ImageSharp/Formats/Tiff/Compression/TiffCompressionFactory.cs
  4. 7
      src/ImageSharp/Formats/Tiff/Compression/TiffCompressionType.cs
  5. 4
      src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs
  6. 8
      src/ImageSharp/Formats/Tiff/TiffDecoderHelpers.cs
  7. 10
      src/ImageSharp/Formats/Tiff/TiffThrowHelper.cs

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

File diff suppressed because it is too large

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

@ -0,0 +1,95 @@
// Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0.
using System;
using System.IO;
using SixLabors.ImageSharp.Memory;
namespace SixLabors.ImageSharp.Formats.Tiff.Compression
{
/// <summary>
/// Class to handle cases where TIFF image data is compressed using CCITT T4 compression.
/// </summary>
internal class T4TiffCompression : TiffBaseCompression
{
/// <summary>
/// Initializes a new instance of the <see cref="T4TiffCompression" /> class.
/// </summary>
/// <param name="allocator">The memory allocator.</param>
public T4TiffCompression(MemoryAllocator allocator)
: base(allocator)
{
}
/// <inheritdoc/>
public override void Decompress(Stream stream, int byteCount, Span<byte> buffer)
{
// TODO: handle case when white is not zero.
bool isWhiteZero = true;
int whiteValue = isWhiteZero ? 0 : 1;
int blackValue = isWhiteZero ? 1 : 0;
var bitReader = new T4BitReader(stream, byteCount);
uint bitsWritten = 0;
uint pixels = 0;
while (bitReader.HasMoreData)
{
bitReader.ReadNextRun();
if (bitReader.IsEndOfScanLine)
{
// Write padding bytes, if necessary.
uint pad = 8 - (bitsWritten % 8);
if (pad != 8)
{
this.WriteBits(buffer, (int)bitsWritten, pad, 0);
bitsWritten += pad;
}
continue;
}
if (bitReader.IsWhiteRun)
{
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<byte> buffer, int pos, uint count, int value)
{
int bitPos = pos % 8;
int bufferPos = pos / 8;
int startIdx = bufferPos + bitPos;
int endIdx = (int)(startIdx + count);
for (int i = startIdx; i < endIdx; i++)
{
this.WriteBit(buffer, bufferPos, bitPos, value);
bitPos++;
if (bitPos >= 8)
{
bitPos = 0;
bufferPos++;
}
}
}
private void WriteBit(Span<byte> buffer, int bufferPos, int bitPos, int value)
{
buffer[bufferPos] |= (byte)(value << (7 - bitPos));
}
}
}

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

@ -1,7 +1,7 @@
// Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0.
using System;
using SixLabors.ImageSharp.Formats.Tiff.Compression;
using SixLabors.ImageSharp.Memory;
namespace SixLabors.ImageSharp.Formats.Tiff
@ -20,6 +20,8 @@ namespace SixLabors.ImageSharp.Formats.Tiff
return new DeflateTiffCompression(allocator);
case TiffCompressionType.Lzw:
return new LzwTiffCompression(allocator);
case TiffCompressionType.T4:
return new T4TiffCompression(allocator);
default:
throw TiffThrowHelper.NotSupportedCompression(nameof(compressionType));
}

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

@ -1,4 +1,4 @@
// Copyright (c) Six Labors.
// Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0.
namespace SixLabors.ImageSharp.Formats.Tiff
@ -27,5 +27,10 @@ namespace SixLabors.ImageSharp.Formats.Tiff
/// Image data is compressed using LZW compression.
/// </summary>
Lzw = 3,
/// <summary>
/// Image data is compressed using T4-encoding: CCITT T.4.
/// </summary>
T4 = 4,
}
}

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

@ -1,8 +1,6 @@
// 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.Linq;
@ -311,7 +309,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff
{
int uncompressedStripSize = this.CalculateStripBufferSize(frame.Width, rowsPerStrip);
using IManagedByteBuffer stripBuffer = this.memoryAllocator.AllocateManagedByteBuffer(uncompressedStripSize);
using IManagedByteBuffer stripBuffer = this.memoryAllocator.AllocateManagedByteBuffer(uncompressedStripSize, AllocationOptions.Clean);
Buffer2D<TPixel> pixels = frame.PixelBuffer;

8
src/ImageSharp/Formats/Tiff/TiffDecoderHelpers.cs

@ -1,14 +1,12 @@
// Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0.
using System;
using System.Collections.Generic;
using System.Linq;
using SixLabors.ImageSharp.Metadata;
using SixLabors.ImageSharp.Metadata.Profiles.Exif;
using SixLabors.ImageSharp.Metadata.Profiles.Icc;
using SixLabors.ImageSharp.Metadata.Profiles.Iptc;
using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Formats.Tiff
{
@ -348,6 +346,12 @@ namespace SixLabors.ImageSharp.Formats.Tiff
break;
}
case TiffCompression.CcittGroup3Fax:
{
options.CompressionType = TiffCompressionType.T4;
break;
}
default:
{
TiffThrowHelper.ThrowNotSupported("The specified TIFF compression format is not supported: " + compression);

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

@ -12,6 +12,16 @@ namespace SixLabors.ImageSharp.Formats.Tiff
/// </summary>
internal static class TiffThrowHelper
{
/// <summary>
/// Cold path optimization for throwing <see cref="ImageFormatException"/>-s
/// </summary>
/// <param name="errorMessage">The error message for the exception.</param>
[MethodImpl(MethodImplOptions.NoInlining)]
public static void ThrowImageFormatException(string errorMessage)
{
throw new ImageFormatException(errorMessage);
}
[MethodImpl(InliningOptions.ColdPath)]
public static Exception TagNotFound(string tagName)
=> new ArgumentException("Required tag is not found.", tagName);

Loading…
Cancel
Save