|
|
|
@ -1,10 +1,9 @@ |
|
|
|
using System.IO; |
|
|
|
using System.Runtime.CompilerServices; |
|
|
|
using ImageMagick; |
|
|
|
using Avalonia.Controls; |
|
|
|
using Avalonia.Media.Imaging; |
|
|
|
using Avalonia.Rendering; |
|
|
|
|
|
|
|
using SixLabors.ImageSharp; |
|
|
|
using Xunit; |
|
|
|
using Avalonia.Platform; |
|
|
|
using System.Threading.Tasks; |
|
|
|
@ -12,6 +11,8 @@ using System; |
|
|
|
using System.Threading; |
|
|
|
using Avalonia.Media; |
|
|
|
using Avalonia.Threading; |
|
|
|
using SixLabors.ImageSharp.PixelFormats; |
|
|
|
using Image = SixLabors.ImageSharp.Image; |
|
|
|
#if AVALONIA_SKIA
|
|
|
|
using Avalonia.Skia; |
|
|
|
#else
|
|
|
|
@ -119,12 +120,12 @@ namespace Avalonia.Direct2D1.RenderTests |
|
|
|
var immediatePath = Path.Combine(OutputPath, testName + ".immediate.out.png"); |
|
|
|
var deferredPath = Path.Combine(OutputPath, testName + ".deferred.out.png"); |
|
|
|
|
|
|
|
using (var expected = new MagickImage(expectedPath)) |
|
|
|
using (var immediate = new MagickImage(immediatePath)) |
|
|
|
using (var deferred = new MagickImage(deferredPath)) |
|
|
|
using (var expected = Image.Load<Rgba32>(expectedPath)) |
|
|
|
using (var immediate = Image.Load<Rgba32>(immediatePath)) |
|
|
|
using (var deferred = Image.Load<Rgba32>(deferredPath)) |
|
|
|
{ |
|
|
|
double immediateError = expected.Compare(immediate, ErrorMetric.RootMeanSquared); |
|
|
|
double deferredError = expected.Compare(deferred, ErrorMetric.RootMeanSquared); |
|
|
|
var immediateError = CompareImages(immediate, expected); |
|
|
|
var deferredError = CompareImages(deferred, expected); |
|
|
|
|
|
|
|
if (immediateError > 0.022) |
|
|
|
{ |
|
|
|
@ -143,10 +144,10 @@ namespace Avalonia.Direct2D1.RenderTests |
|
|
|
var expectedPath = Path.Combine(OutputPath, testName + ".expected.png"); |
|
|
|
var actualPath = Path.Combine(OutputPath, testName + ".out.png"); |
|
|
|
|
|
|
|
using (var expected = new MagickImage(expectedPath)) |
|
|
|
using (var actual = new MagickImage(actualPath)) |
|
|
|
using (var expected = Image.Load<Rgba32>(expectedPath)) |
|
|
|
using (var actual = Image.Load<Rgba32>(actualPath)) |
|
|
|
{ |
|
|
|
double immediateError = expected.Compare(actual, ErrorMetric.RootMeanSquared); |
|
|
|
double immediateError = CompareImages(actual, expected); |
|
|
|
|
|
|
|
if (immediateError > 0.022) |
|
|
|
{ |
|
|
|
@ -154,6 +155,53 @@ namespace Avalonia.Direct2D1.RenderTests |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Calculates root mean square error for given two images.
|
|
|
|
/// Based roughly on ImageMagick implementation to ensure consistency.
|
|
|
|
/// </summary>
|
|
|
|
private static double CompareImages(Image<Rgba32> actual, Image<Rgba32> expected) |
|
|
|
{ |
|
|
|
if (actual.Width != expected.Width || actual.Height != expected.Height) |
|
|
|
{ |
|
|
|
throw new ArgumentException("Images have different resolutions"); |
|
|
|
} |
|
|
|
|
|
|
|
var quantity = actual.Width * actual.Height; |
|
|
|
double squaresError = 0; |
|
|
|
|
|
|
|
const double scale = 1 / 255d; |
|
|
|
|
|
|
|
for (var x = 0; x < actual.Width; x++) |
|
|
|
{ |
|
|
|
double localError = 0; |
|
|
|
|
|
|
|
for (var y = 0; y < actual.Height; y++) |
|
|
|
{ |
|
|
|
var expectedAlpha = expected[x, y].A * scale; |
|
|
|
var actualAlpha = actual[x, y].A * scale; |
|
|
|
|
|
|
|
var r = scale * (expectedAlpha * expected[x, y].R - actualAlpha * actual[x, y].R); |
|
|
|
var g = scale * (expectedAlpha * expected[x, y].G - actualAlpha * actual[x, y].G); |
|
|
|
var b = scale * (expectedAlpha * expected[x, y].B - actualAlpha * actual[x, y].B); |
|
|
|
var a = expectedAlpha - actualAlpha; |
|
|
|
|
|
|
|
var error = r * r + g * g + b * b + a * a; |
|
|
|
|
|
|
|
localError += error; |
|
|
|
} |
|
|
|
|
|
|
|
squaresError += localError; |
|
|
|
} |
|
|
|
|
|
|
|
var meanSquaresError = squaresError / quantity; |
|
|
|
|
|
|
|
const int channelCount = 4; |
|
|
|
|
|
|
|
meanSquaresError = meanSquaresError / channelCount; |
|
|
|
|
|
|
|
return Math.Sqrt(meanSquaresError); |
|
|
|
} |
|
|
|
|
|
|
|
private string GetTestsDirectory() |
|
|
|
{ |
|
|
|
|