Browse Source

Rework horizontal predictor: Fixes issue with paletted images which use a predictor

pull/1570/head
Brian Popow 6 years ago
parent
commit
b00104d769
  1. 19
      src/ImageSharp/Formats/Tiff/Compression/DeflateTiffCompression.cs
  2. 75
      src/ImageSharp/Formats/Tiff/Compression/HorizontalPredictor.cs
  3. 18
      src/ImageSharp/Formats/Tiff/Compression/LzwTiffCompression.cs
  4. 8
      src/ImageSharp/Formats/Tiff/Compression/NoneTiffCompression.cs
  5. 8
      src/ImageSharp/Formats/Tiff/Compression/PackBitsTiffCompression.cs
  6. 19
      src/ImageSharp/Formats/Tiff/Compression/TiffBaseCompression.cs
  7. 6
      src/ImageSharp/Formats/Tiff/Compression/TiffCompressionFactory.cs
  8. 2
      src/ImageSharp/Formats/Tiff/TiffBitsPerPixel.cs
  9. 60
      src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs
  10. 3
      tests/ImageSharp.Tests/Formats/Tiff/Compression/DeflateTiffCompressionTests.cs
  11. 5
      tests/ImageSharp.Tests/Formats/Tiff/Compression/LzwTiffCompressionTests.cs
  12. 4
      tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs
  13. 7
      tests/ImageSharp.Tests/TestImages.cs
  14. 3
      tests/Images/Input/Tiff/Calliphora_gray_lzw_predictor.tiff
  15. 3
      tests/Images/Input/Tiff/Calliphora_rgb_lzw.tif
  16. 4
      tests/Images/Input/Tiff/Calliphora_rgb_lzw_predictor.tiff
  17. 3
      tests/Images/Input/Tiff/Calliphora_rgb_palette_lzw_predictor.tiff

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

@ -4,7 +4,10 @@
using System; using System;
using System.IO; using System.IO;
using System.IO.Compression; using System.IO.Compression;
using SixLabors.ImageSharp.Formats.Experimental.Tiff.Constants;
using SixLabors.ImageSharp.Formats.Experimental.Tiff.Utils; using SixLabors.ImageSharp.Formats.Experimental.Tiff.Utils;
using SixLabors.ImageSharp.Formats.Tiff.Compression;
using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.Memory;
namespace SixLabors.ImageSharp.Formats.Experimental.Tiff.Compression namespace SixLabors.ImageSharp.Formats.Experimental.Tiff.Compression
@ -17,8 +20,15 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff.Compression
/// </remarks> /// </remarks>
internal class DeflateTiffCompression : TiffBaseCompression internal class DeflateTiffCompression : TiffBaseCompression
{ {
public DeflateTiffCompression(MemoryAllocator allocator) /// <summary>
: base(allocator) /// Initializes a new instance of the <see cref="DeflateTiffCompression" /> class.
/// </summary>
/// <param name="memoryAllocator">The memoryAllocator to use for buffer allocations.</param>
/// <param name="width">The image width.</param>
/// <param name="bitsPerPixel">The bits used per pixel.</param>
/// <param name="predictor">The tiff predictor used.</param>
public DeflateTiffCompression(MemoryAllocator memoryAllocator, int width, int bitsPerPixel, TiffPredictor predictor)
: base(memoryAllocator, width, bitsPerPixel, predictor)
{ {
} }
@ -52,6 +62,11 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff.Compression
{ {
deflateStream.ReadFull(buffer); deflateStream.ReadFull(buffer);
} }
if (this.Predictor == TiffPredictor.Horizontal)
{
HorizontalPredictor.Undo(buffer, this.Width, this.BitsPerPixel);
}
} }
} }
} }

75
src/ImageSharp/Formats/Tiff/Compression/HorizontalPredictor.cs

