Browse Source

Merge branch 'master' into js/move-graphics-options

pull/491/head
James Jackson-South 8 years ago
committed by GitHub
parent
commit
b112663606
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      src/ImageSharp/PixelFormats/PixelBlenderMode.cs
  2. 8
      src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.cs
  3. 2
      src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.tt
  4. 130
      src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.Generated.cs
  5. 19
      src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.Generated.tt
  6. 24
      src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.cs
  7. 2
      src/ImageSharp/PixelFormats/PixelOperations{TPixel}.PixelBenders.cs
  8. 2
      tests/ImageSharp.Tests/Drawing/DrawImageTest.cs
  9. 48
      tests/ImageSharp.Tests/PixelFormats/PixelBlenders/PorterDuffCompositorTests.cs
  10. 2
      tests/ImageSharp.Tests/PixelFormats/PixelBlenders/PorterDuffFunctionsTests.cs
  11. 6
      tests/ImageSharp.Tests/PixelFormats/PixelBlenders/PorterDuffFunctionsTests_TPixel.cs
  12. 88
      tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.Blender.cs
  13. 2
      tests/ImageSharp.Tests/TestImages.cs
  14. 2
      tests/Images/External
  15. BIN
      tests/Images/Input/Png/pd-dest.png
  16. BIN
      tests/Images/Input/Png/pd-source.png

2
src/ImageSharp/PixelFormats/PixelBlenderMode.cs

@ -26,7 +26,7 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <summary>
/// Blends the 2 values by subtraction.
/// </summary>
Substract,
Subtract,
/// <summary>
/// Multiplies the complements of the backdrop and source values, then complements the result.

8
src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.cs

