diff --git a/src/ImageSharp/Formats/Jpeg/Common/Block8x8F.cs b/src/ImageSharp/Formats/Jpeg/Common/Block8x8F.cs
index b3220dea6..9a1acecfa 100644
--- a/src/ImageSharp/Formats/Jpeg/Common/Block8x8F.cs
+++ b/src/ImageSharp/Formats/Jpeg/Common/Block8x8F.cs
@@ -250,6 +250,13 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Common
}
}
+ public float[] ToArray()
+ {
+ float[] result = new float[Size];
+ this.CopyTo(result);
+ return result;
+ }
+
///
/// Multiply all elements of the block.
///
diff --git a/tests/ImageSharp.Tests/Formats/Jpg/ReferenceImplementationsTests.AccurateDCT.cs b/tests/ImageSharp.Tests/Formats/Jpg/ReferenceImplementationsTests.AccurateDCT.cs
new file mode 100644
index 000000000..b716146e8
--- /dev/null
+++ b/tests/ImageSharp.Tests/Formats/Jpg/ReferenceImplementationsTests.AccurateDCT.cs
@@ -0,0 +1,36 @@
+namespace SixLabors.ImageSharp.Tests.Formats.Jpg
+{
+ using SixLabors.ImageSharp.Formats.Jpeg.Common;
+ using SixLabors.ImageSharp.Tests.Formats.Jpg.Utils;
+
+ using Xunit;
+ using Xunit.Abstractions;
+
+ public partial class ReferenceImplementationsTests
+ {
+ public class AccurateDCT : JpegUtilityTestFixture
+ {
+ public AccurateDCT(ITestOutputHelper output)
+ : base(output)
+ {
+ }
+
+ [Theory]
+ [InlineData(42)]
+ [InlineData(1)]
+ [InlineData(2)]
+ public void ForwardThenInverse(int seed)
+ {
+ float[] data = JpegUtilityTestFixture.Create8x8RandomFloatData(-1000, 1000, seed);
+
+ var b0 = default(Block8x8F);
+ b0.LoadFrom(data);
+
+ Block8x8F b1 = ReferenceImplementations.AccurateDCT.TransformFDCT(ref b0);
+ Block8x8F b2 = ReferenceImplementations.AccurateDCT.TransformIDCT(ref b1);
+
+ this.CompareBlocks(b0, b2, 1e-4f);
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/tests/ImageSharp.Tests/Formats/Jpg/ReferenceImplementationsTests.FastFloatingPointDCT.cs b/tests/ImageSharp.Tests/Formats/Jpg/ReferenceImplementationsTests.FastFloatingPointDCT.cs
index 4d7ad8a7e..05fe178cb 100644
--- a/tests/ImageSharp.Tests/Formats/Jpg/ReferenceImplementationsTests.FastFloatingPointDCT.cs
+++ b/tests/ImageSharp.Tests/Formats/Jpg/ReferenceImplementationsTests.FastFloatingPointDCT.cs
@@ -3,21 +3,28 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
{
using System;
+ using SixLabors.ImageSharp.Formats.Jpeg.Common;
using SixLabors.ImageSharp.Tests.Formats.Jpg.Utils;
using Xunit;
+ using Xunit.Abstractions;
public partial class ReferenceImplementationsTests
{
- public class FastFloatingPointDCT
+ public class FastFloatingPointDCT : JpegUtilityTestFixture
{
+ public FastFloatingPointDCT(ITestOutputHelper output)
+ : base(output)
+ {
+ }
+
[Theory]
[InlineData(42, 0)]
[InlineData(1, 0)]
[InlineData(2, 0)]
public void ForwardThenInverse(int seed, int startAt)
{
- int[] data = JpegUtilityTestFixture.Create8x8RandomIntData(-200, 200, seed);
+ int[] data = JpegUtilityTestFixture.Create8x8RandomIntData(-1000, 1000, seed);
float[] src = data.ConvertAllToFloat();
float[] dest = new float[64];
float[] temp = new float[64];
@@ -25,13 +32,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
ReferenceImplementations.FastFloatingPointDCT.fDCT2D_llm(src, dest, temp, true);
ReferenceImplementations.FastFloatingPointDCT.iDCT2D_llm(dest, src, temp);
- for (int i = startAt; i < 64; i++)
- {
- float expected = data[i];
- float actual = (float)src[i];
-
- Assert.Equal(expected, actual, new ApproximateFloatComparer(2f));
- }
+ this.CompareBlocks(data.ConvertAllToFloat(), src, 2f);
}
[Theory]
@@ -40,7 +41,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
[InlineData(2)]
public void IDCT_IsEquivalentTo_StandardIntegerImplementation(int seed)
{
- int[] intData = JpegUtilityTestFixture.Create8x8RandomIntData(-200, 200, seed);
+ int[] intData = JpegUtilityTestFixture.Create8x8RandomIntData(-1000, 1000, seed);
Span floatSrc = intData.ConvertAllToFloat();
ReferenceImplementations.StandardIntegerDCT.TransformIDCTInplace(intData);
@@ -50,13 +51,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
ReferenceImplementations.FastFloatingPointDCT.iDCT2D_llm(floatSrc, dest, temp);
- for (int i = 0; i < 64; i++)
- {
- float expected = intData[i];
- float actual = dest[i];
-
- Assert.Equal(expected, actual, new ApproximateFloatComparer(1f));
- }
+ this.CompareBlocks(intData.ConvertAllToFloat(), dest, 1f);
}
[Theory]
@@ -65,7 +60,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
[InlineData(2)]
public void IDCT_IsEquivalentTo_AccurateImplementation(int seed)
{
- int[] intData = JpegUtilityTestFixture.Create8x8RandomIntData(-200, 200, seed);
+ int[] intData = JpegUtilityTestFixture.Create8x8RandomIntData(-1000, 1000, seed);
float[] floatSrc = intData.ConvertAllToFloat();
ReferenceImplementations.AccurateDCT.TransformIDCTInplace(intData);
@@ -75,13 +70,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
ReferenceImplementations.FastFloatingPointDCT.iDCT2D_llm(floatSrc, dest, temp);
- for (int i = 0; i < 64; i++)
- {
- float expected = intData[i];
- float actual = dest[i];
-
- Assert.Equal(expected, actual, new ApproximateFloatComparer(1f));
- }
+ this.CompareBlocks(intData.ConvertAllToFloat(), dest, 1f);
}
[Theory]
@@ -90,7 +79,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
[InlineData(2)]
public void FDCT_IsEquivalentTo_StandardIntegerImplementation(int seed)
{
- int[] intData = JpegUtilityTestFixture.Create8x8RandomIntData(-200, 200, seed);
+ int[] intData = JpegUtilityTestFixture.Create8x8RandomIntData(-1000, 1000, seed);
float[] floatSrc = intData.ConvertAllToFloat();
ReferenceImplementations.StandardIntegerDCT.TransformFDCTInplace(intData);
@@ -100,14 +89,39 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
ReferenceImplementations.FastFloatingPointDCT.fDCT2D_llm(floatSrc, dest, temp, offsetSourceByNeg128: true);
- for (int i = 0; i < 64; i++)
- {
- float expected = intData[i];
- float actual = dest[i];
+ this.CompareBlocks(intData.ConvertAllToFloat(), dest, 2f);
+ }
+
+ [Theory]
+ [InlineData(42)]
+ [InlineData(1)]
+ [InlineData(2)]
+ public void FDCT_IsEquivalentTo_AccurateImplementation(int seed)
+ {
+ float[] floatData = JpegUtilityTestFixture.Create8x8RandomFloatData(-1000, 1000);
+
+ Block8x8F source = default(Block8x8F);
+ source.LoadFrom(floatData);
+
+ Block8x8F expected = ReferenceImplementations.AccurateDCT.TransformFDCT(ref source);
+ Block8x8F actual = ReferenceImplementations.FastFloatingPointDCT.TransformFDCT(ref source);
+
+ this.CompareBlocks(expected, actual, 1f);
+
+ //int[] intData = JpegUtilityTestFixture.Create8x8RandomIntData(-1000, 1000, seed);
+ //float[] floatSrc = intData.ConvertAllToFloat();
- Assert.Equal(expected, actual, new ApproximateFloatComparer(1f));
- }
+ //ReferenceImplementations.AccurateDCT.TransformFDCTInplace(intData);
+
+ //float[] dest = new float[64];
+ //float[] temp = new float[64];
+
+ //ReferenceImplementations.FastFloatingPointDCT.fDCT2D_llm(floatSrc, dest, temp, offsetSourceByNeg128: false);
+
+ //this.CompareBlocks(intData.ConvertAllToFloat(), dest, 1f);
}
+
+
}
}
}
\ No newline at end of file
diff --git a/tests/ImageSharp.Tests/Formats/Jpg/ReferenceImplementationsTests.StandardIntegerDCT.cs b/tests/ImageSharp.Tests/Formats/Jpg/ReferenceImplementationsTests.StandardIntegerDCT.cs
index 49187d9bc..4fdfd62f3 100644
--- a/tests/ImageSharp.Tests/Formats/Jpg/ReferenceImplementationsTests.StandardIntegerDCT.cs
+++ b/tests/ImageSharp.Tests/Formats/Jpg/ReferenceImplementationsTests.StandardIntegerDCT.cs
@@ -10,7 +10,6 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
public partial class ReferenceImplementationsTests
{
-
public class StandardIntegerDCT
{
public StandardIntegerDCT(ITestOutputHelper output)
@@ -34,10 +33,39 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
Block8x8 expected = ReferenceImplementations.AccurateDCT.TransformIDCT(ref source);
Block8x8 actual = ReferenceImplementations.StandardIntegerDCT.TransformIDCT(ref source);
+ Block8x8F sourceF = source.AsFloatBlock();
+ Block8x8F wut0 = ReferenceImplementations.FastFloatingPointDCT.TransformIDCT(ref sourceF);
+ Block8x8 wut1 = wut0.RoundAsInt16Block();
+
long diff = Block8x8.TotalDifference(ref expected, ref actual);
this.Output.WriteLine(expected.ToString());
this.Output.WriteLine(actual.ToString());
+ this.Output.WriteLine(wut1.ToString());
this.Output.WriteLine("DIFFERENCE: "+diff);
+
+ Assert.True(diff < 4);
+ }
+
+ [Theory]
+ [InlineData(42)]
+ [InlineData(1)]
+ [InlineData(2)]
+ public void FDCT_IsEquivalentTo_AccurateImplementation(int seed)
+ {
+ int[] data = Create8x8RandomIntData(-1000, 1000, seed);
+
+ Block8x8 source = default(Block8x8);
+ source.LoadFrom(data);
+
+ Block8x8 expected = ReferenceImplementations.AccurateDCT.TransformFDCT(ref source);
+ Block8x8 actual = ReferenceImplementations.StandardIntegerDCT.TransformFDCT(ref source);
+
+ long diff = Block8x8.TotalDifference(ref expected, ref actual);
+ this.Output.WriteLine(expected.ToString());
+ this.Output.WriteLine(actual.ToString());
+ this.Output.WriteLine("DIFFERENCE: " + diff);
+
+ Assert.True(diff < 4);
}
diff --git a/tests/ImageSharp.Tests/Formats/Jpg/Utils/JpegUtilityTestFixture.cs b/tests/ImageSharp.Tests/Formats/Jpg/Utils/JpegUtilityTestFixture.cs
index 19602579a..057a84fde 100644
--- a/tests/ImageSharp.Tests/Formats/Jpg/Utils/JpegUtilityTestFixture.cs
+++ b/tests/ImageSharp.Tests/Formats/Jpg/Utils/JpegUtilityTestFixture.cs
@@ -11,6 +11,9 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg.Utils
using System.Diagnostics;
using System.Text;
+ using SixLabors.ImageSharp.Formats.Jpeg.Common;
+
+ using Xunit;
using Xunit.Abstractions;
public class JpegUtilityTestFixture : MeasureFixture
@@ -133,5 +136,35 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg.Utils
Debug.WriteLine(msg);
this.Output.WriteLine(msg);
}
+
+ internal void CompareBlocks(Block8x8 a, Block8x8 b, float tolerance) =>
+ this.CompareBlocks(a.AsFloatBlock(), b.AsFloatBlock(), tolerance);
+
+ internal void CompareBlocks(Block8x8F a, Block8x8F b, float tolerance)
+ => this.CompareBlocks(a.ToArray(), b.ToArray(), tolerance);
+
+ internal void CompareBlocks(Span a, Span b, float tolerance)
+ {
+ ApproximateFloatComparer comparer = new ApproximateFloatComparer(tolerance);
+ double totalDifference = 0.0;
+
+ bool failed = false;
+
+ for (int i = 0; i < 64; i++)
+ {
+ float expected = a[i];
+ float actual = b[i];
+ totalDifference += Math.Abs(expected - actual);
+
+ if (!comparer.Equals(expected, actual))
+ {
+ failed = true;
+ this.Output.WriteLine($"Difference too large at index {i}");
+ }
+ }
+
+ this.Output.WriteLine("TOTAL DIFF: "+totalDifference);
+ Assert.False(failed);
+ }
}
}
\ No newline at end of file
diff --git a/tests/ImageSharp.Tests/Formats/Jpg/Utils/ReferenceImplementations.AccurateDCT.cs b/tests/ImageSharp.Tests/Formats/Jpg/Utils/ReferenceImplementations.AccurateDCT.cs
index d6c2bc454..7f80b4f98 100644
--- a/tests/ImageSharp.Tests/Formats/Jpg/Utils/ReferenceImplementations.AccurateDCT.cs
+++ b/tests/ImageSharp.Tests/Formats/Jpg/Utils/ReferenceImplementations.AccurateDCT.cs
@@ -100,20 +100,24 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg.Utils
double tmp, tmp2;
Block8x8F res = default(Block8x8F);
- for (v=0; v<8; v++) {
- for (u=0; u<8; u++) {
- tmp = 0.0;
- for (y=0; y<8; y++) {
- tmp2 = 0.0;
- for (x=0; x<8; x++) {
- tmp2 += (double) block[y, x] * CosLut[x, u];
+ for (v = 0; v < 8; v++)
+ {
+ for (u = 0; u < 8; u++)
+ {
+ tmp = 0.0;
+ for (y = 0; y < 8; y++)
+ {
+ tmp2 = 0.0;
+ for (x = 0; x < 8; x++)
+ {
+ tmp2 += (double)block[y,x] * CosLut[x,u];
}
- tmp += CosLut[y, v] * tmp2;
+ tmp += CosLut[y,v] * tmp2;
}
- res[v, u] = (float)tmp;
- }
+ res[v,u] = (float) tmp;
+ }
}
-
+
return res;
}
}
diff --git a/tests/ImageSharp.Tests/Formats/Jpg/Utils/ReferenceImplementations.FastFloatingPointDCT.cs b/tests/ImageSharp.Tests/Formats/Jpg/Utils/ReferenceImplementations.FastFloatingPointDCT.cs
index 5c3b65a1e..6aea87330 100644
--- a/tests/ImageSharp.Tests/Formats/Jpg/Utils/ReferenceImplementations.FastFloatingPointDCT.cs
+++ b/tests/ImageSharp.Tests/Formats/Jpg/Utils/ReferenceImplementations.FastFloatingPointDCT.cs
@@ -4,12 +4,39 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg.Utils
using System.Numerics;
using System.Runtime.CompilerServices;
+ using SixLabors.ImageSharp.Formats.Jpeg.Common;
using SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Utils;
internal static partial class ReferenceImplementations
{
internal static class FastFloatingPointDCT
{
+ public static Block8x8F TransformIDCT(ref Block8x8F source)
+ {
+ float[] s = new float[64];
+ source.CopyTo(s);
+ float[] d = new float[64];
+ float[] temp = new float[64];
+
+ iDCT2D_llm(s, d, temp);
+ Block8x8F result = default(Block8x8F);
+ result.LoadFrom(d);
+ return result;
+ }
+
+ public static Block8x8F TransformFDCT(ref Block8x8F source)
+ {
+ float[] s = new float[64];
+ source.CopyTo(s);
+ float[] d = new float[64];
+ float[] temp = new float[64];
+
+ fDCT2D_llm(s, d, temp);
+ Block8x8F result = default(Block8x8F);
+ result.LoadFrom(d);
+ return result;
+ }
+
///
/// https://github.com/norishigefukushima/dct_simd/blob/master/dct/dct8x8_simd.cpp#L200
///
diff --git a/tests/ImageSharp.Tests/Formats/Jpg/Utils/ReferenceImplementations.StandardIntegerDCT.cs b/tests/ImageSharp.Tests/Formats/Jpg/Utils/ReferenceImplementations.StandardIntegerDCT.cs
index 243969cab..a1f70bcdd 100644
--- a/tests/ImageSharp.Tests/Formats/Jpg/Utils/ReferenceImplementations.StandardIntegerDCT.cs
+++ b/tests/ImageSharp.Tests/Formats/Jpg/Utils/ReferenceImplementations.StandardIntegerDCT.cs
@@ -75,6 +75,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg.Utils
return result;
}
+ [Obsolete("Looks like this method produces really bad results for bigger values!")]
public static Block8x8 TransformIDCT(ref Block8x8 block)
{
int[] temp = new int[Block8x8.Size];
@@ -231,6 +232,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg.Utils
/// ASSP, Vol. ASSP- 32, pp. 803-816, Aug. 1984.
///
/// The source block of coefficients
+ [Obsolete("Looks like this method produces really bad results for bigger values!")]
public static void TransformIDCTInplace(Span src)
{
// Horizontal 1-D IDCT.