diff --git a/src/ImageSharp/Formats/Tiff/TiffEncoderCore.cs b/src/ImageSharp/Formats/Tiff/TiffEncoderCore.cs index a0e204bd29..75d078ccd6 100644 --- a/src/ImageSharp/Formats/Tiff/TiffEncoderCore.cs +++ b/src/ImageSharp/Formats/Tiff/TiffEncoderCore.cs @@ -159,7 +159,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff imageDataBytes = writer.WriteGray(image, this.padding, this.CompressionType); break; case TiffEncodingMode.BiColor: - imageDataBytes = writer.WriteBiColor(image); + imageDataBytes = writer.WriteBiColor(image, this.CompressionType); break; default: imageDataBytes = writer.WriteRgbImageData(image, this.padding, this.CompressionType); @@ -386,20 +386,22 @@ namespace SixLabors.ImageSharp.Formats.Tiff private ushort GetCompressionType() { - if (this.CompressionType == TiffEncoderCompression.Deflate && - this.Mode == TiffEncodingMode.Rgb) + if (this.CompressionType == TiffEncoderCompression.Deflate && this.Mode == TiffEncodingMode.Rgb) { return (ushort)TiffCompression.Deflate; } - if (this.CompressionType == TiffEncoderCompression.Deflate && - this.Mode == TiffEncodingMode.Gray) + if (this.CompressionType == TiffEncoderCompression.Deflate && this.Mode == TiffEncodingMode.Gray) { return (ushort)TiffCompression.Deflate; } - if (this.CompressionType == TiffEncoderCompression.Deflate && - this.Mode == TiffEncodingMode.ColorPalette) + if (this.CompressionType == TiffEncoderCompression.Deflate && this.Mode == TiffEncodingMode.ColorPalette) + { + return (ushort)TiffCompression.Deflate; + } + + if (this.CompressionType == TiffEncoderCompression.Deflate && this.Mode == TiffEncodingMode.BiColor) { return (ushort)TiffCompression.Deflate; } diff --git a/src/ImageSharp/Formats/Tiff/Utils/TiffWriter.cs b/src/ImageSharp/Formats/Tiff/Utils/TiffWriter.cs index d018248edc..3a0fcea75a 100644 --- a/src/ImageSharp/Formats/Tiff/Utils/TiffWriter.cs +++ b/src/ImageSharp/Formats/Tiff/Utils/TiffWriter.cs @@ -357,15 +357,24 @@ namespace SixLabors.ImageSharp.Formats.Tiff return bytesWritten; } - public int WriteBiColor(Image image) + /// + /// Writes the image data as 1 bit black and white to the stream. + /// + /// The pixel data. + /// The image to write to the stream. + /// The compression to use. + /// The number of bytes written. + public int WriteBiColor(Image image, TiffEncoderCompression compression) where TPixel : unmanaged, IPixel { int padding = image.Width % 8 == 0 ? 0 : 1; int bytesPerRow = (image.Width / 8) + padding; - using IMemoryOwner rowRgb = this.memoryAllocator.Allocate(image.Width); + using IMemoryOwner rowL8 = this.memoryAllocator.Allocate(image.Width); using IManagedByteBuffer row = this.memoryAllocator.AllocateManagedByteBuffer(bytesPerRow, AllocationOptions.Clean); + using var memoryStream = new MemoryStream(); + using var deflateStream = new ZlibDeflateStream(this.memoryAllocator, memoryStream, PngCompressionLevel.Level6); // TODO: make compression level configurable Span rowSpan = row.GetSpan(); - Span rowRgbSpan = rowRgb.GetSpan(); + Span rowL8Span = rowL8.GetSpan(); // Convert image to black and white. using Image imageClone = image.Clone(); @@ -377,11 +386,11 @@ namespace SixLabors.ImageSharp.Formats.Tiff int bitIndex = 0; int byteIndex = 0; Span pixelRow = imageClone.GetPixelRowSpan(y); - PixelOperations.Instance.ToRgb24(this.configuration, pixelRow, rowRgbSpan); + PixelOperations.Instance.ToL8(this.configuration, pixelRow, rowL8Span); for (int x = 0; x < pixelRow.Length; x++) { int shift = 7 - bitIndex; - if (rowRgbSpan[x].R == 255) + if (rowL8Span[x].PackedValue == 255) { rowSpan[byteIndex] |= (byte)(1 << shift); } @@ -394,12 +403,27 @@ namespace SixLabors.ImageSharp.Formats.Tiff } } - this.output.Write(row); - bytesWritten += row.Length(); + if (compression == TiffEncoderCompression.Deflate) + { + deflateStream.Write(row); + } + else + { + this.output.Write(row); + bytesWritten += row.Length(); + } row.Clear(); } + 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 9c043b4ee2..91a735897e 100644 --- a/tests/ImageSharp.Tests/Formats/Tiff/TiffEncoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Tiff/TiffEncoderTests.cs @@ -77,6 +77,16 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff public void TiffEncoder_EncodeColorPalette_WithDeflateCompression_Works(TestImageProvider provider) where TPixel : unmanaged, IPixel => TestTiffEncoderCore(provider, TiffBitsPerPixel.Pixel24, TiffEncodingMode.ColorPalette, TiffEncoderCompression.Deflate); + [Theory] + [WithFile(TestImages.Tiff.Calliphora_HuffmanCompressed, PixelTypes.Rgba32)] + public void TiffEncoder_EncodeBiColor_Works(TestImageProvider provider) + where TPixel : unmanaged, IPixel => TestTiffEncoderCore(provider, TiffBitsPerPixel.Pixel24, TiffEncodingMode.BiColor); + + [Theory] + [WithFile(TestImages.Tiff.Calliphora_HuffmanCompressed, PixelTypes.Rgba32)] + public void TiffEncoder_EncodeBiColor_WithDeflateCompression_Works(TestImageProvider provider) + where TPixel : unmanaged, IPixel => TestTiffEncoderCore(provider, TiffBitsPerPixel.Pixel24, TiffEncodingMode.BiColor, TiffEncoderCompression.Deflate); + private static void TestTiffEncoderCore( TestImageProvider provider, TiffBitsPerPixel bitsPerPixel,