diff --git a/tests/ImageSharp.Tests/ImageSharp.Tests.csproj b/tests/ImageSharp.Tests/ImageSharp.Tests.csproj
index 8dd2f2790..55b3c80e3 100644
--- a/tests/ImageSharp.Tests/ImageSharp.Tests.csproj
+++ b/tests/ImageSharp.Tests/ImageSharp.Tests.csproj
@@ -27,7 +27,4 @@
PreserveNewest
-
-
-
\ No newline at end of file
diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelBlenders/PorterDuffFunctionsTests.cs b/tests/ImageSharp.Tests/PixelFormats/PixelBlenders/PorterDuffFunctionsTests.cs
new file mode 100644
index 000000000..45962c589
--- /dev/null
+++ b/tests/ImageSharp.Tests/PixelFormats/PixelBlenders/PorterDuffFunctionsTests.cs
@@ -0,0 +1,183 @@
+//
+// Copyright (c) James Jackson-South and contributors.
+// Licensed under the Apache License, Version 2.0.
+//
+
+namespace ImageSharp.Tests.PixelFormats.PixelBlenders
+{
+ using System;
+ using System.Collections.Generic;
+ using System.Numerics;
+ using System.Text;
+ using ImageSharp.PixelFormats.PixelBlenders;
+ using ImageSharp.Tests.TestUtilities;
+ using Xunit;
+
+ public class PorterDuffFunctionsTests
+ {
+ public static TheoryData NormalBlendFunctionData = new TheoryData() {
+ { new TestVector4(1,1,1,1), new TestVector4(1,1,1,1), 1, new TestVector4(1,1,1,1) },
+ { new TestVector4(1,1,1,1), new TestVector4(0,0,0,.8f), .5f, new TestVector4(0.6f, 0.6f, 0.6f, 1) },
+ };
+
+ [Theory]
+ [MemberData(nameof(NormalBlendFunctionData))]
+ public void NormalBlendFunction(TestVector4 back, TestVector4 source, float amount, TestVector4 expected)
+ {
+ Vector4 actual = PorterDuffFunctions.NormalBlendFunction(back, source, amount);
+ Assert.Equal(expected, actual);
+ }
+
+ public static TheoryData MultiplyFunctionData = new TheoryData() {
+ { new TestVector4(1,1,1,1), new TestVector4(1,1,1,1), 1, new TestVector4(1,1,1,1) },
+ { new TestVector4(1,1,1,1), new TestVector4(0,0,0,.8f), .5f, new TestVector4(0.6f, 0.6f, 0.6f, 1) },
+ {
+ new TestVector4(0.9f,0.9f,0.9f,0.9f),
+ new TestVector4(0.4f,0.4f,0.4f,0.4f),
+ .5f,
+ new TestVector4(0.7834783f, 0.7834783f, 0.7834783f, 0.92f)
+ },
+ };
+
+ [Theory]
+ [MemberData(nameof(MultiplyFunctionData))]
+ public void MultiplyFunction(TestVector4 back, TestVector4 source, float amount, TestVector4 expected)
+ {
+ Vector4 actual = PorterDuffFunctions.MultiplyFunction(back, source, amount);
+ VectorAssert.Equal(expected, actual, 5);
+ }
+
+ public static TheoryData AddFunctionData = new TheoryData() {
+ { new TestVector4(1,1,1,1), new TestVector4(1,1,1,1), 1, new TestVector4(1,1,1,1) },
+ { new TestVector4(1,1,1,1), new TestVector4(0,0,0,.8f), .5f, new TestVector4(.6f, .6f, .6f, 1f) },
+ {
+ new TestVector4(0.2f,0.2f,0.2f,0.3f),
+ new TestVector4(0.3f,0.3f,0.3f,0.2f),
+ .5f,
+ new TestVector4(.2075676f, .2075676f, .2075676f, .37f)
+ },
+ };
+
+ [Theory]
+ [MemberData(nameof(AddFunctionData))]
+ public void AddFunction(TestVector4 back, TestVector4 source, float amount, TestVector4 expected)
+ {
+ Vector4 actual = PorterDuffFunctions.MultiplyFunction(back, source, amount);
+ VectorAssert.Equal(expected, actual, 5);
+ }
+
+ public static TheoryData SubstractFunctionData = new TheoryData() {
+ { new TestVector4(1,1,1,1), new TestVector4(1,1,1,1), 1, new TestVector4(0,0,0,1) },
+ { new TestVector4(1,1,1,1), new TestVector4(0,0,0,.8f), .5f, new TestVector4(1,1,1, 1f) },
+ {
+ new TestVector4(0.2f,0.2f,0.2f,0.3f),
+ new TestVector4(0.3f,0.3f,0.3f,0.2f),
+ .5f,
+ new TestVector4(.2027027f, .2027027f, .2027027f, .37f)
+ },
+ };
+
+ [Theory]
+ [MemberData(nameof(SubstractFunctionData))]
+ public void SubstractFunction(TestVector4 back, TestVector4 source, float amount, TestVector4 expected)
+ {
+ Vector4 actual = PorterDuffFunctions.SubstractFunction(back, source, amount);
+ VectorAssert.Equal(expected, actual, 5);
+ }
+
+ public static TheoryData ScreenFunctionData = new TheoryData() {
+ { new TestVector4(1,1,1,1), new TestVector4(1,1,1,1), 1, new TestVector4(1,1,1,1) },
+ { new TestVector4(1,1,1,1), new TestVector4(0,0,0,.8f), .5f, new TestVector4(1,1,1, 1f) },
+ {
+ new TestVector4(0.2f,0.2f,0.2f,0.3f),
+ new TestVector4(0.3f,0.3f,0.3f,0.2f),
+ .5f,
+ new TestVector4(.2383784f, .2383784f, .2383784f, .37f)
+ },
+ };
+
+ [Theory]
+ [MemberData(nameof(ScreenFunctionData))]
+ public void ScreenFunction(TestVector4 back, TestVector4 source, float amount, TestVector4 expected)
+ {
+ Vector4 actual = PorterDuffFunctions.ScreenFunction(back, source, amount);
+ VectorAssert.Equal(expected, actual, 5);
+ }
+
+ public static TheoryData DarkenFunctionData = new TheoryData() {
+ { new TestVector4(1,1,1,1), new TestVector4(1,1,1,1), 1, new TestVector4(1,1,1,1) },
+ { new TestVector4(1,1,1,1), new TestVector4(0,0,0,.8f), .5f, new TestVector4(.6f,.6f,.6f, 1f) },
+ {
+ new TestVector4(0.2f,0.2f,0.2f,0.3f),
+ new TestVector4(0.3f,0.3f,0.3f,0.2f),
+ .5f,
+ new TestVector4(.2189189f, .2189189f, .2189189f, .37f)
+ },
+ };
+
+ [Theory]
+ [MemberData(nameof(DarkenFunctionData))]
+ public void DarkenFunction(TestVector4 back, TestVector4 source, float amount, TestVector4 expected)
+ {
+ Vector4 actual = PorterDuffFunctions.DarkenFunction(back, source, amount);
+ VectorAssert.Equal(expected, actual, 5);
+ }
+
+ public static TheoryData LightenFunctionData = new TheoryData() {
+ { new TestVector4(1,1,1,1), new TestVector4(1,1,1,1), 1, new TestVector4(1,1,1,1) },
+ { new TestVector4(1,1,1,1), new TestVector4(0,0,0,.8f), .5f, new TestVector4(1,1,1,1f) },
+ {
+ new TestVector4(0.2f,0.2f,0.2f,0.3f),
+ new TestVector4(0.3f,0.3f,0.3f,0.2f),
+ .5f,
+ new TestVector4(.227027f, .227027f, .227027f, .37f)
+ },
+ };
+
+ [Theory]
+ [MemberData(nameof(LightenFunctionData))]
+ public void LightenFunction(TestVector4 back, TestVector4 source, float amount, TestVector4 expected)
+ {
+ Vector4 actual = PorterDuffFunctions.LightenFunction(back, source, amount);
+ VectorAssert.Equal(expected, actual, 5);
+ }
+
+ public static TheoryData OverlayFunctionData = new TheoryData() {
+ { new TestVector4(1,1,1,1), new TestVector4(1,1,1,1), 1, new TestVector4(1,1,1,1) },
+ { new TestVector4(1,1,1,1), new TestVector4(0,0,0,.8f), .5f, new TestVector4(1,1,1,1f) },
+ {
+ new TestVector4(0.2f,0.2f,0.2f,0.3f),
+ new TestVector4(0.3f,0.3f,0.3f,0.2f),
+ .5f,
+ new TestVector4(.2124324f, .2124324f, .2124324f, .37f)
+ },
+ };
+
+ [Theory]
+ [MemberData(nameof(OverlayFunctionData))]
+ public void OverlayFunction(TestVector4 back, TestVector4 source, float amount, TestVector4 expected)
+ {
+ Vector4 actual = PorterDuffFunctions.OverlayFunction(back, source, amount);
+ VectorAssert.Equal(expected, actual, 5);
+ }
+
+ public static TheoryData HardLightFunctionData = new TheoryData() {
+ { new TestVector4(1,1,1,1), new TestVector4(1,1,1,1), 1, new TestVector4(1,1,1,1) },
+ { new TestVector4(1,1,1,1), new TestVector4(0,0,0,.8f), .5f, new TestVector4(0.6f,0.6f,0.6f,1f) },
+ {
+ new TestVector4(0.2f,0.2f,0.2f,0.3f),
+ new TestVector4(0.3f,0.3f,0.3f,0.2f),
+ .5f,
+ new TestVector4(.2124324f, .2124324f, .2124324f, .37f)
+ },
+ };
+
+ [Theory]
+ [MemberData(nameof(HardLightFunctionData))]
+ public void HardLightFunction(TestVector4 back, TestVector4 source, float amount, TestVector4 expected)
+ {
+ Vector4 actual = PorterDuffFunctions.HardLightFunction(back, source, amount);
+ VectorAssert.Equal(expected, actual, 5);
+ }
+ }
+}
diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelBlenders/PorterDuffFunctionsTests_TPixel.cs b/tests/ImageSharp.Tests/PixelFormats/PixelBlenders/PorterDuffFunctionsTests_TPixel.cs
new file mode 100644
index 000000000..168269e51
--- /dev/null
+++ b/tests/ImageSharp.Tests/PixelFormats/PixelBlenders/PorterDuffFunctionsTests_TPixel.cs
@@ -0,0 +1,193 @@
+//
+// Copyright (c) James Jackson-South and contributors.
+// Licensed under the Apache License, Version 2.0.
+//
+
+namespace ImageSharp.Tests.PixelFormats.PixelBlenders
+{
+ using System;
+ using System.Collections.Generic;
+ using System.Numerics;
+ using System.Text;
+ using ImageSharp.PixelFormats;
+ using ImageSharp.PixelFormats.PixelBlenders;
+ using ImageSharp.Tests.TestUtilities;
+ using Xunit;
+
+ public class PorterDuffFunctionsTests_TPixel
+ {
+ public static TheoryData