@ -0,0 +1,75 @@
// Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0.
using System;
using System.Runtime.InteropServices;
using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Formats.Tiff.Compression
{
/// <summary>
/// Methods for undoing the horizontal prediction used in combination with deflate and LZW compressed TIFF images.
/// </summary>
public static class HorizontalPredictor
{
/// <summary>
/// Inverts the horizontal prediction.
/// </summary>
/// <param name="pixelBytes">Buffer with decompressed pixel data.</param>
/// <param name="width">The width of the image or strip.</param>
/// <param name="bitsPerPixel">Bits per pixel.</param>
public static void Undo(Span<byte> pixelBytes, int width, int bitsPerPixel)
{
if (bitsPerPixel == 8)
{
Undo8Bit(pixelBytes, width);
}
else if (bitsPerPixel == 24)
{
Undo24Bit(pixelBytes, width);
}
}
private static void Undo8Bit(Span<byte> pixelBytes, int width)
{
var rowBytesCount = width;
int height = pixelBytes.Length / rowBytesCount;
for (int y = 0; y < height; y++)
{
Span<byte> rowBytes = pixelBytes.Slice(y * rowBytesCount, rowBytesCount);
byte pixelValue = rowBytes[0];
for (int x = 1; x < width; x++)
{
pixelValue += rowBytes[x];
rowBytes[x] = pixelValue;
}
}
}
private static void Undo24Bit(Span<byte> pixelBytes, int width)
{
var rowBytesCount = width * 3;
int height = pixelBytes.Length / rowBytesCount;
for (int y = 0; y < height; y++)
{
Span<byte> rowBytes = pixelBytes.Slice(y * rowBytesCount, rowBytesCount);
Span<Rgb24> rowRgb = MemoryMarshal.Cast<byte, Rgb24>(rowBytes);
byte r = rowRgb[0].R;
byte g = rowRgb[0].G;
byte b = rowRgb[0].B;
for (int x = 1; x < width; x++)
{
ref Rgb24 pixel = ref rowRgb[x];
r += rowRgb[x].R;
g += rowRgb[x].G;
b += rowRgb[x].B;
var rgb = new Rgb24(r, g, b);
pixel.FromRgb24(rgb);
}
}
}
}
}

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

@ -3,7 +3,9 @@
using System; using System;
using System.IO; using System.IO;
using SixLabors.ImageSharp.Formats.Experimental.Tiff.Constants;
using SixLabors.ImageSharp.Formats.Experimental.Tiff.Utils; using SixLabors.ImageSharp.Formats.Experimental.Tiff.Utils;
using SixLabors.ImageSharp.Formats.Tiff.Compression;
using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.Memory;
namespace SixLabors.ImageSharp.Formats.Experimental.Tiff.Compression namespace SixLabors.ImageSharp.Formats.Experimental.Tiff.Compression
@ -13,8 +15,15 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff.Compression
/// </summary> /// </summary>
internal class LzwTiffCompression : TiffBaseCompression internal class LzwTiffCompression : TiffBaseCompression
{ {
public LzwTiffCompression(MemoryAllocator allocator) /// <summary>
: base(allocator) /// Initializes a new instance of the <see cref="LzwTiffCompression" /> class.
/// </summary>
/// <param name="memoryAllocator">The memoryAllocator to use for buffer allocations.</param>
/// <param name="width">The image width.</param>
/// <param name="bitsPerPixel">The bits used per pixel.</param>
/// <param name="predictor">The tiff predictor used.</param>
public LzwTiffCompression(MemoryAllocator memoryAllocator, int width, int bitsPerPixel, TiffPredictor predictor)
: base(memoryAllocator, width, bitsPerPixel, predictor)
{ {
} }
@ -24,6 +33,11 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff.Compression
var subStream = new SubStream(stream, byteCount); var subStream = new SubStream(stream, byteCount);
var decoder = new TiffLzwDecoder(subStream, this.Allocator); var decoder = new TiffLzwDecoder(subStream, this.Allocator);
decoder.DecodePixels(buffer.Length, 8, buffer); decoder.DecodePixels(buffer.Length, 8, buffer);
if (this.Predictor == TiffPredictor.Horizontal)
{
HorizontalPredictor.Undo(buffer, this.Width, this.BitsPerPixel);
}
} }
} }
} }

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

