Browse Source

Add tiff encoder option to choose the deflate compression level

pull/1467/head
Brian Popow 5 years ago
parent
commit
20fcf84311
  1. 2
      src/ImageSharp/Formats/Png/DeflateCompressionLevel.cs
  2. 4
      src/ImageSharp/Formats/Png/IPngEncoderOptions.cs
  3. 2
      src/ImageSharp/Formats/Png/PngEncoder.cs
  4. 2
      src/ImageSharp/Formats/Png/PngEncoderOptions.cs
  5. 2
      src/ImageSharp/Formats/Png/Zlib/ZlibDeflateStream.cs
  6. 7
      src/ImageSharp/Formats/Tiff/ITiffEncoderOptions.cs
  7. 22
      src/ImageSharp/Formats/Tiff/TiffEncoder.cs
  8. 17
      src/ImageSharp/Formats/Tiff/TiffEncoderCore.cs
  9. 44
      src/ImageSharp/Formats/Tiff/Utils/TiffWriter.cs
  10. 28
      tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs
  11. 2
      tests/ImageSharp.Tests/Formats/Tiff/Compression/DeflateTiffCompressionTests.cs
  12. 2
      tests/ImageSharp.Tests/Image/ImageTests.SaveAsync.cs

2
src/ImageSharp/Formats/Png/PngCompressionLevel.cs → src/ImageSharp/Formats/Png/DeflateCompressionLevel.cs

