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.
241 lines
6.9 KiB
241 lines
6.9 KiB
// Copyright (c) Six Labors.
|
|
// Licensed under the Apache License, Version 2.0.
|
|
|
|
using System;
|
|
using SixLabors.ImageSharp.Formats.Jpeg.Components;
|
|
using SixLabors.ImageSharp.Formats.Jpeg.Components.Encoder;
|
|
using SixLabors.ImageSharp.Tests.TestUtilities;
|
|
using Xunit;
|
|
using Xunit.Abstractions;
|
|
|
|
// ReSharper disable InconsistentNaming
|
|
namespace SixLabors.ImageSharp.Tests.Formats.Jpg
|
|
{
|
|
[Trait("Format", "Jpg")]
|
|
public class HuffmanScanEncoderTests
|
|
{
|
|
private ITestOutputHelper Output { get; }
|
|
|
|
public HuffmanScanEncoderTests(ITestOutputHelper output)
|
|
{
|
|
this.Output = output;
|
|
}
|
|
|
|
private static int GetHuffmanEncodingLength_Reference(uint number)
|
|
{
|
|
int bits = 0;
|
|
if (number > 32767)
|
|
{
|
|
number >>= 16;
|
|
bits += 16;
|
|
}
|
|
|
|
if (number > 127)
|
|
{
|
|
number >>= 8;
|
|
bits += 8;
|
|
}
|
|
|
|
if (number > 7)
|
|
{
|
|
number >>= 4;
|
|
bits += 4;
|
|
}
|
|
|
|
if (number > 1)
|
|
{
|
|
number >>= 2;
|
|
bits += 2;
|
|
}
|
|
|
|
if (number > 0)
|
|
{
|
|
bits++;
|
|
}
|
|
|
|
return bits;
|
|
}
|
|
|
|
[Fact]
|
|
public void GetHuffmanEncodingLength_Zero()
|
|
{
|
|
int expected = 0;
|
|
|
|
int actual = HuffmanScanEncoder.GetHuffmanEncodingLength(0);
|
|
|
|
Assert.Equal(expected, actual);
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData(1)]
|
|
[InlineData(2)]
|
|
public void GetHuffmanEncodingLength_Random(int seed)
|
|
{
|
|
int maxNumber = 1 << 16;
|
|
|
|
var rng = new Random(seed);
|
|
for (int i = 0; i < 1000; i++)
|
|
{
|
|
uint number = (uint)rng.Next(0, maxNumber);
|
|
|
|
int expected = GetHuffmanEncodingLength_Reference(number);
|
|
|
|
int actual = HuffmanScanEncoder.GetHuffmanEncodingLength(number);
|
|
|
|
Assert.Equal(expected, actual);
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void GetLastValuableElementIndex_AllZero()
|
|
{
|
|
static void RunTest()
|
|
{
|
|
Block8x8F data = default;
|
|
|
|
int expectedLessThan = 1;
|
|
|
|
int actual = HuffmanScanEncoder.GetLastValuableElementIndex(ref data);
|
|
|
|
Assert.True(actual < expectedLessThan);
|
|
}
|
|
|
|
FeatureTestRunner.RunWithHwIntrinsicsFeature(
|
|
RunTest,
|
|
HwIntrinsics.AllowAll | HwIntrinsics.DisableAVX2);
|
|
}
|
|
|
|
[Fact]
|
|
public void GetLastValuableElementIndex_AllNonZero()
|
|
{
|
|
static void RunTest()
|
|
{
|
|
Block8x8F data = default;
|
|
for (int i = 0; i < Block8x8F.Size; i++)
|
|
{
|
|
data[i] = 10;
|
|
}
|
|
|
|
int expected = Block8x8F.Size - 1;
|
|
|
|
int actual = HuffmanScanEncoder.GetLastValuableElementIndex(ref data);
|
|
|
|
Assert.Equal(expected, actual);
|
|
}
|
|
|
|
FeatureTestRunner.RunWithHwIntrinsicsFeature(
|
|
RunTest,
|
|
HwIntrinsics.AllowAll | HwIntrinsics.DisableAVX2);
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData(1)]
|
|
[InlineData(2)]
|
|
public void GetLastValuableElementIndex_RandomFilledSingle(int seed)
|
|
{
|
|
static void RunTest(string seedSerialized)
|
|
{
|
|
int seed = FeatureTestRunner.Deserialize<int>(seedSerialized);
|
|
var rng = new Random(seed);
|
|
|
|
for (int i = 0; i < 1000; i++)
|
|
{
|
|
Block8x8F data = default;
|
|
|
|
int setIndex = rng.Next(1, Block8x8F.Size);
|
|
data[setIndex] = rng.Next();
|
|
|
|
int expected = setIndex;
|
|
|
|
int actual = HuffmanScanEncoder.GetLastValuableElementIndex(ref data);
|
|
|
|
Assert.Equal(expected, actual);
|
|
}
|
|
}
|
|
|
|
FeatureTestRunner.RunWithHwIntrinsicsFeature(
|
|
RunTest,
|
|
seed,
|
|
HwIntrinsics.AllowAll | HwIntrinsics.DisableAVX2);
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData(1)]
|
|
[InlineData(2)]
|
|
public void GetLastValuableElementIndex_RandomFilledPartially(int seed)
|
|
{
|
|
static void RunTest(string seedSerialized)
|
|
{
|
|
int seed = FeatureTestRunner.Deserialize<int>(seedSerialized);
|
|
var rng = new Random(seed);
|
|
|
|
for (int i = 0; i < 1000; i++)
|
|
{
|
|
Block8x8F data = default;
|
|
|
|
int lastIndex = rng.Next(1, Block8x8F.Size);
|
|
int fillValue = rng.Next();
|
|
for (int dataIndex = 0; dataIndex <= lastIndex; dataIndex++)
|
|
{
|
|
data[dataIndex] = fillValue;
|
|
}
|
|
|
|
int expected = lastIndex;
|
|
|
|
int actual = HuffmanScanEncoder.GetLastValuableElementIndex(ref data);
|
|
|
|
Assert.Equal(expected, actual);
|
|
}
|
|
}
|
|
|
|
FeatureTestRunner.RunWithHwIntrinsicsFeature(
|
|
RunTest,
|
|
seed,
|
|
HwIntrinsics.AllowAll | HwIntrinsics.DisableAVX2);
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData(1)]
|
|
[InlineData(2)]
|
|
public void GetLastValuableElementIndex_RandomFilledFragmented(int seed)
|
|
{
|
|
static void RunTest(string seedSerialized)
|
|
{
|
|
int seed = FeatureTestRunner.Deserialize<int>(seedSerialized);
|
|
var rng = new Random(seed);
|
|
|
|
for (int i = 0; i < 1000; i++)
|
|
{
|
|
Block8x8F data = default;
|
|
|
|
int fillValue = rng.Next();
|
|
|
|
// first filled chunk
|
|
int lastIndex1 = rng.Next(1, Block8x8F.Size / 2);
|
|
for (int dataIndex = 0; dataIndex <= lastIndex1; dataIndex++)
|
|
{
|
|
data[dataIndex] = fillValue;
|
|
}
|
|
|
|
// second filled chunk, there might be a spot with zero(s) between first and second chunk
|
|
int lastIndex2 = rng.Next(lastIndex1 + 1, Block8x8F.Size);
|
|
for (int dataIndex = 0; dataIndex <= lastIndex2; dataIndex++)
|
|
{
|
|
data[dataIndex] = fillValue;
|
|
}
|
|
|
|
int expected = lastIndex2;
|
|
|
|
int actual = HuffmanScanEncoder.GetLastValuableElementIndex(ref data);
|
|
|
|
Assert.Equal(expected, actual);
|
|
}
|
|
}
|
|
|
|
FeatureTestRunner.RunWithHwIntrinsicsFeature(
|
|
RunTest,
|
|
seed,
|
|
HwIntrinsics.AllowAll | HwIntrinsics.DisableAVX2);
|
|
}
|
|
}
|
|
}
|
|
|