Browse Source

better JpegColorConverterTests

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

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

@ -1,3 +1,5 @@
namespace SixLabors.ImageSharp.Tests.Formats.Jpg
{
using System; using System;
using System.Numerics; using System.Numerics;
@ -9,18 +11,17 @@ using SixLabors.ImageSharp.Memory;
using Xunit; using Xunit;
using Xunit.Abstractions; using Xunit.Abstractions;
namespace SixLabors.ImageSharp.Tests.Formats.Jpg
{
public class JpegColorConverterTests 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 public static readonly TheoryData<int, int, int> CommonConversionData =
private const int ResultBufferLength = 40; new TheoryData<int, int, int>
{
private readonly Vector4[] result = new Vector4[ResultBufferLength]; { 40, 40, 1 },
{ 42, 40, 2 },
{ 42, 39, 3 }
};
private static readonly ColorSpaceConverter ColorSpaceConverter = new ColorSpaceConverter(); private static readonly ColorSpaceConverter ColorSpaceConverter = new ColorSpaceConverter();
@ -31,63 +32,46 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
private ITestOutputHelper Output { get; } 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); ValidateConversion(
Buffer2D<float>[] buffers = new Buffer2D<float>[componentCount]; JpegColorSpace.YCbCr,
for (int i = 0; i < componentCount; i++) 3,
{ inputBufferLength,
float[] values = new float[InputBufferLength]; resultBufferLength,
seed,
for (int j = 0; j < InputBufferLength; j++) (values, result, i) =>
{
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 ConvertFromYCbCr()
{
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 y = values.Component0[i];
float cb = values.Component1[i]; float cb = values.Component1[i];
float cr = values.Component2[i]; float cr = values.Component2[i];
var ycbcr = new YCbCr(y, cb, cr); var ycbcr = new YCbCr(y, cb, cr);
Vector4 rgba = this.result[i]; Vector4 rgba = result[i];
var actual = new Rgb(rgba.X, rgba.Y, rgba.Z); var actual = new Rgb(rgba.X, rgba.Y, rgba.Z);
var expected = ColorSpaceConverter.ToRgb(ycbcr); var expected = ColorSpaceConverter.ToRgb(ycbcr);
Assert.True(actual.AlmostEquals(expected, Precision)); Assert.True(actual.AlmostEquals(expected, Precision));
Assert.Equal(1, rgba.W); Assert.Equal(1, rgba.W);
} });
} }
[Fact] [Theory]
public void ConvertFromCmyk() [MemberData(nameof(CommonConversionData))]
public void ConvertFromCmyk(int inputBufferLength, int resultBufferLength, int seed)
{ {
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 v = new Vector4(0, 0, 0, 1F);
var scale = new Vector4(1 / 255F, 1 / 255F, 1 / 255F, 1F); var scale = new Vector4(1 / 255F, 1 / 255F, 1 / 255F, 1F);
for (int i = 0; i < ResultBufferLength; i++) ValidateConversion(
JpegColorSpace.Cmyk,
4,
inputBufferLength,
resultBufferLength,
seed,
(values, result, i) =>
{ {
float c = values.Component0[i]; float c = values.Component0[i];
float m = values.Component1[i]; float m = values.Component1[i];
@ -101,28 +85,75 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
v *= scale; v *= scale;
Vector4 rgba = this.result[i]; Vector4 rgba = result[i];
var actual = new Rgb(rgba.X, rgba.Y, rgba.Z); var actual = new Rgb(rgba.X, rgba.Y, rgba.Z);
var expected = new Rgb(v.X, v.Y, v.Z); var expected = new Rgb(v.X, v.Y, v.Z);
Assert.True(actual.AlmostEquals(expected, Precision)); Assert.True(actual.AlmostEquals(expected, Precision));
Assert.Equal(1, rgba.W); Assert.Equal(1, rgba.W);
} });
} }
[Fact] [Theory]
public void ConvertFromYcck() [MemberData(nameof(CommonConversionData))]
public void ConvertFromGrayScale(int inputBufferLength, int resultBufferLength, int seed)
{
ValidateConversion(
JpegColorSpace.GrayScale,
1,
inputBufferLength,
resultBufferLength,
seed,
(values, result, i) =>
{ {
var converter = JpegColorConverter.GetConverter(JpegColorSpace.Ycck); 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);
JpegColorConverter.ComponentValues values = CreateRandomValues(4); 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 v = new Vector4(0, 0, 0, 1F);
var scale = new Vector4(1 / 255F, 1 / 255F, 1 / 255F, 1F); var scale = new Vector4(1 / 255F, 1 / 255F, 1 / 255F, 1F);
for (int i = 0; i < ResultBufferLength; i++) ValidateConversion(
JpegColorSpace.Ycck,
4,
inputBufferLength,
resultBufferLength,
seed,
(values, result, i) =>
{ {
float y = values.Component0[i]; float y = values.Component0[i];
float cb = values.Component1[i] - 128F; float cb = values.Component1[i] - 128F;
@ -130,62 +161,64 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
float k = values.Component3[i] / 255F; float k = values.Component3[i] / 255F;
v.X = (255F - MathF.Round(y + (1.402F * cr), MidpointRounding.AwayFromZero)) * k; 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.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.Z = (255F - MathF.Round(y + (1.772F * cb), MidpointRounding.AwayFromZero)) * k;
v.W = 1F; v.W = 1F;
v *= scale; v *= scale;
Vector4 rgba = this.result[i]; Vector4 rgba = result[i];
var actual = new Rgb(rgba.X, rgba.Y, rgba.Z); var actual = new Rgb(rgba.X, rgba.Y, rgba.Z);
var expected = new Rgb(v.X, v.Y, v.Z); var expected = new Rgb(v.X, v.Y, v.Z);
Assert.True(actual.AlmostEquals(expected, Precision)); Assert.True(actual.AlmostEquals(expected, Precision));
Assert.Equal(1, rgba.W); Assert.Equal(1, rgba.W);
} });
} }
[Fact] private static JpegColorConverter.ComponentValues CreateRandomValues(
public void ConvertFromGrayScale() int componentCount,
int inputBufferLength,
int seed,
float maxVal = 255f)
{ {
var converter = JpegColorConverter.GetConverter(JpegColorSpace.GrayScale); var rnd = new Random(seed);
Buffer2D<float>[] buffers = new Buffer2D<float>[componentCount];
JpegColorConverter.ComponentValues values = CreateRandomValues(1); for (int i = 0; i < componentCount; i++)
{
converter.ConvertToRGBA(values, this.result); float[] values = new float[inputBufferLength];
for (int i = 0; i < ResultBufferLength; i++) for (int j = 0; j < inputBufferLength; j++)
{ {
float y = values.Component0[i]; values[j] = (float)rnd.NextDouble() * maxVal;
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);
Assert.True(actual.AlmostEquals(expected, Precision)); // no need to dispose when buffer is not array owner
Assert.Equal(1, rgba.W); buffers[i] = new Buffer2D<float>(values, values.Length, 1);
} }
return new JpegColorConverter.ComponentValues(buffers, 0);
} }
[Fact] private static void ValidateConversion(
public void ConvertFromRgb() 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]; doValidate(values, result, 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);
} }
} }
} }

Loading…
Cancel
Save