mirror of https://github.com/SixLabors/ImageSharp
6 changed files with 280 additions and 29 deletions
@ -0,0 +1,18 @@ |
|||||
|
// Copyright (c) Six Labors.
|
||||
|
// Licensed under the Apache License, Version 2.0.
|
||||
|
|
||||
|
namespace SixLabors.ImageSharp.Formats.WebP.Lossy |
||||
|
{ |
||||
|
internal class Vp8CostArray |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Initializes a new instance of the <see cref="Vp8CostArray"/> class.
|
||||
|
/// </summary>
|
||||
|
public Vp8CostArray() |
||||
|
{ |
||||
|
this.Costs = new ushort[WebPConstants.NumCtx * (67 + 1)]; |
||||
|
} |
||||
|
|
||||
|
public ushort[] Costs { get; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,169 @@ |
|||||
|
// Copyright (c) Six Labors.
|
||||
|
// Licensed under the Apache License, Version 2.0.
|
||||
|
|
||||
|
using System; |
||||
|
|
||||
|
namespace SixLabors.ImageSharp.Formats.WebP.Lossy |
||||
|
{ |
||||
|
internal class Vp8EncProba |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Last (inclusive) level with variable cost.
|
||||
|
/// </summary>
|
||||
|
private const int MaxVariableLevel = 67; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Initializes a new instance of the <see cref="Vp8EncProba"/> class.
|
||||
|
/// </summary>
|
||||
|
public Vp8EncProba() |
||||
|
{ |
||||
|
this.Dirty = true; |
||||
|
this.UseSkipProba = false; |
||||
|
this.Segments = new byte[3]; |
||||
|
this.Coeffs = new Vp8BandProbas[WebPConstants.NumTypes][]; |
||||
|
for (int i = 0; i < this.Coeffs.Length; i++) |
||||
|
{ |
||||
|
this.Coeffs[i] = new Vp8BandProbas[WebPConstants.NumBands]; |
||||
|
for (int j = 0; j < this.Coeffs[i].Length; j++) |
||||
|
{ |
||||
|
this.Coeffs[i][j] = new Vp8BandProbas(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
this.LevelCost = new Vp8CostArray[WebPConstants.NumTypes][]; |
||||
|
for (int i = 0; i < this.LevelCost.Length; i++) |
||||
|
{ |
||||
|
this.LevelCost[i] = new Vp8CostArray[WebPConstants.NumBands]; |
||||
|
for (int j = 0; j < this.LevelCost[i].Length; j++) |
||||
|
{ |
||||
|
this.LevelCost[i][j] = new Vp8CostArray(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
this.RemappedCosts = new Vp8CostArray[WebPConstants.NumTypes][]; |
||||
|
for (int i = 0; i < this.RemappedCosts.Length; i++) |
||||
|
{ |
||||
|
this.RemappedCosts[i] = new Vp8CostArray[16]; |
||||
|
for (int j = 0; j < this.RemappedCosts[i].Length; j++) |
||||
|
{ |
||||
|
this.RemappedCosts[i][j] = new Vp8CostArray(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// Initialize with default probabilities.
|
||||
|
this.Segments.AsSpan().Fill(255); |
||||
|
for (int t = 0; t < WebPConstants.NumTypes; ++t) |
||||
|
{ |
||||
|
for (int b = 0; b < WebPConstants.NumBands; ++b) |
||||
|
{ |
||||
|
for (int c = 0; c < WebPConstants.NumCtx; ++c) |
||||
|
{ |
||||
|
Vp8ProbaArray dst = this.Coeffs[t][b].Probabilities[c]; |
||||
|
for (int p = 0; p < WebPConstants.NumProbas; ++p) |
||||
|
{ |
||||
|
dst.Probabilities[p] = WebPLookupTables.DefaultCoeffsProba[t, b, c, p]; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets the probabilities for segment tree.
|
||||
|
/// </summary>
|
||||
|
public byte[] Segments { get; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets the final probability of being skipped.
|
||||
|
/// </summary>
|
||||
|
public byte SkipProba { get; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets a value indicating whether to use the skip probability. Note: we always use SkipProba for now.
|
||||
|
/// </summary>
|
||||
|
public bool UseSkipProba { get; } |
||||
|
|
||||
|
public Vp8BandProbas[][] Coeffs { get; } |
||||
|
|
||||
|
public Vp8CostArray[][] LevelCost { get; } |
||||
|
|
||||
|
public Vp8CostArray[][] RemappedCosts { get; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets or sets the number of skipped blocks.
|
||||
|
/// </summary>
|
||||
|
public int NbSkip { get; set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets or sets a value indicating whether CalculateLevelCosts() needs to be called.
|
||||
|
/// </summary>
|
||||
|
public bool Dirty { get; set; } |
||||
|
|
||||
|
public void CalculateLevelCosts() |
||||
|
{ |
||||
|
if (!this.Dirty) |
||||
|
{ |
||||
|
return; // nothing to do.
|
||||
|
} |
||||
|
|
||||
|
for (int ctype = 0; ctype < WebPConstants.NumTypes; ++ctype) |
||||
|
{ |
||||
|
for (int band = 0; band < WebPConstants.NumBands; ++band) |
||||
|
{ |
||||
|
for (int ctx = 0; ctx < WebPConstants.NumCtx; ++ctx) |
||||
|
{ |
||||
|
Vp8ProbaArray p = this.Coeffs[ctype][band].Probabilities[ctx]; |
||||
|
Span<ushort> table = this.LevelCost[ctype][band].Costs.AsSpan(ctx * MaxVariableLevel); |
||||
|
int cost0 = (ctx > 0) ? this.BitCost(1, p.Probabilities[0]) : 0; |
||||
|
int costBase = this.BitCost(1, p.Probabilities[1]) + cost0; |
||||
|
int v; |
||||
|
table[0] = (ushort)(this.BitCost(0, p.Probabilities[1]) + cost0); |
||||
|
for (v = 1; v <= MaxVariableLevel; ++v) |
||||
|
{ |
||||
|
table[v] = (ushort)(costBase + this.VariableLevelCost(v, p.Probabilities)); |
||||
|
} |
||||
|
|
||||
|
// Starting at level 67 and up, the variable part of the cost is actually constant.
|
||||
|
} |
||||
|
} |
||||
|
|
||||
|
for (int n = 0; n < 16; ++n) |
||||
|
{ |
||||
|
for (int ctx = 0; ctx < WebPConstants.NumCtx; ++ctx) |
||||
|
{ |
||||
|
Span<ushort> dst = this.RemappedCosts[ctype][n].Costs.AsSpan(ctx * MaxVariableLevel, MaxVariableLevel); |
||||
|
Span<ushort> src = this.LevelCost[ctype][WebPConstants.Bands[n]].Costs.AsSpan(ctx * MaxVariableLevel, MaxVariableLevel); |
||||
|
src.CopyTo(dst); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
this.Dirty = false; |
||||
|
} |
||||
|
|
||||
|
private int VariableLevelCost(int level, Span<byte> probas) |
||||
|
{ |
||||
|
int pattern = WebPLookupTables.Vp8LevelCodes[level - 1][0]; |
||||
|
int bits = WebPLookupTables.Vp8LevelCodes[level - 1][1]; |
||||
|
int cost = 0; |
||||
|
for (int i = 2; pattern != 0; ++i) |
||||
|
{ |
||||
|
if ((pattern & 1) != 0) |
||||
|
{ |
||||
|
cost += this.BitCost(bits & 1, probas[i]); |
||||
|
} |
||||
|
|
||||
|
bits >>= 1; |
||||
|
pattern >>= 1; |
||||
|
} |
||||
|
|
||||
|
return cost; |
||||
|
} |
||||
|
|
||||
|
// Cost of coding one event with probability 'proba'.
|
||||
|
private int BitCost(int bit, byte proba) |
||||
|
{ |
||||
|
return bit == 0 ? WebPLookupTables.Vp8EntropyCost[proba] : WebPLookupTables.Vp8EntropyCost[255 - proba]; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
Loading…
Reference in new issue