@ -14,8 +14,12 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff.Compression
/// </summary> /// </summary>
internal class NoneTiffCompression : TiffBaseCompression internal class NoneTiffCompression : TiffBaseCompression
{ {
public NoneTiffCompression(MemoryAllocator allocator) /// <summary>
: base(allocator) /// Initializes a new instance of the <see cref="NoneTiffCompression" /> class.
/// </summary>
/// <param name="memoryAllocator">The memoryAllocator to use for buffer allocations.</param>
public NoneTiffCompression(MemoryAllocator memoryAllocator)
: base(memoryAllocator)
{ {
} }

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

@ -15,8 +15,12 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff.Compression
/// </summary> /// </summary>
internal class PackBitsTiffCompression : TiffBaseCompression internal class PackBitsTiffCompression : TiffBaseCompression
{ {
public PackBitsTiffCompression(MemoryAllocator allocator) /// <summary>
: base(allocator) /// Initializes a new instance of the <see cref="PackBitsTiffCompression" /> class.
/// </summary>
/// <param name="memoryAllocator">The memoryAllocator to use for buffer allocations.</param>
public PackBitsTiffCompression(MemoryAllocator memoryAllocator)
: base(memoryAllocator)
{ {
} }

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

@ -5,6 +5,7 @@ using System;
using System.IO; using System.IO;
using SixLabors.ImageSharp.Formats.Experimental.Tiff.Constants; using SixLabors.ImageSharp.Formats.Experimental.Tiff.Constants;
using SixLabors.ImageSharp.Formats.Tiff.Compression;
using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.Memory;
namespace SixLabors.ImageSharp.Formats.Experimental.Tiff.Compression namespace SixLabors.ImageSharp.Formats.Experimental.Tiff.Compression
@ -20,21 +21,37 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff.Compression
private int width; private int width;
private int bitsPerPixel;
private TiffPredictor predictor;
public TiffBaseCompression(MemoryAllocator allocator) => this.allocator = allocator; public TiffBaseCompression(MemoryAllocator allocator) => this.allocator = allocator;
public TiffBaseCompression(MemoryAllocator allocator, TiffPhotometricInterpretation photometricInterpretation, int width) public TiffBaseCompression(MemoryAllocator allocator, TiffPhotometricInterpretation photometricInterpretation, int width)
: this(allocator)
{ {
this.allocator = allocator;
this.photometricInterpretation = photometricInterpretation; this.photometricInterpretation = photometricInterpretation;
this.width = width; this.width = width;
} }
public TiffBaseCompression(MemoryAllocator allocator, int width, int bitsPerPixel, TiffPredictor predictor)
: this(allocator)
{
this.width = width;
this.bitsPerPixel = bitsPerPixel;
this.predictor = predictor;
}
protected MemoryAllocator Allocator => this.allocator; protected MemoryAllocator Allocator => this.allocator;
protected TiffPhotometricInterpretation PhotometricInterpretation => this.photometricInterpretation; protected TiffPhotometricInterpretation PhotometricInterpretation => this.photometricInterpretation;
protected int Width => this.width; protected int Width => this.width;
protected int BitsPerPixel => this.bitsPerPixel;
protected TiffPredictor Predictor => this.predictor;
/// <summary> /// <summary>
/// Decompresses image data into the supplied buffer. /// Decompresses image data into the supplied buffer.
/// </summary> /// </summary>

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

@ -8,7 +8,7 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff.Compression
{ {
internal static class TiffCompressionFactory internal static class TiffCompressionFactory
{ {
public static TiffBaseCompression Create(TiffDecoderCompressionType compressionType, MemoryAllocator allocator, TiffPhotometricInterpretation photometricInterpretation, int width) public static TiffBaseCompression Create(TiffDecoderCompressionType compressionType, MemoryAllocator allocator, TiffPhotometricInterpretation photometricInterpretation, int width, int bitsPerPixel, TiffPredictor predictor)
{ {
switch (compressionType) switch (compressionType)
{ {
@ -17,9 +17,9 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff.Compression
case TiffDecoderCompressionType.PackBits: case TiffDecoderCompressionType.PackBits:
return new PackBitsTiffCompression(allocator); return new PackBitsTiffCompression(allocator);
case TiffDecoderCompressionType.Deflate: case TiffDecoderCompressionType.Deflate:
return new DeflateTiffCompression(allocator); return new DeflateTiffCompression(allocator, width, bitsPerPixel, predictor);
case TiffDecoderCompressionType.Lzw: case TiffDecoderCompressionType.Lzw:
return new LzwTiffCompression(allocator); return new LzwTiffCompression(allocator, width, bitsPerPixel, predictor);
case TiffDecoderCompressionType.T4: case TiffDecoderCompressionType.T4:
return new T4TiffCompression(allocator, photometricInterpretation, width); return new T4TiffCompression(allocator, photometricInterpretation, width);
case TiffDecoderCompressionType.HuffmanRle: case TiffDecoderCompressionType.HuffmanRle:

2
src/ImageSharp/Formats/Tiff/TiffBitsPerPixel.cs

@ -14,7 +14,7 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff
Pixel1 = 1, Pixel1 = 1,
/// <summary> /// <summary>
/// 8 bits per pixel, grayscale image. Each pixel consists of 1 byte. /// 8 bits per pixel, grayscale or indexed image. Each pixel consists of 1 byte.
/// </summary> /// </summary>
Pixel8 = 8, Pixel8 = 8,

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

@ -241,6 +241,7 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff
frameMetaData = coreMetadata.GetTiffMetadata(); frameMetaData = coreMetadata.GetTiffMetadata();
frameMetaData.Tags = tags; frameMetaData.Tags = tags;
TiffFrameMetadata tiffFormatMetaData = coreMetadata.GetFormatMetadata(TiffFormat.Instance); TiffFrameMetadata tiffFormatMetaData = coreMetadata.GetFormatMetadata(TiffFormat.Instance);
TiffPredictor predictor = tiffFormatMetaData.Predictor;
this.VerifyAndParseOptions(frameMetaData); this.VerifyAndParseOptions(frameMetaData);
@ -254,52 +255,16 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff
if (this.PlanarConfiguration == TiffPlanarConfiguration.Planar) if (this.PlanarConfiguration == TiffPlanarConfiguration.Planar)
{ {
this.DecodeStripsPlanar(frame, rowsPerStrip, stripOffsets, stripByteCounts, width); this.DecodeStripsPlanar(frame, rowsPerStrip, stripOffsets, stripByteCounts, width, predictor);
} }
else else
{ {
this.DecodeStripsChunky(frame, rowsPerStrip, stripOffsets, stripByteCounts, width); this.DecodeStripsChunky(frame, rowsPerStrip, stripOffsets, stripByteCounts, width, predictor);
}
if (tiffFormatMetaData.Predictor == TiffPredictor.Horizontal)
{
this.UndoHorizontalPredictor(frame, width, height);
} }
return frame; return frame;
} }
/// <summary>
/// This will reverse the horizontal prediction operation.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="frame">The image frame.</param>
/// <param name="width">The width of the image.</param>
/// <param name="height">The height of the image.</param>
private void UndoHorizontalPredictor<TPixel>(ImageFrame<TPixel> frame, int width, int height)
where TPixel : unmanaged, IPixel<TPixel>
{
using System.Buffers.IMemoryOwner<Rgb24> rowRgbBuffer = this.memoryAllocator.Allocate<Rgb24>(width);
System.Span<Rgb24> rowRgb = rowRgbBuffer.GetSpan();
for (int y = 0; y < height; y++)
{
System.Span<TPixel> pixelRow = frame.GetPixelRowSpan(y);
PixelOperations<TPixel>.Instance.ToRgb24(this.configuration, pixelRow, rowRgb);
byte r = rowRgb[0].R;
byte g = rowRgb[0].G;
byte b = rowRgb[0].B;
for (int x = 1; x < width; x++)
{
ref TPixel pixel = ref pixelRow[x];
r += rowRgb[x].R;
g += rowRgb[x].G;
b += rowRgb[x].B;
var rgb = new Rgb24(r, g, b);
pixel.FromRgb24(rgb);
}
}
}
/// <summary> /// <summary>
/// Calculates the size (in bytes) for a pixel buffer using the determined color format. /// Calculates the size (in bytes) for a pixel buffer using the determined color format.
/// </summary> /// </summary>
@ -339,11 +304,17 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff
/// <param name="stripOffsets">An array of byte offsets to each strip in the image.</param> /// <param name="stripOffsets">An array of byte offsets to each strip in the image.</param>
/// <param name="stripByteCounts">An array of the size of each strip (in bytes).</param> /// <param name="stripByteCounts">An array of the size of each strip (in bytes).</param>
/// <param name="width">The image width.</param> /// <param name="width">The image width.</param>
private void DecodeStripsPlanar<TPixel>(ImageFrame<TPixel> frame, int rowsPerStrip, uint[] stripOffsets, uint[] stripByteCounts, int width) /// <param name="predictor">The tiff predictor used.</param>
private void DecodeStripsPlanar<TPixel>(ImageFrame<TPixel> frame, int rowsPerStrip, uint[] stripOffsets, uint[] stripByteCounts, int width, TiffPredictor predictor)
where TPixel : unmanaged, IPixel<TPixel> where TPixel : unmanaged, IPixel<TPixel>
{ {
int stripsPerPixel = this.BitsPerSample.Length; int stripsPerPixel = this.BitsPerSample.Length;
int stripsPerPlane = stripOffsets.Length / stripsPerPixel; int stripsPerPlane = stripOffsets.Length / stripsPerPixel;
int bitsPerPixel = 0;
foreach (var bits in this.BitsPerSample)
{
bitsPerPixel += bits;
}
Buffer2D<TPixel> pixels = frame.PixelBuffer; Buffer2D<TPixel> pixels = frame.PixelBuffer;
@ -357,7 +328,7 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff
stripBuffers[stripIndex] = this.memoryAllocator.AllocateManagedByteBuffer(uncompressedStripSize); stripBuffers[stripIndex] = this.memoryAllocator.AllocateManagedByteBuffer(uncompressedStripSize);
} }
TiffBaseCompression decompressor = TiffCompressionFactory.Create(this.CompressionType, this.memoryAllocator, this.PhotometricInterpretation, width); TiffBaseCompression decompressor = TiffCompressionFactory.Create(this.CompressionType, this.memoryAllocator, this.PhotometricInterpretation, width, bitsPerPixel, predictor);
RgbPlanarTiffColor<TPixel> colorDecoder = TiffColorDecoderFactory<TPixel>.CreatePlanar(this.ColorType, this.BitsPerSample, this.ColorMap); RgbPlanarTiffColor<TPixel> colorDecoder = TiffColorDecoderFactory<TPixel>.CreatePlanar(this.ColorType, this.BitsPerSample, this.ColorMap);
@ -385,16 +356,21 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff
} }
} }
private void DecodeStripsChunky<TPixel>(ImageFrame<TPixel> frame, int rowsPerStrip, uint[] stripOffsets, uint[] stripByteCounts, int width) private void DecodeStripsChunky<TPixel>(ImageFrame<TPixel> frame, int rowsPerStrip, uint[] stripOffsets, uint[] stripByteCounts, int width, TiffPredictor predictor)
where TPixel : unmanaged, IPixel<TPixel> where TPixel : unmanaged, IPixel<TPixel>
{ {
int uncompressedStripSize = this.CalculateStripBufferSize(frame.Width, rowsPerStrip); int uncompressedStripSize = this.CalculateStripBufferSize(frame.Width, rowsPerStrip);
int bitsPerPixel = 0;
foreach (var bits in this.BitsPerSample)
{
bitsPerPixel += bits;
}
using IManagedByteBuffer stripBuffer = this.memoryAllocator.AllocateManagedByteBuffer(uncompressedStripSize, AllocationOptions.Clean); using IManagedByteBuffer stripBuffer = this.memoryAllocator.AllocateManagedByteBuffer(uncompressedStripSize, AllocationOptions.Clean);
Buffer2D<TPixel> pixels = frame.PixelBuffer; Buffer2D<TPixel> pixels = frame.PixelBuffer;
TiffBaseCompression decompressor = TiffCompressionFactory.Create(this.CompressionType, this.memoryAllocator, this.PhotometricInterpretation, width); TiffBaseCompression decompressor = TiffCompressionFactory.Create(this.CompressionType, this.memoryAllocator, this.PhotometricInterpretation, width, bitsPerPixel, predictor);
TiffBaseColorDecoder<TPixel> colorDecoder = TiffColorDecoderFactory<TPixel>.Create(this.ColorType, this.BitsPerSample, this.ColorMap); TiffBaseColorDecoder<TPixel> colorDecoder = TiffColorDecoderFactory<TPixel>.Create(this.ColorType, this.BitsPerSample, this.ColorMap);

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

@ -3,6 +3,7 @@
using System.IO; using System.IO;
using SixLabors.ImageSharp.Formats.Experimental.Tiff.Compression; using SixLabors.ImageSharp.Formats.Experimental.Tiff.Compression;
using SixLabors.ImageSharp.Formats.Experimental.Tiff.Constants;
using SixLabors.ImageSharp.Formats.Png.Zlib; using SixLabors.ImageSharp.Formats.Png.Zlib;
using Xunit; using Xunit;
@ -23,7 +24,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff.Compression
{ {
var buffer = new byte[data.Length]; var buffer = new byte[data.Length];
new DeflateTiffCompression(null).Decompress(stream, (int)stream.Length, buffer); new DeflateTiffCompression(Configuration.Default.MemoryAllocator, 10, 8, TiffPredictor.None).Decompress(stream, (int)stream.Length, buffer);
Assert.Equal(data, buffer); Assert.Equal(data, buffer);
} }

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

@ -5,6 +5,7 @@ using System;
using System.IO; using System.IO;
using SixLabors.ImageSharp.Formats.Experimental.Tiff.Compression; using SixLabors.ImageSharp.Formats.Experimental.Tiff.Compression;
using SixLabors.ImageSharp.Formats.Experimental.Tiff.Constants;
using SixLabors.ImageSharp.Formats.Experimental.Tiff.Utils; using SixLabors.ImageSharp.Formats.Experimental.Tiff.Utils;
using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.Memory;
using Xunit; using Xunit;
@ -25,14 +26,14 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff.Compression
using Stream stream = CreateCompressedStream(data); using Stream stream = CreateCompressedStream(data);
var buffer = new byte[data.Length]; var buffer = new byte[data.Length];
new LzwTiffCompression(Configuration.Default.MemoryAllocator).Decompress(stream, (int)stream.Length, buffer); new LzwTiffCompression(Configuration.Default.MemoryAllocator, 10, 8, TiffPredictor.None).Decompress(stream, (int)stream.Length, buffer);
Assert.Equal(data, buffer); Assert.Equal(data, buffer);
} }
private static Stream CreateCompressedStream(byte[] inputData) private static Stream CreateCompressedStream(byte[] inputData)
{ {
using Stream compressedStream = new MemoryStream(); Stream compressedStream = new MemoryStream();
using System.Buffers.IMemoryOwner<byte> data = Configuration.Default.MemoryAllocator.Allocate<byte>(inputData.Length); using System.Buffers.IMemoryOwner<byte> data = Configuration.Default.MemoryAllocator.Allocate<byte>(inputData.Length);
inputData.AsSpan().CopyTo(data.GetSpan()); inputData.AsSpan().CopyTo(data.GetSpan());

4
tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs

@ -122,7 +122,9 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff
[WithFile(RgbLzwNoPredictorSinglestripMotorola, PixelTypes.Rgba32)] [WithFile(RgbLzwNoPredictorSinglestripMotorola, PixelTypes.Rgba32)]
[WithFile(RgbLzwNoPredictorMultistripMotorola, PixelTypes.Rgba32)] [WithFile(RgbLzwNoPredictorMultistripMotorola, PixelTypes.Rgba32)]
[WithFile(RgbLzwMultistripPredictor, PixelTypes.Rgba32)] [WithFile(RgbLzwMultistripPredictor, PixelTypes.Rgba32)]
[WithFile(Calliphora_RgbLzw_Predictor, PixelTypes.Rgba32)] [WithFile(Calliphora_RgbPaletteLzw_Predictor, PixelTypes.Rgba32)]
[WithFile(Calliphora_RgbLzwPredictor, PixelTypes.Rgba32)]
[WithFile(Calliphora_GrayscaleLzw_Predictor, PixelTypes.Rgba32)]
[WithFile(SmallRgbLzw, PixelTypes.Rgba32)] [WithFile(SmallRgbLzw, PixelTypes.Rgba32)]
public void TiffDecoder_CanDecode_LzwCompressed<TPixel>(TestImageProvider<TPixel> provider) public void TiffDecoder_CanDecode_LzwCompressed<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel> where TPixel : unmanaged, IPixel<TPixel>

7
tests/ImageSharp.Tests/TestImages.cs

@ -506,11 +506,14 @@ namespace SixLabors.ImageSharp.Tests
public const string Calliphora_GrayscaleUncompressed = "Tiff/Calliphora_grayscale_uncompressed.tiff"; public const string Calliphora_GrayscaleUncompressed = "Tiff/Calliphora_grayscale_uncompressed.tiff";
public const string Calliphora_GrayscaleDeflate_Predictor = "Tiff/Calliphora_gray_deflate_predictor.tiff"; public const string Calliphora_GrayscaleDeflate_Predictor = "Tiff/Calliphora_gray_deflate_predictor.tiff";
public const string Calliphora_GrayscaleLzw_Predictor = "Tiff/Calliphora_gray_lzw_predictor.tiff";
public const string Calliphora_GrayscaleDeflate = "Tiff/Calliphora_gray_deflate.tiff"; public const string Calliphora_GrayscaleDeflate = "Tiff/Calliphora_gray_deflate.tiff";
public const string Calliphora_PaletteUncompressed = "Tiff/Calliphora_palette_uncompressed.tiff";
public const string Calliphora_RgbDeflate_Predictor = "Tiff/Calliphora_rgb_deflate_predictor.tiff"; public const string Calliphora_RgbDeflate_Predictor = "Tiff/Calliphora_rgb_deflate_predictor.tiff";
public const string Calliphora_RgbJpeg = "Tiff/Calliphora_rgb_jpeg.tiff"; public const string Calliphora_RgbJpeg = "Tiff/Calliphora_rgb_jpeg.tiff";
public const string Calliphora_RgbLzw_Predictor = "Tiff/Calliphora_rgb_lzw_predictor.tiff"; public const string Calliphora_PaletteUncompressed = "Tiff/Calliphora_palette_uncompressed.tiff";
public const string Calliphora_RgbLzwPredictor = "Tiff/Calliphora_rgb_lzw_predictor.tiff";
public const string Calliphora_RgbPaletteLzw = "Tiff/Calliphora_rgb_palette_lzw.tiff";
public const string Calliphora_RgbPaletteLzw_Predictor = "Tiff/Calliphora_rgb_palette_lzw_predictor.tiff";
public const string Calliphora_RgbPackbits = "Tiff/Calliphora_rgb_packbits.tiff"; public const string Calliphora_RgbPackbits = "Tiff/Calliphora_rgb_packbits.tiff";
public const string Calliphora_RgbUncompressed = "Tiff/Calliphora_rgb_uncompressed.tiff"; public const string Calliphora_RgbUncompressed = "Tiff/Calliphora_rgb_uncompressed.tiff";
public const string Calliphora_Fax3Compressed = "Tiff/Calliphora_ccitt_fax3.tiff"; public const string Calliphora_Fax3Compressed = "Tiff/Calliphora_ccitt_fax3.tiff";

3
tests/Images/Input/Tiff/Calliphora_gray_lzw_predictor.tiff

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:3f24fd8f36a4847fcb84a317de4fd2eacd5eb0c58ef4436d33919f0a6658d0d9
size 698309

3
tests/Images/Input/Tiff/Calliphora_rgb_lzw.tif

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:53006876fcdc655a794462de57eb6b56f4d0cdd3cb8b752c63328db0eb4aa3c1
size 725085

4
tests/Images/Input/Tiff/Calliphora_rgb_lzw_predictor.tiff

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:29fa2b157c92f6a8bd4036e9d075e24fc451e72ec1a251d97a4b40454e01405c oid sha256:ecb529e5e3e0eca6f5e407b034fa8ba67bb4b9068af9e9b30425b08d30a249c0
size 792087 size 1756355

3
tests/Images/Input/Tiff/Calliphora_rgb_palette_lzw_predictor.tiff

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:29fa2b157c92f6a8bd4036e9d075e24fc451e72ec1a251d97a4b40454e01405c
size 792087
Loading…
Cancel
Save