Browse Source

Add filter strength as encoder parameter

pull/1552/head
Brian Popow 5 years ago
parent
commit
4fefcf1461
  1. 9
      src/ImageSharp/Formats/WebP/IWebpEncoderOptions.cs
  2. 18
      src/ImageSharp/Formats/WebP/Lossy/Vp8Encoder.cs
  3. 3
      src/ImageSharp/Formats/WebP/WebpEncoder.cs
  4. 8
      src/ImageSharp/Formats/WebP/WebpEncoderCore.cs
  5. 20
      tests/ImageSharp.Tests/Formats/WebP/WebpEncoderTests.cs

9
src/ImageSharp/Formats/WebP/IWebpEncoderOptions.cs

@ -39,6 +39,15 @@ namespace SixLabors.ImageSharp.Formats.Webp
/// </summary>
int EntropyPasses { get; }
/// <summary>
/// Gets the strength of the deblocking filter, between 0 (no filtering) and 100 (maximum filtering).
/// A value of 0 will turn off any filtering. Higher value will increase the strength of the filtering process applied after decoding the picture.
/// The higher the value the smoother the picture will appear.
/// Typical values are usually in the range of 20 to 50.
/// Defaults to 60.
/// </summary>
int FilterStrength { get; }
/// <summary>
/// Gets a value indicating whether to preserve the exact RGB values under transparent area. Otherwise, discard this invisible
/// RGB information for better compression.

18
src/ImageSharp/Formats/WebP/Lossy/Vp8Encoder.cs

@ -42,6 +42,11 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossy
/// </summary>
private readonly int entropyPasses;
/// <summary>
/// Specify the strength of the deblocking filter, between 0 (no filtering) and 100 (maximum filtering). A value of 0 will turn off any filtering.
/// </summary>
private readonly int filterStrength;
/// <summary>
/// A bit writer for writing lossy webp streams.
/// </summary>
@ -78,11 +83,8 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossy
private const int QMax = 100;
// TODO: filterStrength is hardcoded, should be configurable.
private const int FilterStrength = 60;
/// <summary>
/// Initializes a new instance of the <see cref="Vp8Encoder"/> class.
/// Initializes a new instance of the <see cref="Vp8Encoder" /> class.
/// </summary>
/// <param name="memoryAllocator">The memory allocator.</param>
/// <param name="configuration">The global configuration.</param>
@ -91,7 +93,8 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossy
/// <param name="quality">The encoding quality.</param>
/// <param name="method">Quality/speed trade-off (0=fast, 6=slower-better).</param>
/// <param name="entropyPasses">Number of entropy-analysis passes (in [1..10]).</param>
public Vp8Encoder(MemoryAllocator memoryAllocator, Configuration configuration, int width, int height, int quality, int method, int entropyPasses)
/// <param name="filterStrength">The filter the strength of the deblocking filter, between 0 (no filtering) and 100 (maximum filtering).</param>
public Vp8Encoder(MemoryAllocator memoryAllocator, Configuration configuration, int width, int height, int quality, int method, int entropyPasses, int filterStrength)
{
this.memoryAllocator = memoryAllocator;
this.configuration = configuration;
@ -100,6 +103,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossy
this.quality = Numerics.Clamp(quality, 0, 100);
this.method = Numerics.Clamp(method, 0, 6);
this.entropyPasses = Numerics.Clamp(entropyPasses, 1, 10);
this.filterStrength = Numerics.Clamp(filterStrength, 0, 100);
this.rdOptLevel = (method >= 6) ? Vp8RdLevel.RdOptTrellisAll
: (method >= 5) ? Vp8RdLevel.RdOptTrellis
: (method >= 3) ? Vp8RdLevel.RdOptBasic
@ -476,7 +480,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossy
private void AdjustFilterStrength()
{
if (FilterStrength > 0)
if (this.filterStrength > 0)
{
int maxLevel = 0;
for (int s = 0; s < WebpConstants.NumMbSegments; s++)
@ -708,7 +712,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossy
int filterType = 1; // TODO: filterType is hardcoded
// level0 is in [0..500]. Using '-f 50' as filter_strength is mid-filtering.
int level0 = 5 * FilterStrength;
int level0 = 5 * this.filterStrength;
for (int i = 0; i < WebpConstants.NumMbSegments; ++i)
{
Vp8SegmentInfo m = this.SegmentInfos[i];

3
src/ImageSharp/Formats/WebP/WebpEncoder.cs

@ -29,6 +29,9 @@ namespace SixLabors.ImageSharp.Formats.Webp
/// <inheritdoc/>
public int EntropyPasses { get; set; }
/// <inheritdoc/>
public int FilterStrength { get; set; } = 60;
/// <inheritdoc/>
public bool Exact { get; set; }

8
src/ImageSharp/Formats/WebP/WebpEncoderCore.cs

@ -47,6 +47,11 @@ namespace SixLabors.ImageSharp.Formats.Webp
/// </summary>
private readonly int entropyPasses;
/// <summary>
/// The filter the strength of the deblocking filter, between 0 (no filtering) and 100 (maximum filtering).
/// </summary>
private readonly int filterStrength;
/// <summary>
/// Flag indicating whether to preserve the exact RGB values under transparent area. Otherwise, discard this invisible
/// RGB information for better compression.
@ -71,6 +76,7 @@ namespace SixLabors.ImageSharp.Formats.Webp
this.quality = options.Quality;
this.method = options.Method;
this.entropyPasses = options.EntropyPasses;
this.filterStrength = options.FilterStrength;
this.exact = options.Exact;
}
@ -91,7 +97,7 @@ namespace SixLabors.ImageSharp.Formats.Webp
if (this.lossy)
{
using var enc = new Vp8Encoder(this.memoryAllocator, this.configuration, image.Width, image.Height, this.quality, this.method, this.entropyPasses);
using var enc = new Vp8Encoder(this.memoryAllocator, this.configuration, image.Width, image.Height, this.quality, this.method, this.entropyPasses, this.filterStrength);
enc.Encode(image, stream);
}
else

20
tests/ImageSharp.Tests/Formats/WebP/WebpEncoderTests.cs

@ -98,6 +98,26 @@ namespace SixLabors.ImageSharp.Tests.Formats.Webp
image.VerifyEncoder(provider, "webp", testOutputDetails, encoder, customComparer: GetComparer(quality));
}
[Theory]
[WithFile(Lossy.NoFilter06, PixelTypes.Rgba32, 100)]
[WithFile(Lossy.NoFilter06, PixelTypes.Rgba32, 80)]
[WithFile(Lossy.NoFilter06, PixelTypes.Rgba32, 50)]
[WithFile(Lossy.NoFilter06, PixelTypes.Rgba32, 30)]
[WithFile(Lossy.NoFilter06, PixelTypes.Rgba32, 10)]
public void Encode_Lossy_WithDifferentFilterStrength_Works<TPixel>(TestImageProvider<TPixel> provider, int filterStrength)
where TPixel : unmanaged, IPixel<TPixel>
{
var encoder = new WebpEncoder()
{
Lossy = true,
FilterStrength = filterStrength
};
using Image<TPixel> image = provider.GetImage();
string testOutputDetails = string.Concat("lossy", "_f", filterStrength);
image.VerifyEncoder(provider, "webp", testOutputDetails, encoder, customComparer: GetComparer(75));
}
[Theory]
[WithFile(Lossy.NoFilter06, PixelTypes.Rgba32, 0, 75)]
[WithFile(Lossy.NoFilter06, PixelTypes.Rgba32, 1, 75)]

Loading…
Cancel
Save