Browse Source

better JpegColorConverterTests

af/merge-core
Anton Firszov 9 years ago
parent
commit
98946bdf0c
  1. 321
      tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs

321
tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs

@ -1,26 +1,27 @@
using System;
using System.Numerics;
namespace SixLabors.ImageSharp.Tests.Formats.Jpg
{
using System;
using System.Numerics;
using SixLabors.ImageSharp.ColorSpaces;
using SixLabors.ImageSharp.ColorSpaces.Conversion;
using SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.ColorSpaces;
using SixLabors.ImageSharp.ColorSpaces.Conversion;
using SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder;
using SixLabors.ImageSharp.Memory;
using Xunit;
using Xunit.Abstractions;
using Xunit;
using Xunit.Abstractions;
namespace SixLabors.ImageSharp.Tests.Formats.Jpg
{
public class JpegColorConverterTests
{
private const float Precision = 0.1f;
private const float Precision = 0.01f;
private const int InputBufferLength = 42;
// The result buffer could be shorter
private const int ResultBufferLength = 40;
private readonly Vector4[] result = new Vector4[ResultBufferLength];
public static readonly TheoryData<int, int, int> CommonConversionData =
new TheoryData<int, int, int>
{
{ 40, 40, 1 },
{ 42, 40, 2 },
{ 42, 39, 3 }
};
private static readonly ColorSpaceConverter ColorSpaceConverter = new ColorSpaceConverter();
@ -31,161 +32,193 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
private ITestOutputHelper Output { get; }
private static JpegColorConverter.ComponentValues CreateRandomValues(int componentCount, float maxVal = 255f)
[Theory]
[MemberData(nameof(CommonConversionData))]
public void ConvertFromYCbCr(int inputBufferLength, int resultBufferLength, int seed)
{
var rnd = new Random(42);
Buffer2D<float>[] buffers = new Buffer2D<float>[componentCount];
for (int i = 0; i < componentCount; i++)
{
float[] values = new float[InputBufferLength];
for (int j = 0; j < InputBufferLength; j++)
{
values[j] = (float)rnd.NextDouble() * maxVal;
}
// no need to dispose when buffer is not array owner
buffers[i] = new Buffer2D<float>(values, values.Length, 1);
}
return new JpegColorConverter.ComponentValues(buffers, 0);
ValidateConversion(
JpegColorSpace.YCbCr,
3,
inputBufferLength,
resultBufferLength,
seed,
(values, result, i) =>
{
float y = values.Component0[i];
float cb = values.Component1[i];
float cr = values.Component2[i];
var ycbcr = new YCbCr(y, cb, cr);
Vector4 rgba = result[i];
var actual = new Rgb(rgba.X, rgba.Y, rgba.Z);
var expected = ColorSpaceConverter.ToRgb(ycbcr);
Assert.True(actual.AlmostEquals(expected, Precision));
Assert.Equal(1, rgba.W);
});
}
[Fact]
public void ConvertFromYCbCr()
[Theory]
[MemberData(nameof(CommonConversionData))]
public void ConvertFromCmyk(int inputBufferLength, int resultBufferLength, int seed)
{
var converter = JpegColorConverter.GetConverter(JpegColorSpace.YCbCr);
JpegColorConverter.ComponentValues values = CreateRandomValues(3);
converter.ConvertToRGBA(values, this.result);
for (int i = 0; i < ResultBufferLength; i++)
{
float y = values.Component0[i];
float cb = values.Component1[i];
float cr = values.Component2[i];
var ycbcr = new YCbCr(y, cb, cr);
Vector4 rgba = this.result[i];
var actual = new Rgb(rgba.X, rgba.Y, rgba.Z);
var expected = ColorSpaceConverter.ToRgb(ycbcr);
Assert.True(actual.AlmostEquals(expected, Precision));
Assert.Equal(1, rgba.W);
}
}
[Fact]
public void ConvertFromCmyk()
{
var converter = JpegColorConverter.GetConverter(JpegColorSpace.Cmyk);
JpegColorConverter.ComponentValues values = CreateRandomValues(4);
converter.ConvertToRGBA(values, this.result);
var v = new Vector4(0, 0, 0, 1F);
var scale = new Vector4(1 / 255F, 1 / 255F, 1 / 255F, 1F);
for (int i = 0; i < ResultBufferLength; i++)
{
float c = values.Component0[i];
float m = values.Component1[i];
float y = values.Component2[i];
float k = values.Component3[i] / 255F;
v.X = c * k;
v.Y = m * k;
v.Z = y * k;
v.W = 1F;
v *= scale;
Vector4 rgba = this.result[i];
var actual = new Rgb(rgba.X, rgba.Y, rgba.Z);
var expected = new Rgb(v.X, v.Y, v.Z);
Assert.True(actual.AlmostEquals(expected, Precision));
Assert.Equal(1, rgba.W);
}
ValidateConversion(
JpegColorSpace.Cmyk,
4,
inputBufferLength,
resultBufferLength,
seed,
(values, result, i) =>
{
float c = values.Component0[i];
float m = values.Component1[i];
float y = values.Component2[i];
float k = values.Component3[i] / 255F;
v.X = c * k;
v.Y = m * k;
v.Z = y * k;
v.W = 1F;
v *= scale;
Vector4 rgba = result[i];
var actual = new Rgb(rgba.X, rgba.Y, rgba.Z);
var expected = new Rgb(v.X, v.Y, v.Z);
Assert.True(actual.AlmostEquals(expected, Precision));
Assert.Equal(1, rgba.W);
});
}
[Fact]
public void ConvertFromYcck()
[Theory]
[MemberData(nameof(CommonConversionData))]
public void ConvertFromGrayScale(int inputBufferLength, int resultBufferLength, int seed)
{
var converter = JpegColorConverter.GetConverter(JpegColorSpace.Ycck);
JpegColorConverter.ComponentValues values = CreateRandomValues(4);
ValidateConversion(
JpegColorSpace.GrayScale,
1,
inputBufferLength,
resultBufferLength,
seed,
(values, result, i) =>
{
float y = values.Component0[i];
Vector4 rgba = result[i];
var actual = new Rgb(rgba.X, rgba.Y, rgba.Z);
var expected = new Rgb(y / 255F, y / 255F, y / 255F);
Assert.True(actual.AlmostEquals(expected, Precision));
Assert.Equal(1, rgba.W);
});
}
converter.ConvertToRGBA(values, this.result);
[Theory]
[MemberData(nameof(CommonConversionData))]
public void ConvertFromRgb(int inputBufferLength, int resultBufferLength, int seed)
{
ValidateConversion(
JpegColorSpace.RGB,
3,
inputBufferLength,
resultBufferLength,
seed,
(values, result, i) =>
{
float r = values.Component0[i];
float g = values.Component1[i];
float b = values.Component2[i];
Vector4 rgba = result[i];
var actual = new Rgb(rgba.X, rgba.Y, rgba.Z);
var expected = new Rgb(r / 255F, g / 255F, b / 255F);
Assert.True(actual.AlmostEquals(expected, Precision));
Assert.Equal(1, rgba.W);
});
}
[Theory]
[MemberData(nameof(CommonConversionData))]
public void ConvertFromYcck(int inputBufferLength, int resultBufferLength, int seed)
{
var v = new Vector4(0, 0, 0, 1F);
var scale = new Vector4(1 / 255F, 1 / 255F, 1 / 255F, 1F);
for (int i = 0; i < ResultBufferLength; i++)
{
float y = values.Component0[i];
float cb = values.Component1[i] - 128F;
float cr = values.Component2[i] - 128F;
float k = values.Component3[i] / 255F;
v.X = (255F - MathF.Round(y + (1.402F * cr), MidpointRounding.AwayFromZero)) * k;
v.Y = (255F - MathF.Round(y - (0.344136F * cb) - (0.714136F * cr), MidpointRounding.AwayFromZero)) * k;
v.Z = (255F - MathF.Round(y + (1.772F * cb), MidpointRounding.AwayFromZero)) * k;
v.W = 1F;
v *= scale;
Vector4 rgba = this.result[i];
var actual = new Rgb(rgba.X, rgba.Y, rgba.Z);
var expected = new Rgb(v.X, v.Y, v.Z);
Assert.True(actual.AlmostEquals(expected, Precision));
Assert.Equal(1, rgba.W);
}
ValidateConversion(
JpegColorSpace.Ycck,
4,
inputBufferLength,
resultBufferLength,
seed,
(values, result, i) =>
{
float y = values.Component0[i];
float cb = values.Component1[i] - 128F;
float cr = values.Component2[i] - 128F;
float k = values.Component3[i] / 255F;
v.X = (255F - MathF.Round(y + (1.402F * cr), MidpointRounding.AwayFromZero)) * k;
v.Y = (255F - MathF.Round(
y - (0.344136F * cb) - (0.714136F * cr),
MidpointRounding.AwayFromZero)) * k;
v.Z = (255F - MathF.Round(y + (1.772F * cb), MidpointRounding.AwayFromZero)) * k;
v.W = 1F;
v *= scale;
Vector4 rgba = result[i];
var actual = new Rgb(rgba.X, rgba.Y, rgba.Z);
var expected = new Rgb(v.X, v.Y, v.Z);
Assert.True(actual.AlmostEquals(expected, Precision));
Assert.Equal(1, rgba.W);
});
}
[Fact]
public void ConvertFromGrayScale()
private static JpegColorConverter.ComponentValues CreateRandomValues(
int componentCount,
int inputBufferLength,
int seed,
float maxVal = 255f)
{
var converter = JpegColorConverter.GetConverter(JpegColorSpace.GrayScale);
JpegColorConverter.ComponentValues values = CreateRandomValues(1);
converter.ConvertToRGBA(values, this.result);
for (int i = 0; i < ResultBufferLength; i++)
var rnd = new Random(seed);
Buffer2D<float>[] buffers = new Buffer2D<float>[componentCount];
for (int i = 0; i < componentCount; i++)
{
float y = values.Component0[i];
Vector4 rgba = this.result[i];
var actual = new Rgb(rgba.X, rgba.Y, rgba.Z);
var expected = new Rgb(y / 255F, y / 255F, y / 255F);
float[] values = new float[inputBufferLength];
Assert.True(actual.AlmostEquals(expected, Precision));
Assert.Equal(1, rgba.W);
for (int j = 0; j < inputBufferLength; j++)
{
values[j] = (float)rnd.NextDouble() * maxVal;
}
// no need to dispose when buffer is not array owner
buffers[i] = new Buffer2D<float>(values, values.Length, 1);
}
return new JpegColorConverter.ComponentValues(buffers, 0);
}
[Fact]
public void ConvertFromRgb()
private static void ValidateConversion(
JpegColorSpace colorSpace,
int componentCount,
int inputBufferLength,
int resultBufferLength,
int seed,
Action<JpegColorConverter.ComponentValues, Span<Vector4>, int> doValidate)
{
var converter = JpegColorConverter.GetConverter(JpegColorSpace.RGB);
var converter = JpegColorConverter.GetConverter(colorSpace);
JpegColorConverter.ComponentValues values = CreateRandomValues(3);
JpegColorConverter.ComponentValues values = CreateRandomValues(componentCount, inputBufferLength, seed);
Vector4[] result = new Vector4[resultBufferLength];
converter.ConvertToRGBA(values, this.result);
converter.ConvertToRGBA(values, result);
for (int i = 0; i < ResultBufferLength; i++)
for (int i = 0; i < resultBufferLength; i++)
{
float r = values.Component0[i];
float g = values.Component1[i];
float b = values.Component2[i];
Vector4 rgba = this.result[i];
var actual = new Rgb(rgba.X, rgba.Y, rgba.Z);
var expected = new Rgb(r / 255F, g / 255F, b / 255F);
Assert.True(actual.AlmostEquals(expected, Precision));
Assert.Equal(1, rgba.W);
doValidate(values, result, i);
}
}
}

Loading…
Cancel
Save