diff --git a/src/ImageSharp/Formats/Tiff/README.md b/src/ImageSharp/Formats/Tiff/README.md
index 4d7bbbeb7..1a81f2286 100644
--- a/src/ImageSharp/Formats/Tiff/README.md
+++ b/src/ImageSharp/Formats/Tiff/README.md
@@ -40,7 +40,7 @@
| |Encoder|Decoder|Comments |
|---------------------------|:-----:|:-----:|--------------------------|
-|None | Y | Y | encoding only rgb so far |
+|None | Y | Y | |
|Ccitt1D | | Y | |
|PackBits | | Y | |
|CcittGroup3Fax | | Y | |
@@ -48,7 +48,7 @@
|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 | | | We should not even try to support this |
|Jpeg (Technote 2) | | | |
-|Deflate (Technote 2) | (Y) | Y | Based on PNG Deflate. Deflate encoding only for RGB now gray, should we allow this for palette too? |
+|Deflate (Technote 2) | (Y) | Y | Based on PNG Deflate. |
|Old Deflate (Technote 2) | | Y | |
### Photometric Interpretation Formats
@@ -75,7 +75,7 @@
|ImageWidth | Y | Y | |
|ImageLength | Y | Y | |
|BitsPerSample | Y | Y | |
-|Compression | | Y | |
+|Compression | Y | Y | |
|PhotometricInterpretation | Y | Y | |
|Thresholding | | | |
|CellWidth | | | |
diff --git a/src/ImageSharp/Formats/Tiff/TiffEncoderCore.cs b/src/ImageSharp/Formats/Tiff/TiffEncoderCore.cs
index f070eab31..7cf12afb5 100644
--- a/src/ImageSharp/Formats/Tiff/TiffEncoderCore.cs
+++ b/src/ImageSharp/Formats/Tiff/TiffEncoderCore.cs
@@ -153,7 +153,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff
switch (this.Mode)
{
case TiffEncodingMode.ColorPalette:
- imageDataBytes = writer.WritePalettedRgb(image, this.quantizer, this.padding, out colorMap);
+ imageDataBytes = writer.WritePalettedRgb(image, this.quantizer, this.padding, this.CompressionType, out colorMap);
break;
case TiffEncodingMode.Gray:
imageDataBytes = writer.WriteGray(image, this.padding, this.CompressionType);
@@ -389,6 +389,12 @@ namespace SixLabors.ImageSharp.Formats.Tiff
return (ushort)TiffCompression.Deflate;
}
+ if (this.CompressionType == TiffEncoderCompression.Deflate &&
+ this.Mode == TiffEncodingMode.ColorPalette)
+ {
+ return (ushort)TiffCompression.Deflate;
+ }
+
return (ushort)TiffCompression.None;
}
}
diff --git a/src/ImageSharp/Formats/Tiff/Utils/TiffWriter.cs b/src/ImageSharp/Formats/Tiff/Utils/TiffWriter.cs
index 028d53ab8..2c6e03d9c 100644
--- a/src/ImageSharp/Formats/Tiff/Utils/TiffWriter.cs
+++ b/src/ImageSharp/Formats/Tiff/Utils/TiffWriter.cs
@@ -201,10 +201,12 @@ namespace SixLabors.ImageSharp.Formats.Tiff
/// The padding bytes for each row.
/// The color map.
/// The number of bytes written.
- public int WritePalettedRgb(Image image, IQuantizer quantizer, int padding, out IExifValue colorMap)
+ public int WritePalettedRgb(Image image, IQuantizer quantizer, int padding, TiffEncoderCompression compression, out IExifValue colorMap)
where TPixel : unmanaged, IPixel
{
int colorPaletteSize = 256 * 3 * 2;
+ using var memoryStream = new MemoryStream();
+ using var deflateStream = new ZlibDeflateStream(this.memoryAllocator, memoryStream, PngCompressionLevel.Level6); // TODO: make compression level configurable
using IManagedByteBuffer row = this.AllocateRow(image.Width, 1, padding);
using IQuantizer frameQuantizer = quantizer.CreatePixelSpecificQuantizer(this.configuration);
using IndexedImageFrame quantized = frameQuantizer.BuildPaletteAndQuantizeFrame(image.Frames.RootFrame, image.Bounds());
@@ -253,16 +255,41 @@ namespace SixLabors.ImageSharp.Formats.Tiff
for (int y = 0; y < image.Height; y++)
{
ReadOnlySpan pixelSpan = quantized.GetPixelRowSpan(y);
- this.output.Write(pixelSpan);
- bytesWritten += pixelSpan.Length;
+
+ if (compression == TiffEncoderCompression.Deflate)
+ {
+ deflateStream.Write(pixelSpan);
+ }
+ else
+ {
+ // No compression.
+ this.output.Write(pixelSpan);
+ bytesWritten += pixelSpan.Length;
+ }
for (int i = 0; i < padding; i++)
{
- this.output.WriteByte(0);
- bytesWritten++;
+ if (compression == TiffEncoderCompression.Deflate)
+ {
+ deflateStream.WriteByte(0);
+ }
+ else
+ {
+ // no compression.
+ this.output.WriteByte(0);
+ bytesWritten++;
+ }
}
}
+ if (compression == TiffEncoderCompression.Deflate)
+ {
+ deflateStream.Flush();
+ byte[] buffer = memoryStream.ToArray();
+ this.output.Write(buffer);
+ bytesWritten += buffer.Length;
+ }
+
return bytesWritten;
}
diff --git a/tests/ImageSharp.Tests/Formats/Tiff/TiffEncoderTests.cs b/tests/ImageSharp.Tests/Formats/Tiff/TiffEncoderTests.cs
index 458acd34c..9c043b4ee 100644
--- a/tests/ImageSharp.Tests/Formats/Tiff/TiffEncoderTests.cs
+++ b/tests/ImageSharp.Tests/Formats/Tiff/TiffEncoderTests.cs
@@ -71,6 +71,12 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff
public void TiffEncoder_EncodeColorPalette_Works(TestImageProvider provider)
where TPixel : unmanaged, IPixel => TestTiffEncoderCore(provider, TiffBitsPerPixel.Pixel24, TiffEncodingMode.ColorPalette);
+ // TODO: this test fails, but the output looks correct. I thinks its due to the fact that a quantizer is used to create the palette.
+ [Theory]
+ [WithFile(TestImages.Tiff.Calliphora_PaletteUncompressed, PixelTypes.Rgba32)]
+ public void TiffEncoder_EncodeColorPalette_WithDeflateCompression_Works(TestImageProvider provider)
+ where TPixel : unmanaged, IPixel => TestTiffEncoderCore(provider, TiffBitsPerPixel.Pixel24, TiffEncodingMode.ColorPalette, TiffEncoderCompression.Deflate);
+
private static void TestTiffEncoderCore(
TestImageProvider provider,
TiffBitsPerPixel bitsPerPixel,