Browse Source

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

pull/1570/head
Brian Popow 5 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.IO;
using System.IO.Compression;
using SixLabors.ImageSharp.Formats.Experimental.Tiff.Constants;
using SixLabors.ImageSharp.Formats.Experimental.Tiff.Utils;
using SixLabors.ImageSharp.Formats.Tiff.Compression;
using SixLabors.ImageSharp.Memory;
namespace SixLabors.ImageSharp.Formats.Experimental.Tiff.Compression
@ -17,8 +20,15 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff.Compression
/// </remarks>
internal class DeflateTiffCompression : TiffBaseCompression
{
public DeflateTiffCompression(MemoryAllocator allocator)
: base(allocator)
/// <summary>
/// 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);
}
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.IO;
using SixLabors.ImageSharp.Formats.Experimental.Tiff.Constants;
using SixLabors.ImageSharp.Formats.Experimental.Tiff.Utils;
using SixLabors.ImageSharp.Formats.Tiff.Compression;
using SixLabors.ImageSharp.Memory;
namespace SixLabors.ImageSharp.Formats.Experimental.Tiff.Compression
@ -13,8 +15,15 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff.Compression
/// </summary>
internal class LzwTiffCompression : TiffBaseCompression
{
public LzwTiffCompression(MemoryAllocator allocator)
: base(allocator)
/// <summary>
/// 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 decoder = new TiffLzwDecoder(subStream, this.Allocator);
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>
internal class NoneTiffCompression : TiffBaseCompression
{
public NoneTiffCompression(MemoryAllocator allocator)
: base(allocator)
/// <summary>
/// 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>
internal class PackBitsTiffCompression : TiffBaseCompression
{
public PackBitsTiffCompression(MemoryAllocator allocator)
: base(allocator)
/// <summary>
/// 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 SixLabors.ImageSharp.Formats.Experimental.Tiff.Constants;
using SixLabors.ImageSharp.Formats.Tiff.Compression;
using SixLabors.ImageSharp.Memory;
namespace SixLabors.ImageSharp.Formats.Experimental.Tiff.Compression
@ -20,21 +21,37 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff.Compression
private int width;
private int bitsPerPixel;
private TiffPredictor predictor;
public TiffBaseCompression(MemoryAllocator allocator) => this.allocator = allocator;
public TiffBaseCompression(MemoryAllocator allocator, TiffPhotometricInterpretation photometricInterpretation, int width)
: this(allocator)
{
this.allocator = allocator;
this.photometricInterpretation = photometricInterpretation;
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 TiffPhotometricInterpretation PhotometricInterpretation => this.photometricInterpretation;
protected int Width => this.width;
protected int BitsPerPixel => this.bitsPerPixel;
protected TiffPredictor Predictor => this.predictor;
/// <summary>
/// Decompresses image data into the supplied buffer.
/// </summary>

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

@ -8,7 +8,7 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff.Compression
{
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)
{
@ -17,9 +17,9 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff.Compression
case TiffDecoderCompressionType.PackBits:
return new PackBitsTiffCompression(allocator);
case TiffDecoderCompressionType.Deflate:
return new DeflateTiffCompression(allocator);
return new DeflateTiffCompression(allocator, width, bitsPerPixel, predictor);
case TiffDecoderCompressionType.Lzw:
return new LzwTiffCompression(allocator);
return new LzwTiffCompression(allocator, width, bitsPerPixel, predictor);
case TiffDecoderCompressionType.T4:
return new T4TiffCompression(allocator, photometricInterpretation, width);
case TiffDecoderCompressionType.HuffmanRle:

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

@ -14,7 +14,7 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff
Pixel1 = 1,
/// <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>
Pixel8 = 8,

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

@ -241,6 +241,7 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff
frameMetaData = coreMetadata.GetTiffMetadata();
frameMetaData.Tags = tags;
TiffFrameMetadata tiffFormatMetaData = coreMetadata.GetFormatMetadata(TiffFormat.Instance);
TiffPredictor predictor = tiffFormatMetaData.Predictor;
this.VerifyAndParseOptions(frameMetaData);
@ -254,52 +255,16 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff
if (this.PlanarConfiguration == TiffPlanarConfiguration.Planar)
{
this.DecodeStripsPlanar(frame, rowsPerStrip, stripOffsets, stripByteCounts, width);
this.DecodeStripsPlanar(frame, rowsPerStrip, stripOffsets, stripByteCounts, width, predictor);
}
else
{
this.DecodeStripsChunky(frame, rowsPerStrip, stripOffsets, stripByteCounts, width);
}
if (tiffFormatMetaData.Predictor == TiffPredictor.Horizontal)
{
this.UndoHorizontalPredictor(frame, width, height);
this.DecodeStripsChunky(frame, rowsPerStrip, stripOffsets, stripByteCounts, width, predictor);
}
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>
/// Calculates the size (in bytes) for a pixel buffer using the determined color format.
/// </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="stripByteCounts">An array of the size of each strip (in bytes).</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>
{
int stripsPerPixel = this.BitsPerSample.Length;
int stripsPerPlane = stripOffsets.Length / stripsPerPixel;
int bitsPerPixel = 0;
foreach (var bits in this.BitsPerSample)
{
bitsPerPixel += bits;
}
Buffer2D<TPixel> pixels = frame.PixelBuffer;
@ -357,7 +328,7 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff
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);
@ -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>
{
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);
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);

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

@ -3,6 +3,7 @@
using System.IO;
using SixLabors.ImageSharp.Formats.Experimental.Tiff.Compression;
using SixLabors.ImageSharp.Formats.Experimental.Tiff.Constants;
using SixLabors.ImageSharp.Formats.Png.Zlib;
using Xunit;
@ -23,7 +24,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff.Compression
{
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);
}

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

@ -5,6 +5,7 @@ using System;
using System.IO;
using SixLabors.ImageSharp.Formats.Experimental.Tiff.Compression;
using SixLabors.ImageSharp.Formats.Experimental.Tiff.Constants;
using SixLabors.ImageSharp.Formats.Experimental.Tiff.Utils;
using SixLabors.ImageSharp.Memory;
using Xunit;
@ -25,14 +26,14 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff.Compression
using Stream stream = CreateCompressedStream(data);
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);
}
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);
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(RgbLzwNoPredictorMultistripMotorola, 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)]
public void TiffDecoder_CanDecode_LzwCompressed<TPixel>(TestImageProvider<TPixel> provider)
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_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_PaletteUncompressed = "Tiff/Calliphora_palette_uncompressed.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_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_RgbUncompressed = "Tiff/Calliphora_rgb_uncompressed.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
oid sha256:29fa2b157c92f6a8bd4036e9d075e24fc451e72ec1a251d97a4b40454e01405c
size 792087
oid sha256:ecb529e5e3e0eca6f5e407b034fa8ba67bb4b9068af9e9b30425b08d30a249c0
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