@ -141,17 +141,17 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
}
}
internal class Substract : PixelBlender<TPixel>
internal class Subtract : PixelBlender<TPixel>
{
/// <summary>
/// Gets the static instance of this blender.
/// </summary>
public static Substract Instance { get; } = new Substract();
public static Subtract Instance { get; } = new Subtract();
/// <inheritdoc />
public override TPixel Blend(TPixel background, TPixel source, float amount)
{
return PorterDuffFunctions.Substract(background, source, amount);
return PorterDuffFunctions.Subtract(background, source, amount);
}
/// <inheritdoc />
@ -172,7 +172,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
for (int i = 0; i < destination.Length; i++)
{
destinationSpan[i] = PorterDuffFunctions.Substract(backgroundSpan[i], sourceSpan[i], amount[i]);
destinationSpan[i] = PorterDuffFunctions.Subtract(backgroundSpan[i], sourceSpan[i], amount[i]);
}
PixelOperations<TPixel>.Instance.PackFromVector4(destinationSpan, destination, destination.Length);

2
src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.tt

@ -42,7 +42,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
"Normal",
"Multiply",
"Add",
"Substract",
"Subtract",
"Screen",
"Darken",
"Lighten",

130
src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.Generated.cs

@ -15,19 +15,19 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
public static Vector4 Src(Vector4 backdrop, Vector4 source, float opacity)
{
opacity = opacity.Clamp(0, 1);
source.W *= opacity;
Vector4 xform = source;
source.W *= opacity;
// calculate weights
float xw = Vector4.Zero.W * source.W;
float bw = Vector4.Zero.W - xw;
float xw = backdrop.W * source.W;
float bw = backdrop.W - xw;
float sw = source.W - xw;
// calculate final alpha
float a = xw + bw + sw;
float fw = (sw * 1) + (bw * 0) + (xw * 1);
// calculate final value
xform = ((xform * xw) + (Vector4.Zero * bw) + (source * sw)) / MathF.Max(a, Constants.Epsilon);
Vector4 xform = ((source * xw) + (Vector4.Zero * bw) + (source * sw)) / MathF.Max(fw, Constants.Epsilon);
xform.W = fw;
return Vector4.Lerp(backdrop, xform, opacity);
}
@ -36,18 +36,18 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
public static Vector4 Atop(Vector4 backdrop, Vector4 source, float opacity)
{
opacity = opacity.Clamp(0, 1);
Vector4 xform = source;
// calculate weights
float xw = backdrop.W * Vector4.Zero.W;
float xw = backdrop.W * source.W;
float bw = backdrop.W - xw;
float sw = Vector4.Zero.W - xw;
float sw = source.W - xw;
// calculate final alpha
float a = xw + bw + sw;
float fw = (sw * 0) + (bw * 1) + (xw * 1);
// calculate final value
xform = ((xform * xw) + (backdrop * bw) + (Vector4.Zero * sw)) / MathF.Max(a, Constants.Epsilon);
Vector4 xform = ((source * xw) + (backdrop * bw) + (Vector4.Zero * sw)) / MathF.Max(fw, Constants.Epsilon);
xform.W = fw;
return Vector4.Lerp(backdrop, xform, opacity);
}
@ -56,8 +56,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
public static Vector4 Over(Vector4 backdrop, Vector4 source, float opacity)
{
opacity = opacity.Clamp(0, 1);
source.W *= opacity;
Vector4 xform = source;
source.W *= opacity;
// calculate weights
float xw = backdrop.W * source.W;
@ -65,10 +64,11 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
float sw = source.W - xw;
// calculate final alpha
float a = xw + bw + sw;
float fw = (sw * 1) + (bw * 1) + (xw * 1);
// calculate final value
xform = ((xform * xw) + (backdrop * bw) + (source * sw)) / MathF.Max(a, Constants.Epsilon);
Vector4 xform = ((source * xw) + (backdrop * bw) + (source * sw)) / MathF.Max(fw, Constants.Epsilon);
xform.W = fw;
return Vector4.Lerp(backdrop, xform, opacity);
}
@ -77,18 +77,18 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
public static Vector4 In(Vector4 backdrop, Vector4 source, float opacity)
{
opacity = opacity.Clamp(0, 1);
Vector4 xform = source;
// calculate weights
float xw = Vector4.Zero.W * Vector4.Zero.W;
float bw = Vector4.Zero.W - xw;
float sw = Vector4.Zero.W - xw;
float xw = backdrop.W * source.W;
float bw = backdrop.W - xw;
float sw = source.W - xw;
// calculate final alpha
float a = xw + bw + sw;
float fw = (sw * 0) + (bw * 0) + (xw * 1);
// calculate final value
xform = ((xform * xw) + (Vector4.Zero * bw) + (Vector4.Zero * sw)) / MathF.Max(a, Constants.Epsilon);
Vector4 xform = ((source * xw) + (Vector4.Zero * bw) + (Vector4.Zero * sw)) / MathF.Max(fw, Constants.Epsilon);
xform.W = fw;
return Vector4.Lerp(backdrop, xform, opacity);
}
@ -97,19 +97,19 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
public static Vector4 Out(Vector4 backdrop, Vector4 source, float opacity)
{
opacity = opacity.Clamp(0, 1);
source.W *= opacity;
Vector4 xform = Vector4.Zero;
source.W *= opacity;
// calculate weights
float xw = Vector4.Zero.W * source.W;
float bw = Vector4.Zero.W - xw;
float xw = backdrop.W * source.W;
float bw = backdrop.W - xw;
float sw = source.W - xw;
// calculate final alpha
float a = xw + bw + sw;
float fw = (sw * 1) + (bw * 0) + (xw * 0);
// calculate final value
xform = ((xform * xw) + (Vector4.Zero * bw) + (source * sw)) / MathF.Max(a, Constants.Epsilon);
Vector4 xform = ((Vector4.Zero * xw) + (Vector4.Zero * bw) + (source * sw)) / MathF.Max(fw, Constants.Epsilon);
xform.W = fw;
return Vector4.Lerp(backdrop, xform, opacity);
}
@ -118,18 +118,18 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
public static Vector4 Dest(Vector4 backdrop, Vector4 source, float opacity)
{
opacity = opacity.Clamp(0, 1);
Vector4 xform = backdrop;
// calculate weights
float xw = backdrop.W * Vector4.Zero.W;
float xw = backdrop.W * source.W;
float bw = backdrop.W - xw;
float sw = Vector4.Zero.W - xw;
float sw = source.W - xw;
// calculate final alpha
float a = xw + bw + sw;
float fw = (sw * 0) + (bw * 1) + (xw * 1);
// calculate final value
xform = ((xform * xw) + (backdrop * bw) + (Vector4.Zero * sw)) / MathF.Max(a, Constants.Epsilon);
Vector4 xform = ((backdrop * xw) + (backdrop * bw) + (Vector4.Zero * sw)) / MathF.Max(fw, Constants.Epsilon);
xform.W = fw;
return Vector4.Lerp(backdrop, xform, opacity);
}
@ -138,19 +138,19 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
public static Vector4 DestAtop(Vector4 backdrop, Vector4 source, float opacity)
{
opacity = opacity.Clamp(0, 1);
source.W *= opacity;
Vector4 xform = backdrop;
source.W *= opacity;
// calculate weights
float xw = Vector4.Zero.W * source.W;
float bw = Vector4.Zero.W - xw;
float xw = backdrop.W * source.W;
float bw = backdrop.W - xw;
float sw = source.W - xw;
// calculate final alpha
float a = xw + bw + sw;
float fw = (sw * 1) + (bw * 0) + (xw * 1);
// calculate final value
xform = ((xform * xw) + (Vector4.Zero * bw) + (source * sw)) / MathF.Max(a, Constants.Epsilon);
Vector4 xform = ((backdrop * xw) + (Vector4.Zero * bw) + (source * sw)) / MathF.Max(fw, Constants.Epsilon);
xform.W = fw;
return Vector4.Lerp(backdrop, xform, opacity);
}
@ -159,8 +159,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
public static Vector4 DestOver(Vector4 backdrop, Vector4 source, float opacity)
{
opacity = opacity.Clamp(0, 1);
source.W *= opacity;
Vector4 xform = backdrop;
source.W *= opacity;
// calculate weights
float xw = backdrop.W * source.W;
@ -168,10 +167,11 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
float sw = source.W - xw;
// calculate final alpha
float a = xw + bw + sw;
float fw = (sw * 1) + (bw * 1) + (xw * 1);
// calculate final value
xform = ((xform * xw) + (backdrop * bw) + (source * sw)) / MathF.Max(a, Constants.Epsilon);
Vector4 xform = ((backdrop * xw) + (backdrop * bw) + (source * sw)) / MathF.Max(fw, Constants.Epsilon);
xform.W = fw;
return Vector4.Lerp(backdrop, xform, opacity);
}
@ -180,18 +180,18 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
public static Vector4 DestIn(Vector4 backdrop, Vector4 source, float opacity)
{
opacity = opacity.Clamp(0, 1);
Vector4 xform = backdrop;
// calculate weights
float xw = Vector4.Zero.W * Vector4.Zero.W;
float bw = Vector4.Zero.W - xw;
float sw = Vector4.Zero.W - xw;
float xw = backdrop.W * source.W;
float bw = backdrop.W - xw;
float sw = source.W - xw;
// calculate final alpha
float a = xw + bw + sw;
float fw = (sw * 0) + (bw * 0) + (xw * 1);
// calculate final value
xform = ((xform * xw) + (Vector4.Zero * bw) + (Vector4.Zero * sw)) / MathF.Max(a, Constants.Epsilon);
Vector4 xform = ((backdrop * xw) + (Vector4.Zero * bw) + (Vector4.Zero * sw)) / MathF.Max(fw, Constants.Epsilon);
xform.W = fw;
return Vector4.Lerp(backdrop, xform, opacity);
}
@ -200,18 +200,18 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
public static Vector4 DestOut(Vector4 backdrop, Vector4 source, float opacity)
{
opacity = opacity.Clamp(0, 1);
Vector4 xform = Vector4.Zero;
// calculate weights
float xw = backdrop.W * Vector4.Zero.W;
float xw = backdrop.W * source.W;
float bw = backdrop.W - xw;
float sw = Vector4.Zero.W - xw;
float sw = source.W - xw;
// calculate final alpha
float a = xw + bw + sw;
float fw = (sw * 0) + (bw * 1) + (xw * 0);
// calculate final value
xform = ((xform * xw) + (backdrop * bw) + (Vector4.Zero * sw)) / MathF.Max(a, Constants.Epsilon);
Vector4 xform = ((Vector4.Zero * xw) + (backdrop * bw) + (Vector4.Zero * sw)) / MathF.Max(fw, Constants.Epsilon);
xform.W = fw;
return Vector4.Lerp(backdrop, xform, opacity);
}
@ -220,18 +220,18 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
public static Vector4 Clear(Vector4 backdrop, Vector4 source, float opacity)
{
opacity = opacity.Clamp(0, 1);
Vector4 xform = Vector4.Zero;
// calculate weights
float xw = Vector4.Zero.W * Vector4.Zero.W;
float bw = Vector4.Zero.W - xw;
float sw = Vector4.Zero.W - xw;
float xw = backdrop.W * source.W;
float bw = backdrop.W - xw;
float sw = source.W - xw;
// calculate final alpha
float a = xw + bw + sw;
float fw = (sw * 0) + (bw * 0) + (xw * 0);
// calculate final value
xform = ((xform * xw) + (Vector4.Zero * bw) + (Vector4.Zero * sw)) / MathF.Max(a, Constants.Epsilon);
Vector4 xform = ((Vector4.Zero * xw) + (Vector4.Zero * bw) + (Vector4.Zero * sw)) / MathF.Max(fw, Constants.Epsilon);
xform.W = fw;
return Vector4.Lerp(backdrop, xform, opacity);
}
@ -240,8 +240,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
public static Vector4 Xor(Vector4 backdrop, Vector4 source, float opacity)
{
opacity = opacity.Clamp(0, 1);
source.W *= opacity;
Vector4 xform = Vector4.Zero;
source.W *= opacity;
// calculate weights
float xw = backdrop.W * source.W;
@ -249,10 +248,11 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
float sw = source.W - xw;
// calculate final alpha
float a = xw + bw + sw;
float fw = (sw * 1) + (bw * 1) + (xw * 0);
// calculate final value
xform = ((xform * xw) + (backdrop * bw) + (source * sw)) / MathF.Max(a, Constants.Epsilon);
Vector4 xform = ((Vector4.Zero * xw) + (backdrop * bw) + (source * sw)) / MathF.Max(fw, Constants.Epsilon);
xform.W = fw;
return Vector4.Lerp(backdrop, xform, opacity);
}
@ -285,11 +285,11 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static TPixel Substract<TPixel>(TPixel backdrop, TPixel source, float amount)
public static TPixel Subtract<TPixel>(TPixel backdrop, TPixel source, float amount)
where TPixel : struct, IPixel<TPixel>
{
TPixel dest = default(TPixel);
dest.PackFromVector4(Substract(backdrop.ToVector4(), source.ToVector4(), amount));
dest.PackFromVector4(Subtract(backdrop.ToVector4(), source.ToVector4(), amount));
return dest;
}

19
src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.Generated.tt

@ -40,26 +40,29 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
void GenerateVectorCompositor(string name, string sourceVar, string destVar, string blendVar)
{
int a_s = sourceVar == "Vector4.Zero" ? 0 : 1;
int a_b = destVar == "Vector4.Zero" ? 0 : 1;
int a_x = blendVar == "Vector4.Zero" ? 0 : 1;
#>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4 <#=name#>(Vector4 backdrop, Vector4 source, float opacity)
{
opacity = opacity.Clamp(0, 1);
<# if(sourceVar != "Vector4.Zero" ) { #>
source.W *= opacity;
source.W *= opacity;
<# } #>
Vector4 xform = <#=blendVar#>;
// calculate weights
float xw = <#=destVar#>.W * <#=sourceVar#>.W;
float bw = <#=destVar#>.W - xw;
float sw = <#=sourceVar#>.W - xw;
float xw = backdrop.W * source.W;
float bw = backdrop.W - xw;
float sw = source.W - xw;
// calculate final alpha
float a = xw + bw + sw;
float fw = (sw * <#=a_s#>) + (bw * <#=a_b#>) + (xw * <#=a_x#>);
// calculate final value
xform = ((xform * xw) + (<#=destVar#> * bw) + (<#=sourceVar#> * sw)) / MathF.Max(a, Constants.Epsilon);
Vector4 xform = ((<#=blendVar#> * xw) + (<#=destVar#> * bw) + (<#=sourceVar#> * sw)) / MathF.Max(fw, Constants.Epsilon);
xform.W = fw;
return Vector4.Lerp(backdrop, xform, opacity);
}
@ -83,7 +86,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
GeneratePixelBlender("Normal");
GeneratePixelBlender("Multiply");
GeneratePixelBlender("Add");
GeneratePixelBlender("Substract");
GeneratePixelBlender("Subtract");
GeneratePixelBlender("Screen");
GeneratePixelBlender("Darken");
GeneratePixelBlender("Lighten");

24
src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.cs

@ -23,7 +23,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
/// <summary>
/// Source over backdrop
/// </summary>
/// <param name="backdrop">Backgrop color</param>
/// <param name="backdrop">Backdrop color</param>
/// <param name="source">Source color</param>
/// <param name="opacity">Opacity applied to Source Alpha</param>
/// <returns>Output color</returns>
@ -37,7 +37,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
/// <summary>
/// Source multiplied by backdrop
/// </summary>
/// <param name="backdrop">Backgrop color</param>
/// <param name="backdrop">Backdrop color</param>
/// <param name="source">Source color</param>
/// <param name="opacity">Opacity applied to Source Alpha</param>
/// <returns>Output color</returns>
@ -51,7 +51,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
/// <summary>
/// Source added to backdrop
/// </summary>
/// <param name="backdrop">Backgrop color</param>
/// <param name="backdrop">Backdrop color</param>
/// <param name="source">Source color</param>
/// <param name="opacity">Opacity applied to Source Alpha</param>
/// <returns>Output color</returns>
@ -63,14 +63,14 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
}
/// <summary>
/// Source substracted from backdrop
/// Source subtracted from backdrop
/// </summary>
/// <param name="backdrop">Backgrop color</param>
/// <param name="backdrop">Backdrop color</param>
/// <param name="source">Source color</param>
/// <param name="opacity">Opacity applied to Source Alpha</param>
/// <returns>Output color</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4 Substract(Vector4 backdrop, Vector4 source, float opacity)
public static Vector4 Subtract(Vector4 backdrop, Vector4 source, float opacity)
{
source.W *= opacity;
return Compose(backdrop, source, Vector4.Max(Vector4.Zero, backdrop - source));
@ -79,7 +79,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
/// <summary>
/// Complement of source multiplied by the complement of backdrop
/// </summary>
/// <param name="backdrop">Backgrop color</param>
/// <param name="backdrop">Backdrop color</param>
/// <param name="source">Source color</param>
/// <param name="opacity">Opacity applied to Source Alpha</param>
/// <returns>Output color</returns>
@ -93,7 +93,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
/// <summary>
/// Per element, chooses the smallest value of source and backdrop
/// </summary>
/// <param name="backdrop">Backgrop color</param>
/// <param name="backdrop">Backdrop color</param>
/// <param name="source">Source color</param>
/// <param name="opacity">Opacity applied to Source Alpha</param>
/// <returns>Output color</returns>
@ -107,7 +107,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
/// <summary>
/// Per element, chooses the largest value of source and backdrop
/// </summary>
/// <param name="backdrop">Backgrop color</param>
/// <param name="backdrop">Backdrop color</param>
/// <param name="source">Source color</param>
/// <param name="opacity">Opacity applied to Source Alpha</param>
/// <returns>Output color</returns>
@ -121,7 +121,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
/// <summary>
/// Overlays source over backdrop
/// </summary>
/// <param name="backdrop">Backgrop color</param>
/// <param name="backdrop">Backdrop color</param>
/// <param name="source">Source color</param>
/// <param name="opacity">Opacity applied to Source Alpha</param>
/// <returns>Output color</returns>
@ -139,7 +139,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
/// <summary>
/// Hard light effect
/// </summary>
/// <param name="backdrop">Backgrop color</param>
/// <param name="backdrop">Backdrop color</param>
/// <param name="source">Source color</param>
/// <param name="opacity">Opacity applied to Source Alpha</param>
/// <returns>Output color</returns>
@ -169,7 +169,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
/// <summary>
/// General composition function for all modes, with a general solution for alpha channel
/// </summary>
/// <param name="backdrop">Original backgrop color</param>
/// <param name="backdrop">Original Backdrop color</param>
/// <param name="source">Original source color</param>
/// <param name="xform">Desired transformed color, without taking Alpha channel in account</param>
/// <returns>The final color</returns>

2
src/ImageSharp/PixelFormats/PixelOperations{TPixel}.PixelBenders.cs

@ -22,7 +22,7 @@ namespace SixLabors.ImageSharp.PixelFormats
{
case PixelBlenderMode.Multiply: return DefaultPixelBlenders<TPixel>.Multiply.Instance;
case PixelBlenderMode.Add: return DefaultPixelBlenders<TPixel>.Add.Instance;
case PixelBlenderMode.Substract: return DefaultPixelBlenders<TPixel>.Substract.Instance;
case PixelBlenderMode.Subtract: return DefaultPixelBlenders<TPixel>.Subtract.Instance;
case PixelBlenderMode.Screen: return DefaultPixelBlenders<TPixel>.Screen.Instance;
case PixelBlenderMode.Darken: return DefaultPixelBlenders<TPixel>.Darken.Instance;
case PixelBlenderMode.Lighten: return DefaultPixelBlenders<TPixel>.Lighten.Instance;

2
tests/ImageSharp.Tests/Drawing/DrawImageTest.cs

@ -28,7 +28,7 @@ namespace SixLabors.ImageSharp.Tests
[WithFileCollection(nameof(TestFiles), PixelTypes, PixelBlenderMode.Normal)]
[WithFileCollection(nameof(TestFiles), PixelTypes, PixelBlenderMode.Multiply)]
[WithFileCollection(nameof(TestFiles), PixelTypes, PixelBlenderMode.Add)]
[WithFileCollection(nameof(TestFiles), PixelTypes, PixelBlenderMode.Substract)]
[WithFileCollection(nameof(TestFiles), PixelTypes, PixelBlenderMode.Subtract)]
[WithFileCollection(nameof(TestFiles), PixelTypes, PixelBlenderMode.Screen)]
[WithFileCollection(nameof(TestFiles), PixelTypes, PixelBlenderMode.Darken)]
[WithFileCollection(nameof(TestFiles), PixelTypes, PixelBlenderMode.Lighten)]

48
tests/ImageSharp.Tests/PixelFormats/PixelBlenders/PorterDuffCompositorTests.cs

@ -0,0 +1,48 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelBlenders
{
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing;
using SixLabors.ImageSharp.Processing.Drawing;
using Xunit;
public class PorterDuffCompositorTests
{
// TODO: Add other modes to compare.
public static readonly TheoryData<PixelBlenderMode> CompositingOperators =
new TheoryData<PixelBlenderMode>
{
PixelBlenderMode.Src,
PixelBlenderMode.Atop,
PixelBlenderMode.Over,
PixelBlenderMode.In,
PixelBlenderMode.Out,
PixelBlenderMode.Dest,
PixelBlenderMode.DestAtop,
PixelBlenderMode.DestOver,
PixelBlenderMode.DestIn,
PixelBlenderMode.DestOut,
PixelBlenderMode.Clear,
PixelBlenderMode.Xor
};
[Theory]
[WithFile(TestImages.Png.PDDest, nameof(CompositingOperators), PixelTypes.Rgba32)]
public void PorterDuffOutputIsCorrect(TestImageProvider<Rgba32> provider, PixelBlenderMode mode)
{
var srcFile = TestFile.Create(TestImages.Png.PDSrc);
using (Image<Rgba32> src = srcFile.CreateImage())
using (Image<Rgba32> dest = provider.GetImage())
{
using (Image<Rgba32> res = dest.Clone(x => x.Blend(src, new GraphicsOptions { BlenderMode = mode })))
{
res.DebugSave(provider, mode.ToString());
res.CompareToReferenceOutput(provider, mode.ToString());
}
}
}
}
}

2
tests/ImageSharp.Tests/PixelFormats/PixelBlenders/PorterDuffFunctionsTests.cs

@ -79,7 +79,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelBlenders
[MemberData(nameof(SubstractFunctionData))]
public void SubstractFunction(TestVector4 back, TestVector4 source, float amount, TestVector4 expected)
{
Vector4 actual = PorterDuffFunctions.Substract((Vector4)back, source, amount);
Vector4 actual = PorterDuffFunctions.Subtract((Vector4)back, source, amount);
VectorAssert.Equal(expected, actual, 5);
}

6
tests/ImageSharp.Tests/PixelFormats/PixelBlenders/PorterDuffFunctionsTests_TPixel.cs

@ -151,7 +151,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelBlenders
public void SubstractFunction<TPixel>(TestPixel<TPixel> back, TestPixel<TPixel> source, float amount, TestPixel<TPixel> expected)
where TPixel : struct, IPixel<TPixel>
{
TPixel actual = PorterDuffFunctions.Substract((TPixel)back, source, amount);
TPixel actual = PorterDuffFunctions.Subtract((TPixel)back, source, amount);
VectorAssert.Equal(expected, actual, 2);
}
@ -160,7 +160,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelBlenders
public void SubstractFunction_Blender<TPixel>(TestPixel<TPixel> back, TestPixel<TPixel> source, float amount, TestPixel<TPixel> expected)
where TPixel : struct, IPixel<TPixel>
{
TPixel actual = new DefaultPixelBlenders<TPixel>.Substract().Blend(back, source, amount);
TPixel actual = new DefaultPixelBlenders<TPixel>.Subtract().Blend(back, source, amount);
VectorAssert.Equal(expected, actual, 2);
}
@ -170,7 +170,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelBlenders
where TPixel : struct, IPixel<TPixel>
{
Span<TPixel> dest = new Span<TPixel>(new TPixel[1]);
new DefaultPixelBlenders<TPixel>.Substract().Blend(this.MemoryManager, dest, back.AsSpan(), source.AsSpan(), AsSpan(amount));
new DefaultPixelBlenders<TPixel>.Subtract().Blend(this.MemoryManager, dest, back.AsSpan(), source.AsSpan(), AsSpan(amount));
VectorAssert.Equal(expected, dest[0], 2);
}

88
tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.Blender.cs

@ -16,53 +16,53 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats
public static TheoryData<object, Type, PixelBlenderMode> BlenderMappings = new TheoryData<object, Type, PixelBlenderMode>()
{
{ new TestPixel<Rgba32>(), typeof(DefaultPixelBlenders<Rgba32>.Normal), PixelBlenderMode.Normal },
{ new TestPixel<Rgba32>(), typeof(DefaultPixelBlenders<Rgba32>.Screen), PixelBlenderMode.Screen },
{ new TestPixel<Rgba32>(), typeof(DefaultPixelBlenders<Rgba32>.HardLight), PixelBlenderMode.HardLight },
{ new TestPixel<Rgba32>(), typeof(DefaultPixelBlenders<Rgba32>.Overlay), PixelBlenderMode.Overlay },
{ new TestPixel<Rgba32>(), typeof(DefaultPixelBlenders<Rgba32>.Darken), PixelBlenderMode.Darken },
{ new TestPixel<Rgba32>(), typeof(DefaultPixelBlenders<Rgba32>.Lighten), PixelBlenderMode.Lighten },
{ new TestPixel<Rgba32>(), typeof(DefaultPixelBlenders<Rgba32>.Add), PixelBlenderMode.Add },
{ new TestPixel<Rgba32>(), typeof(DefaultPixelBlenders<Rgba32>.Substract), PixelBlenderMode.Substract },
{ new TestPixel<Rgba32>(), typeof(DefaultPixelBlenders<Rgba32>.Multiply), PixelBlenderMode.Multiply },
{
{ new TestPixel<Rgba32>(), typeof(DefaultPixelBlenders<Rgba32>.Normal), PixelBlenderMode.Normal },
{ new TestPixel<Rgba32>(), typeof(DefaultPixelBlenders<Rgba32>.Screen), PixelBlenderMode.Screen },
{ new TestPixel<Rgba32>(), typeof(DefaultPixelBlenders<Rgba32>.HardLight), PixelBlenderMode.HardLight },
{ new TestPixel<Rgba32>(), typeof(DefaultPixelBlenders<Rgba32>.Overlay), PixelBlenderMode.Overlay },
{ new TestPixel<Rgba32>(), typeof(DefaultPixelBlenders<Rgba32>.Darken), PixelBlenderMode.Darken },
{ new TestPixel<Rgba32>(), typeof(DefaultPixelBlenders<Rgba32>.Lighten), PixelBlenderMode.Lighten },
{ new TestPixel<Rgba32>(), typeof(DefaultPixelBlenders<Rgba32>.Add), PixelBlenderMode.Add },
{ new TestPixel<Rgba32>(), typeof(DefaultPixelBlenders<Rgba32>.Subtract), PixelBlenderMode.Subtract },
{ new TestPixel<Rgba32>(), typeof(DefaultPixelBlenders<Rgba32>.Multiply), PixelBlenderMode.Multiply },
{ new TestPixel<Rgba32>(), typeof(DefaultPixelBlenders<Rgba32>.Src), PixelBlenderMode.Src },
{ new TestPixel<Rgba32>(), typeof(DefaultPixelBlenders<Rgba32>.Atop), PixelBlenderMode.Atop },
{ new TestPixel<Rgba32>(), typeof(DefaultPixelBlenders<Rgba32>.Over), PixelBlenderMode.Over },
{ new TestPixel<Rgba32>(), typeof(DefaultPixelBlenders<Rgba32>.In), PixelBlenderMode.In },
{ new TestPixel<Rgba32>(), typeof(DefaultPixelBlenders<Rgba32>.Out), PixelBlenderMode.Out },
{ new TestPixel<Rgba32>(), typeof(DefaultPixelBlenders<Rgba32>.Dest), PixelBlenderMode.Dest },
{ new TestPixel<Rgba32>(), typeof(DefaultPixelBlenders<Rgba32>.DestAtop), PixelBlenderMode.DestAtop },
{ new TestPixel<Rgba32>(), typeof(DefaultPixelBlenders<Rgba32>.DestOver), PixelBlenderMode.DestOver },
{ new TestPixel<Rgba32>(), typeof(DefaultPixelBlenders<Rgba32>.DestIn), PixelBlenderMode.DestIn },
{ new TestPixel<Rgba32>(), typeof(DefaultPixelBlenders<Rgba32>.DestOut), PixelBlenderMode.DestOut },
{ new TestPixel<Rgba32>(), typeof(DefaultPixelBlenders<Rgba32>.Clear), PixelBlenderMode.Clear },
{ new TestPixel<Rgba32>(), typeof(DefaultPixelBlenders<Rgba32>.Xor), PixelBlenderMode.Xor },
{ new TestPixel<Rgba32>(), typeof(DefaultPixelBlenders<Rgba32>.Src), PixelBlenderMode.Src },
{ new TestPixel<Rgba32>(), typeof(DefaultPixelBlenders<Rgba32>.Atop), PixelBlenderMode.Atop },
{ new TestPixel<Rgba32>(), typeof(DefaultPixelBlenders<Rgba32>.Over), PixelBlenderMode.Over },
{ new TestPixel<Rgba32>(), typeof(DefaultPixelBlenders<Rgba32>.In), PixelBlenderMode.In },
{ new TestPixel<Rgba32>(), typeof(DefaultPixelBlenders<Rgba32>.Out), PixelBlenderMode.Out },
{ new TestPixel<Rgba32>(), typeof(DefaultPixelBlenders<Rgba32>.Dest), PixelBlenderMode.Dest },
{ new TestPixel<Rgba32>(), typeof(DefaultPixelBlenders<Rgba32>.DestAtop), PixelBlenderMode.DestAtop },
{ new TestPixel<Rgba32>(), typeof(DefaultPixelBlenders<Rgba32>.DestOver), PixelBlenderMode.DestOver },
{ new TestPixel<Rgba32>(), typeof(DefaultPixelBlenders<Rgba32>.DestIn), PixelBlenderMode.DestIn },
{ new TestPixel<Rgba32>(), typeof(DefaultPixelBlenders<Rgba32>.DestOut), PixelBlenderMode.DestOut },
{ new TestPixel<Rgba32>(), typeof(DefaultPixelBlenders<Rgba32>.Clear), PixelBlenderMode.Clear },
{ new TestPixel<Rgba32>(), typeof(DefaultPixelBlenders<Rgba32>.Xor), PixelBlenderMode.Xor },
{ new TestPixel<RgbaVector>(), typeof(DefaultPixelBlenders<RgbaVector>.Normal), PixelBlenderMode.Normal },
{ new TestPixel<RgbaVector>(), typeof(DefaultPixelBlenders<RgbaVector>.Screen), PixelBlenderMode.Screen },
{ new TestPixel<RgbaVector>(), typeof(DefaultPixelBlenders<RgbaVector>.HardLight), PixelBlenderMode.HardLight },
{ new TestPixel<RgbaVector>(), typeof(DefaultPixelBlenders<RgbaVector>.Overlay), PixelBlenderMode.Overlay },
{ new TestPixel<RgbaVector>(), typeof(DefaultPixelBlenders<RgbaVector>.Darken), PixelBlenderMode.Darken },
{ new TestPixel<RgbaVector>(), typeof(DefaultPixelBlenders<RgbaVector>.Lighten), PixelBlenderMode.Lighten },
{ new TestPixel<RgbaVector>(), typeof(DefaultPixelBlenders<RgbaVector>.Add), PixelBlenderMode.Add },
{ new TestPixel<RgbaVector>(), typeof(DefaultPixelBlenders<RgbaVector>.Substract), PixelBlenderMode.Substract },
{ new TestPixel<RgbaVector>(), typeof(DefaultPixelBlenders<RgbaVector>.Multiply), PixelBlenderMode.Multiply },
{ new TestPixel<RgbaVector>(), typeof(DefaultPixelBlenders<RgbaVector>.Src), PixelBlenderMode.Src },
{ new TestPixel<RgbaVector>(), typeof(DefaultPixelBlenders<RgbaVector>.Atop), PixelBlenderMode.Atop },
{ new TestPixel<RgbaVector>(), typeof(DefaultPixelBlenders<RgbaVector>.Over), PixelBlenderMode.Over },
{ new TestPixel<RgbaVector>(), typeof(DefaultPixelBlenders<RgbaVector>.In), PixelBlenderMode.In },
{ new TestPixel<RgbaVector>(), typeof(DefaultPixelBlenders<RgbaVector>.Out), PixelBlenderMode.Out },
{ new TestPixel<RgbaVector>(), typeof(DefaultPixelBlenders<RgbaVector>.Dest), PixelBlenderMode.Dest },
{ new TestPixel<RgbaVector>(), typeof(DefaultPixelBlenders<RgbaVector>.DestAtop), PixelBlenderMode.DestAtop },
{ new TestPixel<RgbaVector>(), typeof(DefaultPixelBlenders<RgbaVector>.DestOver), PixelBlenderMode.DestOver },
{ new TestPixel<RgbaVector>(), typeof(DefaultPixelBlenders<RgbaVector>.DestIn), PixelBlenderMode.DestIn },
{ new TestPixel<RgbaVector>(), typeof(DefaultPixelBlenders<RgbaVector>.DestOut), PixelBlenderMode.DestOut },
{ new TestPixel<RgbaVector>(), typeof(DefaultPixelBlenders<RgbaVector>.Clear), PixelBlenderMode.Clear },
{ new TestPixel<RgbaVector>(), typeof(DefaultPixelBlenders<RgbaVector>.Xor), PixelBlenderMode.Xor },
{ new TestPixel<RgbaVector>(), typeof(DefaultPixelBlenders<RgbaVector>.Normal), PixelBlenderMode.Normal },
{ new TestPixel<RgbaVector>(), typeof(DefaultPixelBlenders<RgbaVector>.Screen), PixelBlenderMode.Screen },
{ new TestPixel<RgbaVector>(), typeof(DefaultPixelBlenders<RgbaVector>.HardLight), PixelBlenderMode.HardLight },
{ new TestPixel<RgbaVector>(), typeof(DefaultPixelBlenders<RgbaVector>.Overlay), PixelBlenderMode.Overlay },
{ new TestPixel<RgbaVector>(), typeof(DefaultPixelBlenders<RgbaVector>.Darken), PixelBlenderMode.Darken },
{ new TestPixel<RgbaVector>(), typeof(DefaultPixelBlenders<RgbaVector>.Lighten), PixelBlenderMode.Lighten },
{ new TestPixel<RgbaVector>(), typeof(DefaultPixelBlenders<RgbaVector>.Add), PixelBlenderMode.Add },
{ new TestPixel<RgbaVector>(), typeof(DefaultPixelBlenders<RgbaVector>.Subtract), PixelBlenderMode.Subtract },
{ new TestPixel<RgbaVector>(), typeof(DefaultPixelBlenders<RgbaVector>.Multiply), PixelBlenderMode.Multiply },
{ new TestPixel<RgbaVector>(), typeof(DefaultPixelBlenders<RgbaVector>.Src), PixelBlenderMode.Src },
{ new TestPixel<RgbaVector>(), typeof(DefaultPixelBlenders<RgbaVector>.Atop), PixelBlenderMode.Atop },
{ new TestPixel<RgbaVector>(), typeof(DefaultPixelBlenders<RgbaVector>.Over), PixelBlenderMode.Over },
{ new TestPixel<RgbaVector>(), typeof(DefaultPixelBlenders<RgbaVector>.In), PixelBlenderMode.In },
{ new TestPixel<RgbaVector>(), typeof(DefaultPixelBlenders<RgbaVector>.Out), PixelBlenderMode.Out },
{ new TestPixel<RgbaVector>(), typeof(DefaultPixelBlenders<RgbaVector>.Dest), PixelBlenderMode.Dest },
{ new TestPixel<RgbaVector>(), typeof(DefaultPixelBlenders<RgbaVector>.DestAtop), PixelBlenderMode.DestAtop },
{ new TestPixel<RgbaVector>(), typeof(DefaultPixelBlenders<RgbaVector>.DestOver), PixelBlenderMode.DestOver },
{ new TestPixel<RgbaVector>(), typeof(DefaultPixelBlenders<RgbaVector>.DestIn), PixelBlenderMode.DestIn },
{ new TestPixel<RgbaVector>(), typeof(DefaultPixelBlenders<RgbaVector>.DestOut), PixelBlenderMode.DestOut },
{ new TestPixel<RgbaVector>(), typeof(DefaultPixelBlenders<RgbaVector>.Clear), PixelBlenderMode.Clear },
{ new TestPixel<RgbaVector>(), typeof(DefaultPixelBlenders<RgbaVector>.Xor), PixelBlenderMode.Xor },
};
};
[Theory]
[MemberData(nameof(BlenderMappings))]

2
tests/ImageSharp.Tests/TestImages.cs

@ -36,6 +36,8 @@ namespace SixLabors.ImageSharp.Tests
public const string SnakeGame = "Png/SnakeGame.png";
public const string Icon = "Png/icon.png";
public const string Kaboom = "Png/kaboom.png";
public const string PDSrc = "Png/pd-source.png";
public const string PDDest = "Png/pd-dest.png";
// Filtered test images from http://www.schaik.com/pngsuite/pngsuite_fil_png.html
public const string Filter0 = "Png/filter0.png";

2
tests/Images/External

@ -1 +1 @@
Subproject commit e9f33352b77a5176508d2d5dcafbd1bd33805530
Subproject commit 5a66c9c6da02bf27345f90adc05d415c0d0450ea

BIN
tests/Images/Input/Png/pd-dest.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

BIN
tests/Images/Input/Png/pd-source.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Loading…
Cancel
Save