Browse Source

Add option to use deflate compression for bicolor images

pull/1570/head
Brian Popow 6 years ago
parent
commit
262b63f5eb
  1. 16
      src/ImageSharp/Formats/Tiff/TiffEncoderCore.cs
  2. 38
      src/ImageSharp/Formats/Tiff/Utils/TiffWriter.cs
  3. 10
      tests/ImageSharp.Tests/Formats/Tiff/TiffEncoderTests.cs

16
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;
}

38
src/ImageSharp/Formats/Tiff/Utils/TiffWriter.cs

@ -357,15 +357,24 @@ namespace SixLabors.ImageSharp.Formats.Tiff
return bytesWritten;
}
public int WriteBiColor<TPixel>(Image<TPixel> image)
/// <summary>
/// Writes the image data as 1 bit black and white to the stream.
/// </summary>
/// <typeparam name="TPixel">The pixel data.</typeparam>
/// <param name="image">The image to write to the stream.</param>
/// <param name="compression">The compression to use.</param>
/// <returns>The number of bytes written.</returns>
public int WriteBiColor<TPixel>(Image<TPixel> image, TiffEncoderCompression compression)
where TPixel : unmanaged, IPixel<TPixel>
{
int padding = image.Width % 8 == 0 ? 0 : 1;
int bytesPerRow = (image.Width / 8) + padding;
using IMemoryOwner<Rgb24> rowRgb = this.memoryAllocator.Allocate<Rgb24>(image.Width);
using IMemoryOwner<L8> rowL8 = this.memoryAllocator.Allocate<L8>(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<byte> rowSpan = row.GetSpan();
Span<Rgb24> rowRgbSpan = rowRgb.GetSpan();
Span<L8> rowL8Span = rowL8.GetSpan();
// Convert image to black and white.
using Image<TPixel> imageClone = image.Clone();
@ -377,11 +386,11 @@ namespace SixLabors.ImageSharp.Formats.Tiff
int bitIndex = 0;
int byteIndex = 0;
Span<TPixel> pixelRow = imageClone.GetPixelRowSpan(y);
PixelOperations<TPixel>.Instance.ToRgb24(this.configuration, pixelRow, rowRgbSpan);
PixelOperations<TPixel>.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;
}

10
tests/ImageSharp.Tests/Formats/Tiff/TiffEncoderTests.cs

@ -77,6 +77,16 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff
public void TiffEncoder_EncodeColorPalette_WithDeflateCompression_Works<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel> => TestTiffEncoderCore(provider, TiffBitsPerPixel.Pixel24, TiffEncodingMode.ColorPalette, TiffEncoderCompression.Deflate);
[Theory]
[WithFile(TestImages.Tiff.Calliphora_HuffmanCompressed, PixelTypes.Rgba32)]
public void TiffEncoder_EncodeBiColor_Works<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel> => TestTiffEncoderCore(provider, TiffBitsPerPixel.Pixel24, TiffEncodingMode.BiColor);
[Theory]
[WithFile(TestImages.Tiff.Calliphora_HuffmanCompressed, PixelTypes.Rgba32)]
public void TiffEncoder_EncodeBiColor_WithDeflateCompression_Works<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel> => TestTiffEncoderCore(provider, TiffBitsPerPixel.Pixel24, TiffEncodingMode.BiColor, TiffEncoderCompression.Deflate);
private static void TestTiffEncoderCore<TPixel>(
TestImageProvider<TPixel> provider,
TiffBitsPerPixel bitsPerPixel,

Loading…
Cancel
Save