@ -6,7 +6,7 @@ namespace SixLabors.ImageSharp.Formats.Png
/// <summary> /// <summary>
/// Provides enumeration of available PNG compression levels. /// Provides enumeration of available PNG compression levels.
/// </summary> /// </summary>
public enum PngCompressionLevel public enum DeflateCompressionLevel
{ {
/// <summary> /// <summary>
/// Level 0. Equivalent to <see cref="NoCompression"/>. /// Level 0. Equivalent to <see cref="NoCompression"/>.

4
src/ImageSharp/Formats/Png/IPngEncoderOptions.cs

@ -28,9 +28,9 @@ namespace SixLabors.ImageSharp.Formats.Png
/// <summary> /// <summary>
/// Gets the compression level 1-9. /// Gets the compression level 1-9.
/// <remarks>Defaults to <see cref="PngCompressionLevel.DefaultCompression"/>.</remarks> /// <remarks>Defaults to <see cref="DeflateCompressionLevel.DefaultCompression"/>.</remarks>
/// </summary> /// </summary>
PngCompressionLevel CompressionLevel { get; } DeflateCompressionLevel CompressionLevel { get; }
/// <summary> /// <summary>
/// Gets the threshold of characters in text metadata, when compression should be used. /// Gets the threshold of characters in text metadata, when compression should be used.

2
src/ImageSharp/Formats/Png/PngEncoder.cs

@ -25,7 +25,7 @@ namespace SixLabors.ImageSharp.Formats.Png
public PngFilterMethod? FilterMethod { get; set; } public PngFilterMethod? FilterMethod { get; set; }
/// <inheritdoc/> /// <inheritdoc/>
public PngCompressionLevel CompressionLevel { get; set; } = PngCompressionLevel.DefaultCompression; public DeflateCompressionLevel CompressionLevel { get; set; } = DeflateCompressionLevel.DefaultCompression;
/// <inheritdoc/> /// <inheritdoc/>
public int TextCompressionThreshold { get; set; } = 1024; public int TextCompressionThreshold { get; set; } = 1024;

2
src/ImageSharp/Formats/Png/PngEncoderOptions.cs

@ -44,7 +44,7 @@ namespace SixLabors.ImageSharp.Formats.Png
public PngFilterMethod? FilterMethod { get; } public PngFilterMethod? FilterMethod { get; }
/// <inheritdoc/> /// <inheritdoc/>
public PngCompressionLevel CompressionLevel { get; } = PngCompressionLevel.DefaultCompression; public DeflateCompressionLevel CompressionLevel { get; } = DeflateCompressionLevel.DefaultCompression;
/// <inheritdoc/> /// <inheritdoc/>
public int TextCompressionThreshold { get; } public int TextCompressionThreshold { get; }

2
src/ImageSharp/Formats/Png/Zlib/ZlibDeflateStream.cs

@ -48,7 +48,7 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib
/// <param name="memoryAllocator">The memory allocator to use for buffer allocations.</param> /// <param name="memoryAllocator">The memory allocator to use for buffer allocations.</param>
/// <param name="stream">The stream to compress.</param> /// <param name="stream">The stream to compress.</param>
/// <param name="level">The compression level.</param> /// <param name="level">The compression level.</param>
public ZlibDeflateStream(MemoryAllocator memoryAllocator, Stream stream, PngCompressionLevel level) public ZlibDeflateStream(MemoryAllocator memoryAllocator, Stream stream, DeflateCompressionLevel level)
{ {
int compressionLevel = (int)level; int compressionLevel = (int)level;
this.rawStream = stream; this.rawStream = stream;

7
src/ImageSharp/Formats/Tiff/ITiffEncoderOptions.cs

@ -1,6 +1,7 @@
// Copyright (c) Six Labors. // Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.Formats.Png;
using SixLabors.ImageSharp.Processing.Processors.Quantization; using SixLabors.ImageSharp.Processing.Processors.Quantization;
namespace SixLabors.ImageSharp.Formats.Experimental.Tiff namespace SixLabors.ImageSharp.Formats.Experimental.Tiff
@ -15,6 +16,12 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff
/// </summary> /// </summary>
TiffEncoderCompression Compression { get; } TiffEncoderCompression Compression { get; }
/// <summary>
/// Gets the compression level 1-9 for the deflate compression mode.
/// <remarks>Defaults to <see cref="DeflateCompressionLevel.DefaultCompression"/>.</remarks>
/// </summary>
DeflateCompressionLevel CompressionLevel { get; }
/// <summary> /// <summary>
/// Gets the encoding mode to use. RGB, RGB with color palette or gray. /// Gets the encoding mode to use. RGB, RGB with color palette or gray.
/// </summary> /// </summary>

22
src/ImageSharp/Formats/Tiff/TiffEncoder.cs

@ -4,7 +4,9 @@
using System.IO; using System.IO;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Formats.Png;
using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing.Processors.Quantization; using SixLabors.ImageSharp.Processing.Processors.Quantization;
@ -15,25 +17,19 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff
/// </summary> /// </summary>
public class TiffEncoder : IImageEncoder, ITiffEncoderOptions public class TiffEncoder : IImageEncoder, ITiffEncoderOptions
{ {
/// <summary> /// <inheritdoc/>
/// Gets or sets a value indicating which compression to use.
/// </summary>
public TiffEncoderCompression Compression { get; set; } = TiffEncoderCompression.None; public TiffEncoderCompression Compression { get; set; } = TiffEncoderCompression.None;
/// <summary> /// <inheritdoc/>
/// Gets or sets the encoding mode to use. RGB, RGB with a color palette or gray. public DeflateCompressionLevel CompressionLevel { get; } = DeflateCompressionLevel.DefaultCompression;
/// </summary>
/// <inheritdoc/>
public TiffEncodingMode Mode { get; set; } public TiffEncodingMode Mode { get; set; }
/// <summary> /// <inheritdoc/>
/// Gets or sets a value indicating whether to use horizontal prediction. This can improve the compression ratio with deflate or lzw compression.
/// </summary>
public bool UseHorizontalPredictor { get; set; } public bool UseHorizontalPredictor { get; set; }
/// <summary> /// <inheritdoc/>
/// Gets or sets the quantizer for color images with a palette.
/// Defaults to OctreeQuantizer.
/// </summary>
public IQuantizer Quantizer { get; set; } public IQuantizer Quantizer { get; set; }
/// <inheritdoc/> /// <inheritdoc/>

17
src/ImageSharp/Formats/Tiff/TiffEncoderCore.cs

@ -9,6 +9,7 @@ using System.Threading;
using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Formats.Experimental.Tiff.Constants; using SixLabors.ImageSharp.Formats.Experimental.Tiff.Constants;
using SixLabors.ImageSharp.Formats.Experimental.Tiff.Utils; using SixLabors.ImageSharp.Formats.Experimental.Tiff.Utils;
using SixLabors.ImageSharp.Formats.Png;
using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.Metadata; using SixLabors.ImageSharp.Metadata;
using SixLabors.ImageSharp.Metadata.Profiles.Exif; using SixLabors.ImageSharp.Metadata.Profiles.Exif;
@ -51,7 +52,12 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff
/// <summary> /// <summary>
/// Indicating whether to use horizontal prediction. This can improve the compression ratio with deflate compression. /// Indicating whether to use horizontal prediction. This can improve the compression ratio with deflate compression.
/// </summary> /// </summary>
private bool useHorizontalPredictor; private readonly bool useHorizontalPredictor;
/// <summary>
/// Sets the deflate compression level.
/// </summary>
private readonly DeflateCompressionLevel compressionLevel;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="TiffEncoderCore"/> class. /// Initializes a new instance of the <see cref="TiffEncoderCore"/> class.
@ -65,6 +71,7 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff
this.Mode = options.Mode; this.Mode = options.Mode;
this.quantizer = options.Quantizer ?? KnownQuantizers.Octree; this.quantizer = options.Quantizer ?? KnownQuantizers.Octree;
this.useHorizontalPredictor = options.UseHorizontalPredictor; this.useHorizontalPredictor = options.UseHorizontalPredictor;
this.compressionLevel = options.CompressionLevel;
} }
/// <summary> /// <summary>
@ -165,16 +172,16 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff
switch (this.Mode) switch (this.Mode)
{ {
case TiffEncodingMode.ColorPalette: case TiffEncodingMode.ColorPalette:
imageDataBytes = writer.WritePalettedRgb(image, this.quantizer, this.padding, this.CompressionType, this.useHorizontalPredictor, out colorMap); imageDataBytes = writer.WritePalettedRgb(image, this.quantizer, this.padding, this.CompressionType, this.compressionLevel, this.useHorizontalPredictor, out colorMap);
break; break;
case TiffEncodingMode.Gray: case TiffEncodingMode.Gray:
imageDataBytes = writer.WriteGray(image, this.padding, this.CompressionType, this.useHorizontalPredictor); imageDataBytes = writer.WriteGray(image, this.padding, this.CompressionType, this.compressionLevel, this.useHorizontalPredictor);
break; break;
case TiffEncodingMode.BiColor: case TiffEncodingMode.BiColor:
imageDataBytes = writer.WriteBiColor(image, this.CompressionType); imageDataBytes = writer.WriteBiColor(image, this.CompressionType, this.compressionLevel);
break; break;
default: default:
imageDataBytes = writer.WriteRgb(image, this.padding, this.CompressionType, this.useHorizontalPredictor); imageDataBytes = writer.WriteRgb(image, this.padding, this.CompressionType, this.compressionLevel, this.useHorizontalPredictor);
break; break;
} }

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

@ -138,16 +138,17 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff.Utils
/// <param name="image">The image to write to the stream.</param> /// <param name="image">The image to write to the stream.</param>
/// <param name="padding">The padding bytes for each row.</param> /// <param name="padding">The padding bytes for each row.</param>
/// <param name="compression">The compression to use.</param> /// <param name="compression">The compression to use.</param>
/// <param name="compressionLevel">The compression level for deflate compression.</param>
/// <param name="useHorizontalPredictor">Indicates if horizontal prediction should be used. Should only be used with deflate compression.</param> /// <param name="useHorizontalPredictor">Indicates if horizontal prediction should be used. Should only be used with deflate compression.</param>
/// <returns>The number of bytes written.</returns> /// <returns>The number of bytes written.</returns>
public int WriteRgb<TPixel>(Image<TPixel> image, int padding, TiffEncoderCompression compression, bool useHorizontalPredictor) public int WriteRgb<TPixel>(Image<TPixel> image, int padding, TiffEncoderCompression compression, DeflateCompressionLevel compressionLevel, bool useHorizontalPredictor)
where TPixel : unmanaged, IPixel<TPixel> where TPixel : unmanaged, IPixel<TPixel>
{ {
using IManagedByteBuffer row = this.AllocateRow(image.Width, 3, padding); using IManagedByteBuffer row = this.AllocateRow(image.Width, 3, padding);
Span<byte> rowSpan = row.GetSpan(); Span<byte> rowSpan = row.GetSpan();
if (compression == TiffEncoderCompression.Deflate) if (compression == TiffEncoderCompression.Deflate)
{ {
return this.WriteDeflateCompressedRgb(image, rowSpan, useHorizontalPredictor); return this.WriteDeflateCompressedRgb(image, rowSpan, compressionLevel, useHorizontalPredictor);
} }
if (compression == TiffEncoderCompression.Lzw) if (compression == TiffEncoderCompression.Lzw)
@ -179,16 +180,15 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff.Utils
/// <typeparam name="TPixel">The pixel data.</typeparam> /// <typeparam name="TPixel">The pixel data.</typeparam>
/// <param name="image">The image to write to the stream.</param> /// <param name="image">The image to write to the stream.</param>
/// <param name="rowSpan">A Span for a pixel row.</param> /// <param name="rowSpan">A Span for a pixel row.</param>
/// <param name="compressionLevel">The compression level for deflate compression.</param>
/// <param name="useHorizontalPredictor">Indicates if horizontal prediction should be used. Should only be used with deflate compression.</param> /// <param name="useHorizontalPredictor">Indicates if horizontal prediction should be used. Should only be used with deflate compression.</param>
/// <returns>The number of bytes written.</returns> /// <returns>The number of bytes written.</returns>
private int WriteDeflateCompressedRgb<TPixel>(Image<TPixel> image, Span<byte> rowSpan, bool useHorizontalPredictor) private int WriteDeflateCompressedRgb<TPixel>(Image<TPixel> image, Span<byte> rowSpan, DeflateCompressionLevel compressionLevel, bool useHorizontalPredictor)
where TPixel : unmanaged, IPixel<TPixel> where TPixel : unmanaged, IPixel<TPixel>
{ {
int bytesWritten = 0; int bytesWritten = 0;
using var memoryStream = new MemoryStream(); using var memoryStream = new MemoryStream();
using var deflateStream = new ZlibDeflateStream(this.memoryAllocator, memoryStream, compressionLevel); // TODO: move zlib compression from png to a common place?
// TODO: move zlib compression from png to a common place?
using var deflateStream = new ZlibDeflateStream(this.memoryAllocator, memoryStream, PngCompressionLevel.Level6); // TODO: make compression level configurable
for (int y = 0; y < image.Height; y++) for (int y = 0; y < image.Height; y++)
{ {
@ -286,10 +286,11 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff.Utils
/// <param name="quantizer">The quantizer to use.</param> /// <param name="quantizer">The quantizer to use.</param>
/// <param name="padding">The padding bytes for each row.</param> /// <param name="padding">The padding bytes for each row.</param>
/// <param name="compression">The compression to use.</param> /// <param name="compression">The compression to use.</param>
/// <param name="compressionLevel">The compression level for deflate compression.</param>
/// <param name="useHorizontalPredictor">Indicates if horizontal prediction should be used. Should only be used in combination with deflate or LZW compression.</param> /// <param name="useHorizontalPredictor">Indicates if horizontal prediction should be used. Should only be used in combination with deflate or LZW compression.</param>
/// <param name="colorMap">The color map.</param> /// <param name="colorMap">The color map.</param>
/// <returns>The number of bytes written.</returns> /// <returns>The number of bytes written.</returns>
public int WritePalettedRgb<TPixel>(Image<TPixel> image, IQuantizer quantizer, int padding, TiffEncoderCompression compression, bool useHorizontalPredictor, out IExifValue colorMap) public int WritePalettedRgb<TPixel>(Image<TPixel> image, IQuantizer quantizer, int padding, TiffEncoderCompression compression, DeflateCompressionLevel compressionLevel, bool useHorizontalPredictor, out IExifValue colorMap)
where TPixel : unmanaged, IPixel<TPixel> where TPixel : unmanaged, IPixel<TPixel>
{ {
int colorsPerChannel = 256; int colorsPerChannel = 256;
@ -341,7 +342,7 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff.Utils
if (compression == TiffEncoderCompression.Deflate) if (compression == TiffEncoderCompression.Deflate)
{ {
return this.WriteDeflateCompressedPalettedRgb(image, quantized, padding, useHorizontalPredictor); return this.WriteDeflateCompressedPalettedRgb(image, quantized, padding, compressionLevel, useHorizontalPredictor);
} }
if (compression == TiffEncoderCompression.Lzw) if (compression == TiffEncoderCompression.Lzw)
@ -379,14 +380,15 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff.Utils
/// <param name="image">The image to write to the stream.</param> /// <param name="image">The image to write to the stream.</param>
/// <param name="quantized">The quantized frame.</param> /// <param name="quantized">The quantized frame.</param>
/// <param name="padding">The padding bytes for each row.</param> /// <param name="padding">The padding bytes for each row.</param>
/// <param name="compressionLevel">The compression level for deflate compression.</param>
/// <param name="useHorizontalPredictor">Indicates if horizontal prediction should be used.</param> /// <param name="useHorizontalPredictor">Indicates if horizontal prediction should be used.</param>
/// <returns>The number of bytes written.</returns> /// <returns>The number of bytes written.</returns>
public int WriteDeflateCompressedPalettedRgb<TPixel>(Image<TPixel> image, IndexedImageFrame<TPixel> quantized, int padding, bool useHorizontalPredictor) public int WriteDeflateCompressedPalettedRgb<TPixel>(Image<TPixel> image, IndexedImageFrame<TPixel> quantized, int padding, DeflateCompressionLevel compressionLevel, bool useHorizontalPredictor)
where TPixel : unmanaged, IPixel<TPixel> where TPixel : unmanaged, IPixel<TPixel>
{ {
using IManagedByteBuffer tmpBuffer = this.memoryAllocator.AllocateManagedByteBuffer(image.Width); using IManagedByteBuffer tmpBuffer = this.memoryAllocator.AllocateManagedByteBuffer(image.Width);
using var memoryStream = new MemoryStream(); using var memoryStream = new MemoryStream();
using var deflateStream = new ZlibDeflateStream(this.memoryAllocator, memoryStream, PngCompressionLevel.Level6); // TODO: make compression level configurable using var deflateStream = new ZlibDeflateStream(this.memoryAllocator, memoryStream, compressionLevel);
int bytesWritten = 0; int bytesWritten = 0;
for (int y = 0; y < image.Height; y++) for (int y = 0; y < image.Height; y++)
@ -513,9 +515,10 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff.Utils
/// <param name="image">The image to write to the stream.</param> /// <param name="image">The image to write to the stream.</param>
/// <param name="padding">The padding bytes for each row.</param> /// <param name="padding">The padding bytes for each row.</param>
/// <param name="compression">The compression to use.</param> /// <param name="compression">The compression to use.</param>
/// <param name="compressionLevel">The compression level for deflate compression.</param>
/// <param name="useHorizontalPredictor">Indicates if horizontal prediction should be used. Should only be used with deflate or lzw compression.</param> /// <param name="useHorizontalPredictor">Indicates if horizontal prediction should be used. Should only be used with deflate or lzw compression.</param>
/// <returns>The number of bytes written.</returns> /// <returns>The number of bytes written.</returns>
public int WriteGray<TPixel>(Image<TPixel> image, int padding, TiffEncoderCompression compression, bool useHorizontalPredictor) public int WriteGray<TPixel>(Image<TPixel> image, int padding, TiffEncoderCompression compression, DeflateCompressionLevel compressionLevel, bool useHorizontalPredictor)
where TPixel : unmanaged, IPixel<TPixel> where TPixel : unmanaged, IPixel<TPixel>
{ {
using IManagedByteBuffer row = this.AllocateRow(image.Width, 1, padding); using IManagedByteBuffer row = this.AllocateRow(image.Width, 1, padding);
@ -523,7 +526,7 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff.Utils
if (compression == TiffEncoderCompression.Deflate) if (compression == TiffEncoderCompression.Deflate)
{ {
return this.WriteGrayDeflateCompressed(image, rowSpan, useHorizontalPredictor); return this.WriteGrayDeflateCompressed(image, rowSpan, compressionLevel, useHorizontalPredictor);
} }
if (compression == TiffEncoderCompression.Lzw) if (compression == TiffEncoderCompression.Lzw)
@ -553,16 +556,15 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff.Utils
/// </summary> /// </summary>
/// <param name="image">The image to write to the stream.</param> /// <param name="image">The image to write to the stream.</param>
/// <param name="rowSpan">A span of a row of pixels.</param> /// <param name="rowSpan">A span of a row of pixels.</param>
/// <param name="compressionLevel">The compression level for deflate compression.</param>
/// <param name="useHorizontalPredictor">Indicates if horizontal prediction should be used.</param> /// <param name="useHorizontalPredictor">Indicates if horizontal prediction should be used.</param>
/// <returns>The number of bytes written.</returns> /// <returns>The number of bytes written.</returns>
private int WriteGrayDeflateCompressed<TPixel>(Image<TPixel> image, Span<byte> rowSpan, bool useHorizontalPredictor) private int WriteGrayDeflateCompressed<TPixel>(Image<TPixel> image, Span<byte> rowSpan, DeflateCompressionLevel compressionLevel, bool useHorizontalPredictor)
where TPixel : unmanaged, IPixel<TPixel> where TPixel : unmanaged, IPixel<TPixel>
{ {
int bytesWritten = 0; int bytesWritten = 0;
using var memoryStream = new MemoryStream(); using var memoryStream = new MemoryStream();
using var deflateStream = new ZlibDeflateStream(this.memoryAllocator, memoryStream, compressionLevel); // TODO: move zlib compression from png to a common place?
// TODO: move zlib compression from png to a common place?
using var deflateStream = new ZlibDeflateStream(this.memoryAllocator, memoryStream, PngCompressionLevel.Level6); // TODO: make compression level configurable
for (int y = 0; y < image.Height; y++) for (int y = 0; y < image.Height; y++)
{ {
@ -656,8 +658,9 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff.Utils
/// <typeparam name="TPixel">The pixel data.</typeparam> /// <typeparam name="TPixel">The pixel data.</typeparam>
/// <param name="image">The image to write to the stream.</param> /// <param name="image">The image to write to the stream.</param>
/// <param name="compression">The compression to use.</param> /// <param name="compression">The compression to use.</param>
/// <param name="compressionLevel">The compression level for deflate compression.</param>
/// <returns>The number of bytes written.</returns> /// <returns>The number of bytes written.</returns>
public int WriteBiColor<TPixel>(Image<TPixel> image, TiffEncoderCompression compression) public int WriteBiColor<TPixel>(Image<TPixel> image, TiffEncoderCompression compression, DeflateCompressionLevel compressionLevel)
where TPixel : unmanaged, IPixel<TPixel> where TPixel : unmanaged, IPixel<TPixel>
{ {
int padding = image.Width % 8 == 0 ? 0 : 1; int padding = image.Width % 8 == 0 ? 0 : 1;
@ -674,7 +677,7 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff.Utils
if (compression == TiffEncoderCompression.Deflate) if (compression == TiffEncoderCompression.Deflate)
{ {
return this.WriteBiColorDeflate(imageBlackWhite, pixelRowAsGraySpan, outputRow); return this.WriteBiColorDeflate(imageBlackWhite, pixelRowAsGraySpan, outputRow, compressionLevel);
} }
if (compression == TiffEncoderCompression.PackBits) if (compression == TiffEncoderCompression.PackBits)
@ -734,12 +737,13 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff.Utils
/// <param name="image">The image to write to the stream.</param> /// <param name="image">The image to write to the stream.</param>
/// <param name="pixelRowAsGraySpan">A span for converting a pixel row to gray.</param> /// <param name="pixelRowAsGraySpan">A span for converting a pixel row to gray.</param>
/// <param name="outputRow">A span which will be used to store the output pixels.</param> /// <param name="outputRow">A span which will be used to store the output pixels.</param>
/// <param name="compressionLevel">The compression level for deflate compression.</param>
/// <returns>The number of bytes written.</returns> /// <returns>The number of bytes written.</returns>
public int WriteBiColorDeflate<TPixel>(Image<TPixel> image, Span<L8> pixelRowAsGraySpan, Span<byte> outputRow) public int WriteBiColorDeflate<TPixel>(Image<TPixel> image, Span<L8> pixelRowAsGraySpan, Span<byte> outputRow, DeflateCompressionLevel compressionLevel)
where TPixel : unmanaged, IPixel<TPixel> where TPixel : unmanaged, IPixel<TPixel>
{ {
using var memoryStream = new MemoryStream(); using var memoryStream = new MemoryStream();
using var deflateStream = new ZlibDeflateStream(this.memoryAllocator, memoryStream, PngCompressionLevel.Level6); // TODO: make compression level configurable using var deflateStream = new ZlibDeflateStream(this.memoryAllocator, memoryStream, compressionLevel);
int bytesWritten = 0; int bytesWritten = 0;
for (int y = 0; y < image.Height; y++) for (int y = 0; y < image.Height; y++)

28
tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs

@ -62,19 +62,19 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png
/// <summary> /// <summary>
/// All types except Palette /// All types except Palette
/// </summary> /// </summary>
public static readonly TheoryData<PngCompressionLevel> CompressionLevels public static readonly TheoryData<DeflateCompressionLevel> CompressionLevels
= new TheoryData<PngCompressionLevel> = new TheoryData<DeflateCompressionLevel>
{ {
PngCompressionLevel.Level0, DeflateCompressionLevel.Level0,
PngCompressionLevel.Level1, DeflateCompressionLevel.Level1,
PngCompressionLevel.Level2, DeflateCompressionLevel.Level2,
PngCompressionLevel.Level3, DeflateCompressionLevel.Level3,
PngCompressionLevel.Level4, DeflateCompressionLevel.Level4,
PngCompressionLevel.Level5, DeflateCompressionLevel.Level5,
PngCompressionLevel.Level6, DeflateCompressionLevel.Level6,
PngCompressionLevel.Level7, DeflateCompressionLevel.Level7,
PngCompressionLevel.Level8, DeflateCompressionLevel.Level8,
PngCompressionLevel.Level9, DeflateCompressionLevel.Level9,
}; };
public static readonly TheoryData<int> PaletteSizes = new TheoryData<int> public static readonly TheoryData<int> PaletteSizes = new TheoryData<int>
@ -157,7 +157,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png
[Theory] [Theory]
[WithTestPatternImages(nameof(CompressionLevels), 24, 24, PixelTypes.Rgba32)] [WithTestPatternImages(nameof(CompressionLevels), 24, 24, PixelTypes.Rgba32)]
public void WorksWithAllCompressionLevels<TPixel>(TestImageProvider<TPixel> provider, PngCompressionLevel compressionLevel) public void WorksWithAllCompressionLevels<TPixel>(TestImageProvider<TPixel> provider, DeflateCompressionLevel compressionLevel)
where TPixel : unmanaged, IPixel<TPixel> where TPixel : unmanaged, IPixel<TPixel>
{ {
foreach (PngInterlaceMode interlaceMode in InterlaceMode) foreach (PngInterlaceMode interlaceMode in InterlaceMode)
@ -573,7 +573,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png
PngFilterMethod pngFilterMethod, PngFilterMethod pngFilterMethod,
PngBitDepth bitDepth, PngBitDepth bitDepth,
PngInterlaceMode interlaceMode, PngInterlaceMode interlaceMode,
PngCompressionLevel compressionLevel = PngCompressionLevel.DefaultCompression, DeflateCompressionLevel compressionLevel = DeflateCompressionLevel.DefaultCompression,
int paletteSize = 255, int paletteSize = 255,
bool appendPngColorType = false, bool appendPngColorType = false,
bool appendPngFilterMethod = false, bool appendPngFilterMethod = false,

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

@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff.Compression
Stream compressedStream = new MemoryStream(); Stream compressedStream = new MemoryStream();
using (Stream uncompressedStream = new MemoryStream(data), using (Stream uncompressedStream = new MemoryStream(data),
deflateStream = new ZlibDeflateStream(Configuration.Default.MemoryAllocator, compressedStream, ImageSharp.Formats.Png.PngCompressionLevel.Level6)) deflateStream = new ZlibDeflateStream(Configuration.Default.MemoryAllocator, compressedStream, ImageSharp.Formats.Png.DeflateCompressionLevel.Level6))
{ {
uncompressedStream.CopyTo(deflateStream); uncompressedStream.CopyTo(deflateStream);
} }

2
tests/ImageSharp.Tests/Image/ImageTests.SaveAsync.cs

@ -138,7 +138,7 @@ namespace SixLabors.ImageSharp.Tests
public async Task SaveAsync_WithNonSeekableStream_IsCancellable() public async Task SaveAsync_WithNonSeekableStream_IsCancellable()
{ {
using var image = new Image<Rgba32>(4000, 4000); using var image = new Image<Rgba32>(4000, 4000);
var encoder = new PngEncoder() { CompressionLevel = PngCompressionLevel.BestCompression }; var encoder = new PngEncoder() { CompressionLevel = DeflateCompressionLevel.BestCompression };
using var stream = new MemoryStream(); using var stream = new MemoryStream();
var asyncStream = new AsyncStreamWrapper(stream, () => false); var asyncStream = new AsyncStreamWrapper(stream, () => false);
var cts = new CancellationTokenSource(); var cts = new CancellationTokenSource();

Loading…
Cancel
Save