From 3f612b736f46d2df4785b67b0946e1496a5a0291 Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Sat, 28 Nov 2020 16:56:24 +0100 Subject: [PATCH] Split up WriteBiColor in Deflate and no compression --- .../Formats/Tiff/Utils/TiffWriter.cs | 82 ++++++++++++++----- 1 file changed, 60 insertions(+), 22 deletions(-) diff --git a/src/ImageSharp/Formats/Tiff/Utils/TiffWriter.cs b/src/ImageSharp/Formats/Tiff/Utils/TiffWriter.cs index 3a0fcea75a..586eb0a55c 100644 --- a/src/ImageSharp/Formats/Tiff/Utils/TiffWriter.cs +++ b/src/ImageSharp/Formats/Tiff/Utils/TiffWriter.cs @@ -369,30 +369,33 @@ namespace SixLabors.ImageSharp.Formats.Tiff { int padding = image.Width % 8 == 0 ? 0 : 1; int bytesPerRow = (image.Width / 8) + padding; - using IMemoryOwner rowL8 = this.memoryAllocator.Allocate(image.Width); + using IMemoryOwner pixelRowAsGray = 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 rowL8Span = rowL8.GetSpan(); + Span outputRow = row.GetSpan(); + Span pixelRowAsGraySpan = pixelRowAsGray.GetSpan(); // Convert image to black and white. using Image imageClone = image.Clone(); imageClone.Mutate(img => img.BinaryDither(default(ErrorDither))); + if (compression == TiffEncoderCompression.Deflate) + { + return this.WriteBiColorDeflate(image, pixelRowAsGraySpan, outputRow); + } + int bytesWritten = 0; for (int y = 0; y < image.Height; y++) { int bitIndex = 0; int byteIndex = 0; Span pixelRow = imageClone.GetPixelRowSpan(y); - PixelOperations.Instance.ToL8(this.configuration, pixelRow, rowL8Span); + PixelOperations.Instance.ToL8(this.configuration, pixelRow, pixelRowAsGraySpan); for (int x = 0; x < pixelRow.Length; x++) { int shift = 7 - bitIndex; - if (rowL8Span[x].PackedValue == 255) + if (pixelRowAsGraySpan[x].PackedValue == 255) { - rowSpan[byteIndex] |= (byte)(1 << shift); + outputRow[byteIndex] |= (byte)(1 << shift); } bitIndex++; @@ -403,27 +406,62 @@ namespace SixLabors.ImageSharp.Formats.Tiff } } - if (compression == TiffEncoderCompression.Deflate) - { - deflateStream.Write(row); - } - else - { - this.output.Write(row); - bytesWritten += row.Length(); - } + this.output.Write(row); + bytesWritten += row.Length(); row.Clear(); } - if (compression == TiffEncoderCompression.Deflate) + return bytesWritten; + } + + /// + /// Writes the image data as 1 bit black and white with deflate compression to the stream. + /// + /// The pixel data. + /// The image to write to the stream. + /// A span for converting a pixel row to gray. + /// A span which will be used to store the output pixels. + /// The number of bytes written. + public int WriteBiColorDeflate(Image image, Span pixelRowAsGraySpan, Span outputRow) + where TPixel : unmanaged, IPixel + { + using var memoryStream = new MemoryStream(); + using var deflateStream = new ZlibDeflateStream(this.memoryAllocator, memoryStream, PngCompressionLevel.Level6); // TODO: make compression level configurable + + int bytesWritten = 0; + for (int y = 0; y < image.Height; y++) { - deflateStream.Flush(); - byte[] buffer = memoryStream.ToArray(); - this.output.Write(buffer); - bytesWritten += buffer.Length; + int bitIndex = 0; + int byteIndex = 0; + Span pixelRow = image.GetPixelRowSpan(y); + PixelOperations.Instance.ToL8(this.configuration, pixelRow, pixelRowAsGraySpan); + for (int x = 0; x < pixelRow.Length; x++) + { + int shift = 7 - bitIndex; + if (pixelRowAsGraySpan[x].PackedValue == 255) + { + outputRow[byteIndex] |= (byte)(1 << shift); + } + + bitIndex++; + if (bitIndex == 8) + { + byteIndex++; + bitIndex = 0; + } + } + + deflateStream.Write(outputRow); + + outputRow.Clear(); } + deflateStream.Flush(); + byte[] buffer = memoryStream.ToArray(); + this.output.Write(buffer); + bytesWritten += buffer.Length; + return bytesWritten; }