mirror of https://github.com/SixLabors/ImageSharp
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
256 lines
8.3 KiB
256 lines
8.3 KiB
// Copyright (c) Six Labors.
|
|
// Licensed under the Six Labors Split License.
|
|
|
|
using System.Text;
|
|
using SixLabors.ImageSharp.Formats.Webp;
|
|
using SixLabors.ImageSharp.Formats.Webp.Lossy;
|
|
using SixLabors.ImageSharp.Tests.TestUtilities;
|
|
|
|
namespace SixLabors.ImageSharp.Tests.Formats.Webp;
|
|
|
|
[Trait("Format", "Webp")]
|
|
public class Vp8ResidualTests
|
|
{
|
|
private static void WriteVp8Residual(string filename, Vp8Residual residual)
|
|
{
|
|
using FileStream stream = File.Open(filename, FileMode.Create);
|
|
using BinaryWriter writer = new(stream, Encoding.UTF8, false);
|
|
|
|
writer.Write(residual.First);
|
|
writer.Write(residual.Last);
|
|
writer.Write(residual.CoeffType);
|
|
|
|
for (int i = 0; i < residual.Coeffs.Length; i++)
|
|
{
|
|
writer.Write(residual.Coeffs[i]);
|
|
}
|
|
|
|
for (int i = 0; i < residual.Prob.Length; i++)
|
|
{
|
|
for (int j = 0; j < residual.Prob[i].Probabilities.Length; j++)
|
|
{
|
|
writer.Write(residual.Prob[i].Probabilities[j].Probabilities);
|
|
}
|
|
}
|
|
|
|
for (int i = 0; i < residual.Costs.Length; i++)
|
|
{
|
|
Vp8Costs costs = residual.Costs[i];
|
|
Vp8CostArray[] costsArray = costs.Costs;
|
|
for (int j = 0; j < costsArray.Length; j++)
|
|
{
|
|
for (int k = 0; k < costsArray[j].Costs.Length; k++)
|
|
{
|
|
writer.Write(costsArray[j].Costs[k]);
|
|
}
|
|
}
|
|
}
|
|
|
|
for (int i = 0; i < residual.Stats.Length; i++)
|
|
{
|
|
for (int j = 0; j < residual.Stats[i].Stats.Length; j++)
|
|
{
|
|
for (int k = 0; k < residual.Stats[i].Stats[j].Stats.Length; k++)
|
|
{
|
|
writer.Write(residual.Stats[i].Stats[j].Stats[k]);
|
|
}
|
|
}
|
|
}
|
|
|
|
writer.Flush();
|
|
}
|
|
|
|
private static Vp8Residual ReadVp8Residual(string fileName)
|
|
{
|
|
using FileStream stream = File.Open(fileName, FileMode.Open);
|
|
using BinaryReader reader = new(stream, Encoding.UTF8, false);
|
|
|
|
Vp8Residual residual = new()
|
|
{
|
|
First = reader.ReadInt32(),
|
|
Last = reader.ReadInt32(),
|
|
CoeffType = reader.ReadInt32()
|
|
};
|
|
|
|
for (int i = 0; i < residual.Coeffs.Length; i++)
|
|
{
|
|
residual.Coeffs[i] = reader.ReadInt16();
|
|
}
|
|
|
|
Vp8BandProbas[] bandProbas = new Vp8BandProbas[8];
|
|
for (int i = 0; i < bandProbas.Length; i++)
|
|
{
|
|
bandProbas[i] = new Vp8BandProbas();
|
|
for (int j = 0; j < bandProbas[i].Probabilities.Length; j++)
|
|
{
|
|
for (int k = 0; k < 11; k++)
|
|
{
|
|
bandProbas[i].Probabilities[j].Probabilities[k] = reader.ReadByte();
|
|
}
|
|
}
|
|
}
|
|
|
|
residual.Prob = bandProbas;
|
|
|
|
residual.Costs = new Vp8Costs[16];
|
|
for (int i = 0; i < residual.Costs.Length; i++)
|
|
{
|
|
residual.Costs[i] = new Vp8Costs();
|
|
Vp8CostArray[] costsArray = residual.Costs[i].Costs;
|
|
for (int j = 0; j < costsArray.Length; j++)
|
|
{
|
|
for (int k = 0; k < costsArray[j].Costs.Length; k++)
|
|
{
|
|
costsArray[j].Costs[k] = reader.ReadUInt16();
|
|
}
|
|
}
|
|
}
|
|
|
|
residual.Stats = new Vp8Stats[8];
|
|
for (int i = 0; i < residual.Stats.Length; i++)
|
|
{
|
|
residual.Stats[i] = new Vp8Stats();
|
|
for (int j = 0; j < residual.Stats[i].Stats.Length; j++)
|
|
{
|
|
for (int k = 0; k < residual.Stats[i].Stats[j].Stats.Length; k++)
|
|
{
|
|
residual.Stats[i].Stats[j].Stats[k] = reader.ReadUInt32();
|
|
}
|
|
}
|
|
}
|
|
|
|
return residual;
|
|
}
|
|
|
|
[Fact]
|
|
public void Vp8Residual_Serialization_Works()
|
|
{
|
|
// arrange
|
|
Vp8Residual expected = new();
|
|
Vp8EncProba encProb = new();
|
|
Random rand = new(439);
|
|
CreateRandomProbas(encProb, rand);
|
|
CreateCosts(encProb, rand);
|
|
expected.Init(1, 0, encProb);
|
|
for (int i = 0; i < expected.Coeffs.Length; i++)
|
|
{
|
|
expected.Coeffs[i] = (byte)rand.Next(255);
|
|
}
|
|
|
|
// act
|
|
string fileName = "Vp8SerializationTest.bin";
|
|
WriteVp8Residual(fileName, expected);
|
|
Vp8Residual actual = ReadVp8Residual(fileName);
|
|
File.Delete(fileName);
|
|
|
|
// assert
|
|
Assert.Equal(expected.CoeffType, actual.CoeffType);
|
|
Assert.Equal(expected.Coeffs, actual.Coeffs);
|
|
Assert.Equal(expected.Costs.Length, actual.Costs.Length);
|
|
Assert.Equal(expected.First, actual.First);
|
|
Assert.Equal(expected.Last, actual.Last);
|
|
Assert.Equal(expected.Stats.Length, actual.Stats.Length);
|
|
for (int i = 0; i < expected.Stats.Length; i++)
|
|
{
|
|
Vp8StatsArray[] expectedStats = expected.Stats[i].Stats;
|
|
Vp8StatsArray[] actualStats = actual.Stats[i].Stats;
|
|
Assert.Equal(expectedStats.Length, actualStats.Length);
|
|
for (int j = 0; j < expectedStats.Length; j++)
|
|
{
|
|
Assert.Equal(expectedStats[j].Stats, actualStats[j].Stats);
|
|
}
|
|
}
|
|
|
|
Assert.Equal(expected.Prob.Length, actual.Prob.Length);
|
|
for (int i = 0; i < expected.Prob.Length; i++)
|
|
{
|
|
Vp8ProbaArray[] expectedProbabilities = expected.Prob[i].Probabilities;
|
|
Vp8ProbaArray[] actualProbabilities = actual.Prob[i].Probabilities;
|
|
Assert.Equal(expectedProbabilities.Length, actualProbabilities.Length);
|
|
for (int j = 0; j < expectedProbabilities.Length; j++)
|
|
{
|
|
Assert.Equal(expectedProbabilities[j].Probabilities, actualProbabilities[j].Probabilities);
|
|
}
|
|
}
|
|
|
|
for (int i = 0; i < expected.Costs.Length; i++)
|
|
{
|
|
Vp8CostArray[] expectedCosts = expected.Costs[i].Costs;
|
|
Vp8CostArray[] actualCosts = actual.Costs[i].Costs;
|
|
Assert.Equal(expectedCosts.Length, actualCosts.Length);
|
|
for (int j = 0; j < expectedCosts.Length; j++)
|
|
{
|
|
Assert.Equal(expectedCosts[j].Costs, actualCosts[j].Costs);
|
|
}
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void GetResidualCost_Works()
|
|
{
|
|
// arrange
|
|
int ctx0 = 0;
|
|
int expected = 20911;
|
|
Vp8Residual residual = ReadVp8Residual(Path.Combine("TestDataWebp", "Vp8Residual.bin"));
|
|
|
|
// act
|
|
int actual = residual.GetResidualCost(ctx0);
|
|
|
|
// assert
|
|
Assert.Equal(expected, actual);
|
|
}
|
|
|
|
private static void CreateRandomProbas(Vp8EncProba probas, Random rand)
|
|
{
|
|
for (int t = 0; t < WebpConstants.NumTypes; ++t)
|
|
{
|
|
for (int b = 0; b < WebpConstants.NumBands; ++b)
|
|
{
|
|
for (int c = 0; c < WebpConstants.NumCtx; ++c)
|
|
{
|
|
for (int p = 0; p < WebpConstants.NumProbas; ++p)
|
|
{
|
|
probas.Coeffs[t][b].Probabilities[c].Probabilities[p] = (byte)rand.Next(255);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private static void CreateCosts(Vp8EncProba probas, Random rand)
|
|
{
|
|
for (int i = 0; i < probas.RemappedCosts.Length; i++)
|
|
{
|
|
for (int j = 0; j < probas.RemappedCosts[i].Length; j++)
|
|
{
|
|
for (int k = 0; k < probas.RemappedCosts[i][j].Costs.Length; k++)
|
|
{
|
|
ushort[] costs = probas.RemappedCosts[i][j].Costs[k].Costs;
|
|
for (int m = 0; m < costs.Length; m++)
|
|
{
|
|
costs[m] = (byte)rand.Next(255);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private static void RunSetCoeffsTest()
|
|
{
|
|
// arrange
|
|
Vp8Residual residual = new();
|
|
short[] coeffs = [110, 0, -2, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0];
|
|
|
|
// act
|
|
residual.SetCoeffs(coeffs);
|
|
|
|
// assert
|
|
Assert.Equal(9, residual.Last);
|
|
}
|
|
|
|
[Fact]
|
|
public void SetCoeffsTest_Works() => FeatureTestRunner.RunWithHwIntrinsicsFeature(RunSetCoeffsTest, HwIntrinsics.AllowAll);
|
|
|
|
[Fact]
|
|
public void SetCoeffsTest_WithoutSSE2_Works() => FeatureTestRunner.RunWithHwIntrinsicsFeature(RunSetCoeffsTest, HwIntrinsics.DisableHWIntrinsic);
|
|
}
|
|
|