diff --git a/src/ImageSharp/Formats/WebP/Lossy/Vp8Encoder.cs b/src/ImageSharp/Formats/WebP/Lossy/Vp8Encoder.cs
index 16eb7e298..e580421de 100644
--- a/src/ImageSharp/Formats/WebP/Lossy/Vp8Encoder.cs
+++ b/src/ImageSharp/Formats/WebP/Lossy/Vp8Encoder.cs
@@ -27,6 +27,16 @@ namespace SixLabors.ImageSharp.Formats.WebP.Lossy
///
private readonly Vp8BitWriter bitWriter;
+ ///
+ /// The quality, that will be used to encode the image.
+ ///
+ private readonly int quality;
+
+ ///
+ /// Quality/speed trade-off (0=fast, 6=slower-better).
+ ///
+ private readonly int method;
+
///
/// Fixed-point precision for RGB->YUV.
///
@@ -42,7 +52,7 @@ namespace SixLabors.ImageSharp.Formats.WebP.Lossy
private const int QFix = 17;
- private readonly byte[] zigzag = new byte[] { 0, 1, 4, 8, 5, 2, 3, 6, 9, 12, 13, 10, 7, 11, 14, 15 };
+ private readonly byte[] zigzag = { 0, 1, 4, 8, 5, 2, 3, 6, 9, 12, 13, 10, 7, 11, 14, 15 };
private readonly byte[] averageBytesPerMb = { 50, 24, 16, 9, 7, 5, 3, 2 };
@@ -52,9 +62,13 @@ namespace SixLabors.ImageSharp.Formats.WebP.Lossy
/// The memory allocator.
/// The width of the input image.
/// The height of the input image.
- public Vp8Encoder(MemoryAllocator memoryAllocator, int width, int height)
+ /// The encoding quality.
+ /// Quality/speed trade-off (0=fast, 6=slower-better).
+ public Vp8Encoder(MemoryAllocator memoryAllocator, int width, int height, int quality, int method)
{
this.memoryAllocator = memoryAllocator;
+ this.quality = quality.Clamp(0, 100);
+ this.method = method.Clamp(0, 6);
var pixelCount = width * height;
int mbw = (width + 15) >> 4;
@@ -81,10 +95,19 @@ namespace SixLabors.ImageSharp.Formats.WebP.Lossy
///
public int Alpha { get; set; }
+ ///
+ /// Gets the luma component.
+ ///
private IMemoryOwner Y { get; }
+ ///
+ /// Gets the chroma U component.
+ ///
private IMemoryOwner U { get; }
+ ///
+ /// Gets the chroma U component.
+ ///
private IMemoryOwner V { get; }
///
@@ -112,6 +135,12 @@ namespace SixLabors.ImageSharp.Formats.WebP.Lossy
///
private int MbHeaderLimit { get; }
+ ///
+ /// Encodes the image to the specified stream from the .
+ ///
+ /// The pixel format.
+ /// The to encode from.
+ /// The to encode the image data to.
public void Encode(Image image, Stream stream)
where TPixel : unmanaged, IPixel
{
@@ -139,10 +168,8 @@ namespace SixLabors.ImageSharp.Formats.WebP.Lossy
}
var it = new Vp8EncIterator(this.YTop, this.UvTop, this.Preds, this.Nz, mb, mbw, mbh);
- int method = 4; // TODO: hardcoded for now
- int quality = 100; // TODO: hardcoded for now
var alphas = new int[WebPConstants.MaxAlpha + 1];
- int alpha = this.MacroBlockAnalysis(width, height, it, y, u, v, yStride, uvStride, method, quality, alphas, out int uvAlpha);
+ int alpha = this.MacroBlockAnalysis(width, height, it, y, u, v, yStride, uvStride, alphas, out int uvAlpha);
// Analysis is done, proceed to actual coding.
@@ -156,7 +183,7 @@ namespace SixLabors.ImageSharp.Formats.WebP.Lossy
{
var info = new Vp8ModeScore();
it.Import(y, u, v, yStride, uvStride, width, height);
- if (!this.Decimate(it, segmentInfos, info, method))
+ if (!this.Decimate(it, segmentInfos, info))
{
this.CodeResiduals(it, info);
}
@@ -196,7 +223,7 @@ namespace SixLabors.ImageSharp.Formats.WebP.Lossy
// TODO: SetupMatrices
}
- private int MacroBlockAnalysis(int width, int height, Vp8EncIterator it, Span y, Span u, Span v, int yStride, int uvStride, int method, int quality, int[] alphas, out int uvAlpha)
+ private int MacroBlockAnalysis(int width, int height, Vp8EncIterator it, Span y, Span u, Span v, int yStride, int uvStride, int[] alphas, out int uvAlpha)
{
int alpha = 0;
uvAlpha = 0;
@@ -205,7 +232,7 @@ namespace SixLabors.ImageSharp.Formats.WebP.Lossy
do
{
it.Import(y, u, v, yStride, uvStride, width, height);
- int bestAlpha = this.MbAnalyze(it, method, quality, alphas, out var bestUvAlpha);
+ int bestAlpha = this.MbAnalyze(it, alphas, out var bestUvAlpha);
// Accumulate for later complexity analysis.
alpha += bestAlpha;
@@ -217,16 +244,16 @@ namespace SixLabors.ImageSharp.Formats.WebP.Lossy
return alpha;
}
- private int MbAnalyze(Vp8EncIterator it, int method, int quality, int[] alphas, out int bestUvAlpha)
+ private int MbAnalyze(Vp8EncIterator it, int[] alphas, out int bestUvAlpha)
{
it.SetIntra16Mode(0); // default: Intra16, DC_PRED
it.SetSkip(false); // not skipped.
it.SetSegment(0); // default segment, spec-wise.
int bestAlpha;
- if (method <= 1)
+ if (this.method <= 1)
{
- bestAlpha = it.FastMbAnalyze(quality);
+ bestAlpha = it.FastMbAnalyze(this.quality);
}
else
{
@@ -244,7 +271,7 @@ namespace SixLabors.ImageSharp.Formats.WebP.Lossy
return bestAlpha; // Mixed susceptibility (not just luma).
}
- private bool Decimate(Vp8EncIterator it, Vp8SegmentInfo[] segmentInfos, Vp8ModeScore rd, int method)
+ private bool Decimate(Vp8EncIterator it, Vp8SegmentInfo[] segmentInfos, Vp8ModeScore rd)
{
rd.InitScore();
@@ -256,7 +283,7 @@ namespace SixLabors.ImageSharp.Formats.WebP.Lossy
// For method >= 2, pick the best intra4/intra16 based on SSE (~tad slower).
// For method <= 1, we don't re-examine the decision but just go ahead with
// quantization/reconstruction.
- this.RefineUsingDistortion(it, segmentInfos, rd, method >= 2, method >= 1);
+ this.RefineUsingDistortion(it, segmentInfos, rd, this.method >= 2, this.method >= 1);
bool isSkipped = rd.Nz == 0;
it.SetSkip(isSkipped);
diff --git a/src/ImageSharp/Formats/WebP/WebPEncoderCore.cs b/src/ImageSharp/Formats/WebP/WebPEncoderCore.cs
index 8943ce9bd..1158421f0 100644
--- a/src/ImageSharp/Formats/WebP/WebPEncoderCore.cs
+++ b/src/ImageSharp/Formats/WebP/WebPEncoderCore.cs
@@ -79,7 +79,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
if (this.lossy)
{
- var enc = new Vp8Encoder(this.memoryAllocator, image.Width, image.Height);
+ var enc = new Vp8Encoder(this.memoryAllocator, image.Width, image.Height, this.quality, this.method);
enc.Encode(image, stream);
}
else