diff --git a/src/ImageSharp/Formats/WebP/IWebPEncoderOptions.cs b/src/ImageSharp/Formats/WebP/IWebPEncoderOptions.cs
index 36d3460da3..ab3757131c 100644
--- a/src/ImageSharp/Formats/WebP/IWebPEncoderOptions.cs
+++ b/src/ImageSharp/Formats/WebP/IWebPEncoderOptions.cs
@@ -20,7 +20,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
/// this parameter is the amount of effort put into the compression: 0 is the fastest but gives larger
/// files compared to the slowest, but best, 100.
///
- float Quality { get; }
+ int Quality { get; }
///
/// Gets the encoding method to use. Its a quality/speed trade-off (0=fast, 6=slower-better).
diff --git a/src/ImageSharp/Formats/WebP/Lossless/Vp8LEncoder.cs b/src/ImageSharp/Formats/WebP/Lossless/Vp8LEncoder.cs
index 8194c54b83..181fbaac15 100644
--- a/src/ImageSharp/Formats/WebP/Lossless/Vp8LEncoder.cs
+++ b/src/ImageSharp/Formats/WebP/Lossless/Vp8LEncoder.cs
@@ -40,6 +40,11 @@ namespace SixLabors.ImageSharp.Formats.WebP.Lossless
///
private Vp8LBitWriter bitWriter;
+ ///
+ /// The quality, that will be used to encode the image.
+ ///
+ private readonly int quality;
+
private const int ApplyPaletteGreedyMax = 4;
private const int PaletteInvSizeBits = 11;
@@ -52,11 +57,13 @@ namespace SixLabors.ImageSharp.Formats.WebP.Lossless
/// The memory allocator.
/// The width of the input image.
/// The height of the input image.
- public Vp8LEncoder(MemoryAllocator memoryAllocator, int width, int height)
+ /// The encoding quality.
+ public Vp8LEncoder(MemoryAllocator memoryAllocator, int width, int height, int quality)
{
var pixelCount = width * height;
int initialSize = pixelCount * 2;
+ this.quality = quality.Clamp(1, 100);
this.bitWriter = new Vp8LBitWriter(initialSize);
this.Bgra = memoryAllocator.Allocate(pixelCount);
this.Palette = memoryAllocator.Allocate(WebPConstants.MaxPaletteSize);
@@ -255,8 +262,6 @@ namespace SixLabors.ImageSharp.Formats.WebP.Lossless
// Analyze image (entropy, numPalettes etc).
CrunchConfig[] crunchConfigs = this.EncoderAnalyze(image, out bool redAndBlueAlwaysZero);
- int quality = 75; // TODO: quality is hardcoded for now.
-
// TODO : Do we want to do this multi-threaded, this will probably require a second class:
// one which co-ordinates the threading and comparison and another which does the actual encoding
foreach (CrunchConfig crunchConfig in crunchConfigs)
@@ -297,12 +302,12 @@ namespace SixLabors.ImageSharp.Formats.WebP.Lossless
if (this.UsePredictorTransform)
{
- this.ApplyPredictFilter(this.CurrentWidth, height, quality, this.UseSubtractGreenTransform);
+ this.ApplyPredictFilter(this.CurrentWidth, height, this.quality, this.UseSubtractGreenTransform);
}
if (this.UseCrossColorTransform)
{
- this.ApplyCrossColorFilter(this.CurrentWidth, height, quality);
+ this.ApplyCrossColorFilter(this.CurrentWidth, height, this.quality);
}
this.bitWriter.PutBits(0, 1); // No more transforms.
@@ -314,7 +319,6 @@ namespace SixLabors.ImageSharp.Formats.WebP.Lossless
this.Refs,
this.CurrentWidth,
height,
- quality,
useCache,
crunchConfig,
this.CacheBits,
@@ -329,7 +333,6 @@ namespace SixLabors.ImageSharp.Formats.WebP.Lossless
private CrunchConfig[] EncoderAnalyze(Image image, out bool redAndBlueAlwaysZero)
where TPixel : unmanaged, IPixel
{
- var configQuality = 75; // TODO: hardcoded quality for now
int method = 4; // TODO: method hardcoded to 4 for now.
int width = image.Width;
int height = image.Height;
@@ -348,7 +351,7 @@ namespace SixLabors.ImageSharp.Formats.WebP.Lossless
bool doNotCache = false;
var crunchConfigs = new List();
- if (method == 6 && configQuality == 100)
+ if (method == 6 && this.quality == 100)
{
doNotCache = true;
@@ -367,7 +370,7 @@ namespace SixLabors.ImageSharp.Formats.WebP.Lossless
{
// Only choose the guessed best transform.
crunchConfigs.Add(new CrunchConfig { EntropyIdx = entropyIdx });
- if (configQuality >= 75 && method == 5)
+ if (this.quality >= 75 && method == 5)
{
// Test with and without color cache.
doNotCache = true;
@@ -396,14 +399,14 @@ namespace SixLabors.ImageSharp.Formats.WebP.Lossless
return crunchConfigs.ToArray();
}
- private void EncodeImage(Span bgra, Vp8LHashChain hashChain, Vp8LBackwardRefs[] refsArray, int width, int height, int quality, bool useCache, CrunchConfig config, int cacheBits, int histogramBits, int initBytePosition)
+ private void EncodeImage(Span bgra, Vp8LHashChain hashChain, Vp8LBackwardRefs[] refsArray, int width, int height, bool useCache, CrunchConfig config, int cacheBits, int histogramBits, int initBytePosition)
{
int histogramImageXySize = LosslessUtils.SubSampleSize(width, histogramBits) * LosslessUtils.SubSampleSize(height, histogramBits);
var histogramSymbols = new ushort[histogramImageXySize];
var huffTree = new HuffmanTree[3 * WebPConstants.CodeLengthCodes];
for (int i = 0; i < huffTree.Length; i++)
{
- huffTree[i] = new HuffmanTree();
+ huffTree[i] = default;
}
if (useCache)
diff --git a/src/ImageSharp/Formats/WebP/MetadataExtensions.cs b/src/ImageSharp/Formats/WebP/MetadataExtensions.cs
new file mode 100644
index 0000000000..3d0aca6db6
--- /dev/null
+++ b/src/ImageSharp/Formats/WebP/MetadataExtensions.cs
@@ -0,0 +1,18 @@
+using SixLabors.ImageSharp.Formats.WebP;
+using SixLabors.ImageSharp.Metadata;
+
+namespace SixLabors.ImageSharp
+{
+ ///
+ /// Extension methods for the type.
+ ///
+ public static partial class MetadataExtensions
+ {
+ ///
+ /// Gets the webp format specific metadata for the image.
+ ///
+ /// The metadata this method extends.
+ /// The .
+ public static WebPMetadata GetWebpMetadata(this ImageMetadata metadata) => metadata.GetFormatMetadata(WebPFormat.Instance);
+ }
+}
diff --git a/src/ImageSharp/Formats/WebP/WebPEncoder.cs b/src/ImageSharp/Formats/WebP/WebPEncoder.cs
index 787cff67bc..c6770daebc 100644
--- a/src/ImageSharp/Formats/WebP/WebPEncoder.cs
+++ b/src/ImageSharp/Formats/WebP/WebPEncoder.cs
@@ -18,7 +18,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
public bool Lossy { get; set; }
///
- public float Quality { get; set; }
+ public int Quality { get; set; }
///
public int Method { get; set; }
diff --git a/src/ImageSharp/Formats/WebP/WebPEncoderCore.cs b/src/ImageSharp/Formats/WebP/WebPEncoderCore.cs
index f286c4461b..a5bce7f8c1 100644
--- a/src/ImageSharp/Formats/WebP/WebPEncoderCore.cs
+++ b/src/ImageSharp/Formats/WebP/WebPEncoderCore.cs
@@ -41,7 +41,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
///
/// Compression quality. Between 0 and 100.
///
- private float quality;
+ private readonly int quality;
///
/// Initializes a new instance of the class.
@@ -78,7 +78,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
}
else
{
- var enc = new Vp8LEncoder(this.memoryAllocator, image.Width, image.Height);
+ var enc = new Vp8LEncoder(this.memoryAllocator, image.Width, image.Height, this.quality);
enc.Encode(image, stream);
}
}
diff --git a/src/ImageSharp/Formats/WebP/WebPFormat.cs b/src/ImageSharp/Formats/WebP/WebPFormat.cs
index 38787cbf86..2bb606f7f1 100644
--- a/src/ImageSharp/Formats/WebP/WebPFormat.cs
+++ b/src/ImageSharp/Formats/WebP/WebPFormat.cs
@@ -10,6 +10,10 @@ namespace SixLabors.ImageSharp.Formats.WebP
///
public sealed class WebPFormat : IImageFormat
{
+ private WebPFormat()
+ {
+ }
+
///
/// Gets the current instance.
///
diff --git a/tests/ImageSharp.Tests/Formats/WebP/WebPEncoderTests.cs b/tests/ImageSharp.Tests/Formats/WebP/WebPEncoderTests.cs
index 2cc2c88fe7..44ffa2be3d 100644
--- a/tests/ImageSharp.Tests/Formats/WebP/WebPEncoderTests.cs
+++ b/tests/ImageSharp.Tests/Formats/WebP/WebPEncoderTests.cs
@@ -9,8 +9,10 @@ namespace SixLabors.ImageSharp.Tests.Formats.WebP
public class WebPEncoderTests
{
[Theory]
- [WithFile(TestImages.Bmp.Car, PixelTypes.Rgba32)]
- public void Encode_Lossless_Works(TestImageProvider provider)
+ [WithFile(TestImages.Bmp.Car, PixelTypes.Rgba32, 100)]
+ [WithFile(TestImages.Bmp.Car, PixelTypes.Rgba32, 80)]
+ [WithFile(TestImages.Bmp.Car, PixelTypes.Rgba32, 20)]
+ public void Encode_Lossless_Works(TestImageProvider provider, int quality)
where TPixel : unmanaged, IPixel
{
var encoder = new WebPEncoder()
@@ -20,7 +22,8 @@ namespace SixLabors.ImageSharp.Tests.Formats.WebP
using (Image image = provider.GetImage())
{
- image.VerifyEncoder(provider, "webp", "lossless", encoder);
+ var testOutputDetails = string.Concat("lossless", "_", quality);
+ image.VerifyEncoder(provider, "webp", testOutputDetails, encoder);
}
}
}