diff --git a/src/ImageSharp/Formats/WebP/Lossy/Vp8CostArray.cs b/src/ImageSharp/Formats/WebP/Lossy/Vp8CostArray.cs index 4015a18a98..f448de6dc9 100644 --- a/src/ImageSharp/Formats/WebP/Lossy/Vp8CostArray.cs +++ b/src/ImageSharp/Formats/WebP/Lossy/Vp8CostArray.cs @@ -8,7 +8,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossy /// /// Initializes a new instance of the class. /// - public Vp8CostArray() => this.Costs = new ushort[WebpConstants.NumCtx * (67 + 1)]; + public Vp8CostArray() => this.Costs = new ushort[67 + 1]; public ushort[] Costs { get; } } diff --git a/src/ImageSharp/Formats/WebP/Lossy/Vp8EncIterator.cs b/src/ImageSharp/Formats/WebP/Lossy/Vp8EncIterator.cs index ac582fd424..16dba65169 100644 --- a/src/ImageSharp/Formats/WebP/Lossy/Vp8EncIterator.cs +++ b/src/ImageSharp/Formats/WebP/Lossy/Vp8EncIterator.cs @@ -415,11 +415,10 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossy this.MakeIntra4Preds(); for (mode = 0; mode < maxMode; ++mode) { - int alpha; histos[curHisto] = new Vp8Histogram(); histos[curHisto].CollectHistogram(src, this.YuvP.AsSpan(Vp8Encoding.Vp8I4ModeOffsets[mode]), 0, 1); - alpha = histos[curHisto].GetAlpha(); + var alpha = histos[curHisto].GetAlpha(); if (alpha > bestModeAlpha) { bestModeAlpha = alpha; @@ -522,7 +521,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossy for (int x = 0; x < 4; ++x) { int ctx = this.TopNz[x] + this.LeftNz[y]; - res.SetCoeffs(rd.YAcLevels.AsSpan(x + (y * 4))); + res.SetCoeffs(rd.YAcLevels.AsSpan((x + (y * 4)) * 16, 16)); r += res.GetResidualCost(ctx); this.TopNz[x] = this.LeftNz[y] = (res.Last >= 0) ? 1 : 0; } @@ -572,7 +571,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossy for (int x = 0; x < 2; ++x) { int ctx = this.TopNz[4 + ch + x] + this.LeftNz[4 + ch + y]; - res.SetCoeffs(rd.UvLevels.AsSpan((ch * 2) + x + (y * 2))); + res.SetCoeffs(rd.UvLevels.AsSpan(((ch * 2) + x + (y * 2)) * 16, 16)); r += res.GetResidualCost(ctx); this.TopNz[4 + ch + x] = this.LeftNz[4 + ch + y] = (res.Last >= 0) ? 1 : 0; } diff --git a/src/ImageSharp/Formats/WebP/Lossy/Vp8Encoder.cs b/src/ImageSharp/Formats/WebP/Lossy/Vp8Encoder.cs index 9d1baafb94..a0dfc143c7 100644 --- a/src/ImageSharp/Formats/WebP/Lossy/Vp8Encoder.cs +++ b/src/ImageSharp/Formats/WebP/Lossy/Vp8Encoder.cs @@ -311,7 +311,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossy // Warning! order is important: first call VP8Decimate() and // *then* decide how to code the skip decision if there's one. - if (!this.Decimate(it, info, this.rdOptLevel) || dontUseSkip) + if (!this.Decimate(it, ref info, this.rdOptLevel) || dontUseSkip) { this.CodeResiduals(it, info); } @@ -411,7 +411,8 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossy this.Proba.FinalizeTokenProbas(); } - this.Proba.CalculateLevelCosts(); // Finalize costs. + // Finalize costs. + this.Proba.CalculateLevelCosts(); } private long OneStatPass(int width, int height, int yStride, int uvStride, Vp8RdLevel rdOpt, int nbMbs, PassStats stats) @@ -425,12 +426,13 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossy long distortion = 0; long pixelCount = nbMbs * 384; + it.Init(); this.SetLoopParams(stats.Q); do { var info = new Vp8ModeScore(); it.Import(y, u, v, yStride, uvStride, width, height, false); - if (this.Decimate(it, info, rdOpt)) + if (this.Decimate(it, ref info, rdOpt)) { // Just record the number of skips and act like skipProba is not used. ++this.Proba.NbSkip; @@ -877,7 +879,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossy return bestAlpha; // Mixed susceptibility (not just luma). } - private bool Decimate(Vp8EncIterator it, Vp8ModeScore rd, Vp8RdLevel rdOpt) + private bool Decimate(Vp8EncIterator it, ref Vp8ModeScore rd, Vp8RdLevel rdOpt) { rd.InitScore(); @@ -886,13 +888,13 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossy it.MakeLuma16Preds(); it.MakeChroma8Preds(); - // TODO: disabled picking best mode because its still bugged. - /* if (rdOpt > Vp8RdLevel.RdOptNone) + if (rdOpt > Vp8RdLevel.RdOptNone) { QuantEnc.PickBestIntra16(it, ref rd, this.SegmentInfos, this.Proba); if (this.method >= 2) { - QuantEnc.PickBestIntra4(it, ref rd, this.SegmentInfos, this.Proba, this.maxI4HeaderBits); + // TODO: there is still a bug in PickBestIntra4, therefore disabled. + // QuantEnc.PickBestIntra4(it, ref rd, this.SegmentInfos, this.Proba, this.maxI4HeaderBits); } QuantEnc.PickBestUv(it, ref rd, this.SegmentInfos, this.Proba); @@ -905,9 +907,6 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossy // quantization/reconstruction. QuantEnc.RefineUsingDistortion(it, this.SegmentInfos, rd, this.method >= 2, this.method >= 1, this.MbHeaderLimit); } - */ - - QuantEnc.RefineUsingDistortion(it, this.SegmentInfos, rd, this.method >= 2, this.method >= 1, this.MbHeaderLimit); bool isSkipped = rd.Nz == 0; it.SetSkip(isSkipped); diff --git a/src/ImageSharp/Formats/WebP/Lossy/Vp8Residual.cs b/src/ImageSharp/Formats/WebP/Lossy/Vp8Residual.cs index 4a48a94cac..20c5cafa8d 100644 --- a/src/ImageSharp/Formats/WebP/Lossy/Vp8Residual.cs +++ b/src/ImageSharp/Formats/WebP/Lossy/Vp8Residual.cs @@ -47,7 +47,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossy } } - this.Coeffs = coeffs.ToArray(); + this.Coeffs = coeffs.Slice(0, 16).ToArray(); } // Simulate block coding, but only record statistics.