mirror of https://github.com/SixLabors/ImageSharp
11 changed files with 813 additions and 34 deletions
@ -0,0 +1,23 @@ |
|||||
|
// Copyright (c) Six Labors and contributors.
|
||||
|
// Licensed under the GNU Affero General Public License, Version 3.
|
||||
|
|
||||
|
namespace SixLabors.ImageSharp.Formats.WebP |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// These five modes are evaluated and their respective entropy is computed.
|
||||
|
/// </summary>
|
||||
|
internal enum EntropyIx |
||||
|
{ |
||||
|
Direct = 0, |
||||
|
|
||||
|
Spatial = 1, |
||||
|
|
||||
|
SubGreen = 2, |
||||
|
|
||||
|
SpatialSubGreen = 3, |
||||
|
|
||||
|
Palette = 4, |
||||
|
|
||||
|
NumEntropyIx = 5 |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,36 @@ |
|||||
|
// Copyright (c) Six Labors and contributors.
|
||||
|
// Licensed under the GNU Affero General Public License, Version 3.
|
||||
|
|
||||
|
namespace SixLabors.ImageSharp.Formats.WebP |
||||
|
{ |
||||
|
internal enum HistoIx |
||||
|
{ |
||||
|
HistoAlpha = 0, |
||||
|
|
||||
|
HistoAlphaPred, |
||||
|
|
||||
|
HistoGreen, |
||||
|
|
||||
|
HistoGreenPred, |
||||
|
|
||||
|
HistoRed, |
||||
|
|
||||
|
HistoRedPred, |
||||
|
|
||||
|
HistoBlue, |
||||
|
|
||||
|
HistoBluePred, |
||||
|
|
||||
|
HistoRedSubGreen, |
||||
|
|
||||
|
HistoRedPredSubGreen, |
||||
|
|
||||
|
HistoBlueSubGreen, |
||||
|
|
||||
|
HistoBluePredSubGreen, |
||||
|
|
||||
|
HistoPalette, |
||||
|
|
||||
|
HistoTotal, // Must be last.
|
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,116 @@ |
|||||
|
// Copyright (c) Six Labors and contributors.
|
||||
|
// Licensed under the GNU Affero General Public License, Version 3.
|
||||
|
|
||||
|
using System; |
||||
|
|
||||
|
namespace SixLabors.ImageSharp.Formats.WebP.Lossless |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Holds bit entropy results and entropy-related functions.
|
||||
|
/// </summary>
|
||||
|
internal class Vp8LBitEntropy |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Not a trivial literal symbol.
|
||||
|
/// </summary>
|
||||
|
private const uint NonTrivialSym = 0xffffffff; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Initializes a new instance of the <see cref="Vp8LBitEntropy"/> class.
|
||||
|
/// </summary>
|
||||
|
public Vp8LBitEntropy() |
||||
|
{ |
||||
|
this.Entropy = 0.0d; |
||||
|
this.Sum = 0; |
||||
|
this.NoneZeros = 0; |
||||
|
this.MaxVal = 0; |
||||
|
this.NoneZeroCode = NonTrivialSym; |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets or sets the entropy.
|
||||
|
/// </summary>
|
||||
|
public double Entropy { get; set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets or sets the sum of the population.
|
||||
|
/// </summary>
|
||||
|
public uint Sum { get; set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets or sets the number of non-zero elements in the population.
|
||||
|
/// </summary>
|
||||
|
public int NoneZeros { get; set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets or sets the maximum value in the population.
|
||||
|
/// </summary>
|
||||
|
public uint MaxVal { get; set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets or sets the index of the last non-zero in the population.
|
||||
|
/// </summary>
|
||||
|
public uint NoneZeroCode { get; set; } |
||||
|
|
||||
|
public double BitsEntropyRefine(Span<uint> array, int n) |
||||
|
{ |
||||
|
double mix; |
||||
|
if (this.NoneZeros < 5) |
||||
|
{ |
||||
|
if (this.NoneZeros <= 1) |
||||
|
{ |
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
// Two symbols, they will be 0 and 1 in a Huffman code.
|
||||
|
// Let's mix in a bit of entropy to favor good clustering when
|
||||
|
// distributions of these are combined.
|
||||
|
if (this.NoneZeros == 2) |
||||
|
{ |
||||
|
return (0.99 * this.Sum) + (0.01 * this.Entropy); |
||||
|
} |
||||
|
|
||||
|
// No matter what the entropy says, we cannot be better than min_limit
|
||||
|
// with Huffman coding. I am mixing a bit of entropy into the
|
||||
|
// min_limit since it produces much better (~0.5 %) compression results
|
||||
|
// perhaps because of better entropy clustering.
|
||||
|
if (this.NoneZeros == 3) |
||||
|
{ |
||||
|
mix = 0.95; |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
mix = 0.7; // nonzeros == 4.
|
||||
|
} |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
mix = 0.627; |
||||
|
} |
||||
|
|
||||
|
double minLimit = (2 * this.Sum) - this.MaxVal; |
||||
|
minLimit = (mix * minLimit) + ((1.0 - mix) * this.Entropy); |
||||
|
return (this.Entropy < minLimit) ? minLimit : this.Entropy; |
||||
|
} |
||||
|
|
||||
|
public void BitsEntropyUnrefined(Span<uint> array, int n) |
||||
|
{ |
||||
|
for (int i = 0; i < n; i++) |
||||
|
{ |
||||
|
if (array[i] != 0) |
||||
|
{ |
||||
|
this.Sum += array[i]; |
||||
|
this.NoneZeroCode = (uint)i; |
||||
|
this.NoneZeros++; |
||||
|
this.Entropy -= LosslessUtils.FastSLog2(array[i]); |
||||
|
if (this.MaxVal < array[i]) |
||||
|
{ |
||||
|
this.MaxVal = array[i]; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
this.Entropy += LosslessUtils.FastSLog2(this.Sum); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
Loading…
Reference in new issue