Browse Source

generate pixel blenders

af/merge-core
Scott Williams 9 years ago
parent
commit
0384acb36f
  1. 6
      .editorconfig
  2. 18
      src/ImageSharp/ImageSharp.csproj
  3. 62
      src/ImageSharp/PixelFormats/PixelBlenderMode.cs
  4. 57
      src/ImageSharp/PixelFormats/PixelBlenders/DefaultAddPixelBlender{TPixel}.cs
  5. 57
      src/ImageSharp/PixelFormats/PixelBlenders/DefaultDarkenPixelBlender{TPixel}.cs
  6. 57
      src/ImageSharp/PixelFormats/PixelBlenders/DefaultHardLightPixelBlender{TPixel}.cs
  7. 57
      src/ImageSharp/PixelFormats/PixelBlenders/DefaultLightenPixelBlender{TPixel}.cs
  8. 57
      src/ImageSharp/PixelFormats/PixelBlenders/DefaultMultiplyPixelBlender{TPixel}.cs
  9. 57
      src/ImageSharp/PixelFormats/PixelBlenders/DefaultNormalPixelBlender{TPixel}.cs
  10. 57
      src/ImageSharp/PixelFormats/PixelBlenders/DefaultOverlayPixelBlender{TPixel}.cs
  11. 849
      src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.cs
  12. 118
      src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.tt
  13. 57
      src/ImageSharp/PixelFormats/PixelBlenders/DefaultScreenPixelBlender{TPixel}.cs
  14. 57
      src/ImageSharp/PixelFormats/PixelBlenders/DefaultSubstractPixelBlender{TPixel}.cs
  15. 314
      src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.Generated.cs
  16. 126
      src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.Generated.tt
  17. 20
      src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.cs
  18. 151
      src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions{TPixel}.cs
  19. 39
      src/ImageSharp/PixelFormats/PixelOperations{TPixel}.PixelBenders.cs
  20. 4
      tests/ImageSharp.Benchmarks/PixelBlenders/PorterDuffBulkVsPixel.cs
  21. 18
      tests/ImageSharp.Tests/PixelFormats/PixelBlenders/PorterDuffFunctionsTests.cs
  22. 54
      tests/ImageSharp.Tests/PixelFormats/PixelBlenders/PorterDuffFunctionsTests_TPixel.cs
  23. 66
      tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.Blender.cs

6
.editorconfig

@ -13,4 +13,8 @@ dotnet_style_predefined_type_for_locals_parameters_members = true:warning
dotnet_style_predefined_type_for_member_access = true:warning
dotnet_style_qualification_for_field = true:warning
dotnet_style_qualification_for_method = true:warning
dotnet_style_qualification_for_property = true:warning
dotnet_style_qualification_for_property = true:warning
[*.tt]
indent_style = space
indent_size = 4

18
src/ImageSharp/ImageSharp.csproj

@ -63,6 +63,14 @@
<Generator>TextTemplatingFileGenerator</Generator>
<LastGenOutput>Rgba32.PixelOperations.Generated.cs</LastGenOutput>
</None>
<None Update="PixelFormats\PixelBlenders\PorterDuffFunctions.Generated.tt">
<LastGenOutput>PorterDuffFunctions.Generated.cs</LastGenOutput>
<Generator>TextTemplatingFileGenerator</Generator>
</None>
<None Update="PixelFormats\PixelBlenders\DefaultPixelBlenders.Generated.tt">
<LastGenOutput>DefaultPixelBlenders.Generated.cs</LastGenOutput>
<Generator>TextTemplatingFileGenerator</Generator>
</None>
</ItemGroup>
<ItemGroup>
<Service Include="{508349b6-6b84-4df5-91f0-309beebad82d}" />
@ -83,5 +91,15 @@
<AutoGen>True</AutoGen>
<DependentUpon>Rgba32.PixelOperations.Generated.tt</DependentUpon>
</Compile>
<Compile Update="PixelFormats\PixelBlenders\DefaultPixelBlenders.Generated.cs">
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
<DependentUpon>DefaultPixelBlenders.Generated.tt</DependentUpon>
</Compile>
<Compile Update="PixelFormats\PixelBlenders\PorterDuffFunctions.Generated.cs">
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
<DependentUpon>PorterDuffFunctions.Generated.tt</DependentUpon>
</Compile>
</ItemGroup>
</Project>

62
src/ImageSharp/PixelFormats/PixelBlenderMode.cs

@ -57,6 +57,66 @@ namespace ImageSharp.PixelFormats
/// <summary>
/// Multiplies or screens the colors, depending on the source value.
/// </summary>
HardLight
HardLight,
/// <summary>
/// returns the source colors
/// </summary>
Src,
/// <summary>
/// returns the source over the destination
/// </summary>
Atop,
/// <summary>
/// returns the detination over the source
/// </summary>
Over,
/// <summary>
/// the source where the desitnation and source overlap
/// </summary>
In,
/// <summary>
/// the destination where the desitnation and source overlap
/// </summary>
Out,
/// <summary>
/// the destination where the source does not overlap it
/// </summary>
Dest,
/// <summary>
/// the source where they dont overlap othersie dest in overlapping parts
/// </summary>
DestAtop,
/// <summary>
/// the destnation over the source
/// </summary>
DestOver,
/// <summary>
/// the destination where the desitnation and source overlap
/// </summary>
DestIn,
/// <summary>
/// the source where the desitnation and source overlap
/// </summary>
DestOut,
/// <summary>
/// the clear.
/// </summary>
Clear,
/// <summary>
/// clear where they overlap
/// </summary>
Xor
}
}

57
src/ImageSharp/PixelFormats/PixelBlenders/DefaultAddPixelBlender{TPixel}.cs

@ -1,57 +0,0 @@
// <copyright file="DefaultAddPixelBlender{TPixel}.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp.PixelFormats.PixelBlenders
{
using System;
using System.Numerics;
using ImageSharp.Memory;
using ImageSharp.PixelFormats;
/// <summary>
/// Applies an "Add" blending to pixels.
/// </summary>
/// <typeparam name="TPixel">The type of the pixel</typeparam>
internal class DefaultAddPixelBlender<TPixel> : PixelBlender<TPixel>
where TPixel : struct, IPixel<TPixel>
{
/// <summary>
/// Gets the static instance of this blender.
/// </summary>
public static DefaultAddPixelBlender<TPixel> Instance { get; } = new DefaultAddPixelBlender<TPixel>();
/// <inheritdoc />
public override TPixel Blend(TPixel background, TPixel source, float amount)
{
return PorterDuffFunctions<TPixel>.AddFunction(background, source, amount);
}
/// <inheritdoc />
public override void Blend(Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount)
{
Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length));
Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length));
Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length));
using (Buffer<Vector4> buffer = new Buffer<Vector4>(destination.Length * 3))
{
Span<Vector4> destinationSpan = buffer.Slice(0, destination.Length);
Span<Vector4> backgroundSpan = buffer.Slice(destination.Length, destination.Length);
Span<Vector4> sourceSpan = buffer.Slice(destination.Length * 2, destination.Length);
PixelOperations<TPixel>.Instance.ToVector4(background, backgroundSpan, destination.Length);
PixelOperations<TPixel>.Instance.ToVector4(source, sourceSpan, destination.Length);
for (int i = 0; i < destination.Length; i++)
{
destinationSpan[i] = PorterDuffFunctions.AddFunction(backgroundSpan[i], sourceSpan[i], amount[i]);
}
PixelOperations<TPixel>.Instance.PackFromVector4(destinationSpan, destination, destination.Length);
}
}
}
}

57
src/ImageSharp/PixelFormats/PixelBlenders/DefaultDarkenPixelBlender{TPixel}.cs

@ -1,57 +0,0 @@
// <copyright file="DefaultDarkenPixelBlender{TPixel}.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp.PixelFormats.PixelBlenders
{
using System;
using System.Numerics;
using ImageSharp.Memory;
using ImageSharp.PixelFormats;
/// <summary>
/// Applies an "Darken" blending to pixels.
/// </summary>
/// <typeparam name="TPixel">The type of the pixel</typeparam>
internal class DefaultDarkenPixelBlender<TPixel> : PixelBlender<TPixel>
where TPixel : struct, IPixel<TPixel>
{
/// <summary>
/// Gets the static instance of this blender.
/// </summary>
public static DefaultDarkenPixelBlender<TPixel> Instance { get; } = new DefaultDarkenPixelBlender<TPixel>();
/// <inheritdoc />
public override TPixel Blend(TPixel background, TPixel source, float amount)
{
return PorterDuffFunctions<TPixel>.DarkenFunction(background, source, amount);
}
/// <inheritdoc />
public override void Blend(Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount)
{
Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length));
Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length));
Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length));
using (Buffer<Vector4> buffer = new Buffer<Vector4>(destination.Length * 3))
{
Span<Vector4> destinationSpan = buffer.Slice(0, destination.Length);
Span<Vector4> backgroundSpan = buffer.Slice(destination.Length, destination.Length);
Span<Vector4> sourceSpan = buffer.Slice(destination.Length * 2, destination.Length);
PixelOperations<TPixel>.Instance.ToVector4(background, backgroundSpan, destination.Length);
PixelOperations<TPixel>.Instance.ToVector4(source, sourceSpan, destination.Length);
for (int i = 0; i < destination.Length; i++)
{
destinationSpan[i] = PorterDuffFunctions.DarkenFunction(backgroundSpan[i], sourceSpan[i], amount[i]);
}
PixelOperations<TPixel>.Instance.PackFromVector4(destinationSpan, destination, destination.Length);
}
}
}
}

57
src/ImageSharp/PixelFormats/PixelBlenders/DefaultHardLightPixelBlender{TPixel}.cs

@ -1,57 +0,0 @@
// <copyright file="DefaultHardLightPixelBlender{TPixel}.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp.PixelFormats.PixelBlenders
{
using System;
using System.Numerics;
using ImageSharp.Memory;
using ImageSharp.PixelFormats;
/// <summary>
/// Applies an "Hard Light" blending to pixels.
/// </summary>
/// <typeparam name="TPixel">The type of the pixel</typeparam>
internal class DefaultHardLightPixelBlender<TPixel> : PixelBlender<TPixel>
where TPixel : struct, IPixel<TPixel>
{
/// <summary>
/// Gets the static instance of this blender.
/// </summary>
public static DefaultHardLightPixelBlender<TPixel> Instance { get; } = new DefaultHardLightPixelBlender<TPixel>();
/// <inheritdoc />
public override TPixel Blend(TPixel background, TPixel source, float amount)
{
return PorterDuffFunctions<TPixel>.HardLightFunction(background, source, amount);
}
/// <inheritdoc />
public override void Blend(Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount)
{
Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length));
Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length));
Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length));
using (Buffer<Vector4> buffer = new Buffer<Vector4>(destination.Length * 3))
{
Span<Vector4> destinationSpan = buffer.Slice(0, destination.Length);
Span<Vector4> backgroundSpan = buffer.Slice(destination.Length, destination.Length);
Span<Vector4> sourceSpan = buffer.Slice(destination.Length * 2, destination.Length);
PixelOperations<TPixel>.Instance.ToVector4(background, backgroundSpan, destination.Length);
PixelOperations<TPixel>.Instance.ToVector4(source, sourceSpan, destination.Length);
for (int i = 0; i < destination.Length; i++)
{
destinationSpan[i] = PorterDuffFunctions.HardLightFunction(backgroundSpan[i], sourceSpan[i], amount[i]);
}
PixelOperations<TPixel>.Instance.PackFromVector4(destinationSpan, destination, destination.Length);
}
}
}
}

57
src/ImageSharp/PixelFormats/PixelBlenders/DefaultLightenPixelBlender{TPixel}.cs

@ -1,57 +0,0 @@
// <copyright file="DefaultLightenPixelBlender{TPixel}.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp.PixelFormats.PixelBlenders
{
using System;
using System.Numerics;
using ImageSharp.Memory;
using ImageSharp.PixelFormats;
/// <summary>
/// Applies an "Lighten" blending to pixels.
/// </summary>
/// <typeparam name="TPixel">The type of the pixel</typeparam>
internal class DefaultLightenPixelBlender<TPixel> : PixelBlender<TPixel>
where TPixel : struct, IPixel<TPixel>
{
/// <summary>
/// Gets the static instance of this blender.
/// </summary>
public static DefaultLightenPixelBlender<TPixel> Instance { get; } = new DefaultLightenPixelBlender<TPixel>();
/// <inheritdoc />
public override TPixel Blend(TPixel background, TPixel source, float amount)
{
return PorterDuffFunctions<TPixel>.LightenFunction(background, source, amount);
}
/// <inheritdoc />
public override void Blend(Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount)
{
Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length));
Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length));
Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length));
using (Buffer<Vector4> buffer = new Buffer<Vector4>(destination.Length * 3))
{
Span<Vector4> destinationSpan = buffer.Slice(0, destination.Length);
Span<Vector4> backgroundSpan = buffer.Slice(destination.Length, destination.Length);
Span<Vector4> sourceSpan = buffer.Slice(destination.Length * 2, destination.Length);
PixelOperations<TPixel>.Instance.ToVector4(background, backgroundSpan, destination.Length);
PixelOperations<TPixel>.Instance.ToVector4(source, sourceSpan, destination.Length);
for (int i = 0; i < destination.Length; i++)
{
destinationSpan[i] = PorterDuffFunctions.LightenFunction(backgroundSpan[i], sourceSpan[i], amount[i]);
}
PixelOperations<TPixel>.Instance.PackFromVector4(destinationSpan, destination, destination.Length);
}
}
}
}

57
src/ImageSharp/PixelFormats/PixelBlenders/DefaultMultiplyPixelBlender{TPixel}.cs

@ -1,57 +0,0 @@
// <copyright file="DefaultMultiplyPixelBlender{TPixel}.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp.PixelFormats.PixelBlenders
{
using System;
using System.Numerics;
using ImageSharp.Memory;
using ImageSharp.PixelFormats;
/// <summary>
/// Applies an "Multiply" blending to pixels.
/// </summary>
/// <typeparam name="TPixel">The type of the pixel</typeparam>
internal class DefaultMultiplyPixelBlender<TPixel> : PixelBlender<TPixel>
where TPixel : struct, IPixel<TPixel>
{
/// <summary>
/// Gets the static instance of this blender.
/// </summary>
public static DefaultMultiplyPixelBlender<TPixel> Instance { get; } = new DefaultMultiplyPixelBlender<TPixel>();
/// <inheritdoc />
public override TPixel Blend(TPixel background, TPixel source, float amount)
{
return PorterDuffFunctions<TPixel>.MultiplyFunction(background, source, amount);
}
/// <inheritdoc />
public override void Blend(Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount)
{
Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length));
Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length));
Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length));
using (Buffer<Vector4> buffer = new Buffer<Vector4>(destination.Length * 3))
{
Span<Vector4> destinationSpan = buffer.Slice(0, destination.Length);
Span<Vector4> backgroundSpan = buffer.Slice(destination.Length, destination.Length);
Span<Vector4> sourceSpan = buffer.Slice(destination.Length * 2, destination.Length);
PixelOperations<TPixel>.Instance.ToVector4(background, backgroundSpan, destination.Length);
PixelOperations<TPixel>.Instance.ToVector4(source, sourceSpan, destination.Length);
for (int i = 0; i < destination.Length; i++)
{
destinationSpan[i] = PorterDuffFunctions.MultiplyFunction(backgroundSpan[i], sourceSpan[i], amount[i]);
}
PixelOperations<TPixel>.Instance.PackFromVector4(destinationSpan, destination, destination.Length);
}
}
}
}

57
src/ImageSharp/PixelFormats/PixelBlenders/DefaultNormalPixelBlender{TPixel}.cs

@ -1,57 +0,0 @@
// <copyright file="DefaultNormalPixelBlender{TPixel}.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp.PixelFormats.PixelBlenders
{
using System;
using System.Numerics;
using ImageSharp.Memory;
using ImageSharp.PixelFormats;
/// <summary>
/// Applies a "Normal" otherwise nown as "Alpha Blending" blending to pixels.
/// </summary>
/// <typeparam name="TPixel">The type of the pixel</typeparam>
internal class DefaultNormalPixelBlender<TPixel> : PixelBlender<TPixel>
where TPixel : struct, IPixel<TPixel>
{
/// <summary>
/// Gets the static instance of this blender.
/// </summary>
public static DefaultNormalPixelBlender<TPixel> Instance { get; } = new DefaultNormalPixelBlender<TPixel>();
/// <inheritdoc />
public override TPixel Blend(TPixel background, TPixel source, float amount)
{
return PorterDuffFunctions<TPixel>.NormalBlendFunction(background, source, amount);
}
/// <inheritdoc />
public override void Blend(Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount)
{
Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length));
Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length));
Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length));
using (Buffer<Vector4> buffer = new Buffer<Vector4>(destination.Length * 3))
{
Span<Vector4> destinationSpan = buffer.Slice(0, destination.Length);
Span<Vector4> backgroundSpan = buffer.Slice(destination.Length, destination.Length);
Span<Vector4> sourceSpan = buffer.Slice(destination.Length * 2, destination.Length);
PixelOperations<TPixel>.Instance.ToVector4(background, backgroundSpan, destination.Length);
PixelOperations<TPixel>.Instance.ToVector4(source, sourceSpan, destination.Length);
for (int i = 0; i < destination.Length; i++)
{
destinationSpan[i] = PorterDuffFunctions.NormalBlendFunction(backgroundSpan[i], sourceSpan[i], amount[i]);
}
PixelOperations<TPixel>.Instance.PackFromVector4(destinationSpan, destination, destination.Length);
}
}
}
}

57
src/ImageSharp/PixelFormats/PixelBlenders/DefaultOverlayPixelBlender{TPixel}.cs

@ -1,57 +0,0 @@
// <copyright file="DefaultOverlayPixelBlender{TPixel}.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp.PixelFormats.PixelBlenders
{
using System;
using System.Numerics;
using ImageSharp.Memory;
using ImageSharp.PixelFormats;
/// <summary>
/// Applies an "Overlay" blending to pixels.
/// </summary>
/// <typeparam name="TPixel">The type of the pixel</typeparam>
internal class DefaultOverlayPixelBlender<TPixel> : PixelBlender<TPixel>
where TPixel : struct, IPixel<TPixel>
{
/// <summary>
/// Gets the static instance of this blender.
/// </summary>
public static DefaultOverlayPixelBlender<TPixel> Instance { get; } = new DefaultOverlayPixelBlender<TPixel>();
/// <inheritdoc />
public override TPixel Blend(TPixel background, TPixel source, float amount)
{
return PorterDuffFunctions<TPixel>.OverlayFunction(background, source, amount);
}
/// <inheritdoc />
public override void Blend(Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount)
{
Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length));
Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length));
Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length));
using (Buffer<Vector4> buffer = new Buffer<Vector4>(destination.Length * 3))
{
Span<Vector4> destinationSpan = buffer.Slice(0, destination.Length);
Span<Vector4> backgroundSpan = buffer.Slice(destination.Length, destination.Length);
Span<Vector4> sourceSpan = buffer.Slice(destination.Length * 2, destination.Length);
PixelOperations<TPixel>.Instance.ToVector4(background, backgroundSpan, destination.Length);
PixelOperations<TPixel>.Instance.ToVector4(source, sourceSpan, destination.Length);
for (int i = 0; i < destination.Length; i++)
{
destinationSpan[i] = PorterDuffFunctions.OverlayFunction(backgroundSpan[i], sourceSpan[i], amount[i]);
}
PixelOperations<TPixel>.Instance.PackFromVector4(destinationSpan, destination, destination.Length);
}
}
}
}

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

@ -0,0 +1,849 @@
// <autogenerated />
// <copyright file="PorterDuffFunctions.Generated.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp.PixelFormats.PixelBlenders
{
using System;
using System.Numerics;
using ImageSharp.Memory;
/// <summary>
/// Collection of Porter Duff alpha blending functions applying different composition models.
/// </summary>
/// <remarks>
/// These functions are designed to be a general solution for all color cases,
/// that is, they take in account the alpha value of both the backdrop
/// and source, and there's no need to alpha-premultiply neither the backdrop
/// nor the source.
/// Note there are faster functions for when the backdrop color is known
/// to be opaque
/// </remarks>
internal static class DefaultPixelBlenders<TPixel>
where TPixel : struct, IPixel<TPixel>
{
internal class Normal : PixelBlender<TPixel>
{
/// <summary>
/// Gets the static instance of this blender.
/// </summary>
public static Normal Instance { get; } = new Normal();
/// <inheritdoc />
public override TPixel Blend(TPixel background, TPixel source, float amount)
{
return PorterDuffFunctions.Normal(background, source, amount);
}
/// <inheritdoc />
public override void Blend(Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount)
{
Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length));
Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length));
Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length));
using (Buffer<Vector4> buffer = new Buffer<Vector4>(destination.Length * 3))
{
Span<Vector4> destinationSpan = buffer.Slice(0, destination.Length);
Span<Vector4> backgroundSpan = buffer.Slice(destination.Length, destination.Length);
Span<Vector4> sourceSpan = buffer.Slice(destination.Length * 2, destination.Length);
PixelOperations<TPixel>.Instance.ToVector4(background, backgroundSpan, destination.Length);
PixelOperations<TPixel>.Instance.ToVector4(source, sourceSpan, destination.Length);
for (int i = 0; i < destination.Length; i++)
{
destinationSpan[i] = PorterDuffFunctions.Normal(backgroundSpan[i], sourceSpan[i], amount[i]);
}
PixelOperations<TPixel>.Instance.PackFromVector4(destinationSpan, destination, destination.Length);
}
}
}
internal class Multiply : PixelBlender<TPixel>
{
/// <summary>
/// Gets the static instance of this blender.
/// </summary>
public static Multiply Instance { get; } = new Multiply();
/// <inheritdoc />
public override TPixel Blend(TPixel background, TPixel source, float amount)
{
return PorterDuffFunctions.Multiply(background, source, amount);
}
/// <inheritdoc />
public override void Blend(Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount)
{
Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length));
Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length));
Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length));
using (Buffer<Vector4> buffer = new Buffer<Vector4>(destination.Length * 3))
{
Span<Vector4> destinationSpan = buffer.Slice(0, destination.Length);
Span<Vector4> backgroundSpan = buffer.Slice(destination.Length, destination.Length);
Span<Vector4> sourceSpan = buffer.Slice(destination.Length * 2, destination.Length);
PixelOperations<TPixel>.Instance.ToVector4(background, backgroundSpan, destination.Length);
PixelOperations<TPixel>.Instance.ToVector4(source, sourceSpan, destination.Length);
for (int i = 0; i < destination.Length; i++)
{
destinationSpan[i] = PorterDuffFunctions.Multiply(backgroundSpan[i], sourceSpan[i], amount[i]);
}
PixelOperations<TPixel>.Instance.PackFromVector4(destinationSpan, destination, destination.Length);
}
}
}
internal class Add : PixelBlender<TPixel>
{
/// <summary>
/// Gets the static instance of this blender.
/// </summary>
public static Add Instance { get; } = new Add();
/// <inheritdoc />
public override TPixel Blend(TPixel background, TPixel source, float amount)
{
return PorterDuffFunctions.Add(background, source, amount);
}
/// <inheritdoc />
public override void Blend(Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount)
{
Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length));
Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length));
Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length));
using (Buffer<Vector4> buffer = new Buffer<Vector4>(destination.Length * 3))
{
Span<Vector4> destinationSpan = buffer.Slice(0, destination.Length);
Span<Vector4> backgroundSpan = buffer.Slice(destination.Length, destination.Length);
Span<Vector4> sourceSpan = buffer.Slice(destination.Length * 2, destination.Length);
PixelOperations<TPixel>.Instance.ToVector4(background, backgroundSpan, destination.Length);
PixelOperations<TPixel>.Instance.ToVector4(source, sourceSpan, destination.Length);
for (int i = 0; i < destination.Length; i++)
{
destinationSpan[i] = PorterDuffFunctions.Add(backgroundSpan[i], sourceSpan[i], amount[i]);
}
PixelOperations<TPixel>.Instance.PackFromVector4(destinationSpan, destination, destination.Length);
}
}
}
internal class Substract : PixelBlender<TPixel>
{
/// <summary>
/// Gets the static instance of this blender.
/// </summary>
public static Substract Instance { get; } = new Substract();
/// <inheritdoc />
public override TPixel Blend(TPixel background, TPixel source, float amount)
{
return PorterDuffFunctions.Substract(background, source, amount);
}
/// <inheritdoc />
public override void Blend(Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount)
{
Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length));
Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length));
Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length));
using (Buffer<Vector4> buffer = new Buffer<Vector4>(destination.Length * 3))
{
Span<Vector4> destinationSpan = buffer.Slice(0, destination.Length);
Span<Vector4> backgroundSpan = buffer.Slice(destination.Length, destination.Length);
Span<Vector4> sourceSpan = buffer.Slice(destination.Length * 2, destination.Length);
PixelOperations<TPixel>.Instance.ToVector4(background, backgroundSpan, destination.Length);
PixelOperations<TPixel>.Instance.ToVector4(source, sourceSpan, destination.Length);
for (int i = 0; i < destination.Length; i++)
{
destinationSpan[i] = PorterDuffFunctions.Substract(backgroundSpan[i], sourceSpan[i], amount[i]);
}
PixelOperations<TPixel>.Instance.PackFromVector4(destinationSpan, destination, destination.Length);
}
}
}
internal class Screen : PixelBlender<TPixel>
{
/// <summary>
/// Gets the static instance of this blender.
/// </summary>
public static Screen Instance { get; } = new Screen();
/// <inheritdoc />
public override TPixel Blend(TPixel background, TPixel source, float amount)
{
return PorterDuffFunctions.Screen(background, source, amount);
}
/// <inheritdoc />
public override void Blend(Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount)
{
Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length));
Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length));
Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length));
using (Buffer<Vector4> buffer = new Buffer<Vector4>(destination.Length * 3))
{
Span<Vector4> destinationSpan = buffer.Slice(0, destination.Length);
Span<Vector4> backgroundSpan = buffer.Slice(destination.Length, destination.Length);
Span<Vector4> sourceSpan = buffer.Slice(destination.Length * 2, destination.Length);
PixelOperations<TPixel>.Instance.ToVector4(background, backgroundSpan, destination.Length);
PixelOperations<TPixel>.Instance.ToVector4(source, sourceSpan, destination.Length);
for (int i = 0; i < destination.Length; i++)
{
destinationSpan[i] = PorterDuffFunctions.Screen(backgroundSpan[i], sourceSpan[i], amount[i]);
}
PixelOperations<TPixel>.Instance.PackFromVector4(destinationSpan, destination, destination.Length);
}
}
}
internal class Darken : PixelBlender<TPixel>
{
/// <summary>
/// Gets the static instance of this blender.
/// </summary>
public static Darken Instance { get; } = new Darken();
/// <inheritdoc />
public override TPixel Blend(TPixel background, TPixel source, float amount)
{
return PorterDuffFunctions.Darken(background, source, amount);
}
/// <inheritdoc />
public override void Blend(Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount)
{
Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length));
Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length));
Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length));
using (Buffer<Vector4> buffer = new Buffer<Vector4>(destination.Length * 3))
{
Span<Vector4> destinationSpan = buffer.Slice(0, destination.Length);
Span<Vector4> backgroundSpan = buffer.Slice(destination.Length, destination.Length);
Span<Vector4> sourceSpan = buffer.Slice(destination.Length * 2, destination.Length);
PixelOperations<TPixel>.Instance.ToVector4(background, backgroundSpan, destination.Length);
PixelOperations<TPixel>.Instance.ToVector4(source, sourceSpan, destination.Length);
for (int i = 0; i < destination.Length; i++)
{
destinationSpan[i] = PorterDuffFunctions.Darken(backgroundSpan[i], sourceSpan[i], amount[i]);
}
PixelOperations<TPixel>.Instance.PackFromVector4(destinationSpan, destination, destination.Length);
}
}
}
internal class Lighten : PixelBlender<TPixel>
{
/// <summary>
/// Gets the static instance of this blender.
/// </summary>
public static Lighten Instance { get; } = new Lighten();
/// <inheritdoc />
public override TPixel Blend(TPixel background, TPixel source, float amount)
{
return PorterDuffFunctions.Lighten(background, source, amount);
}
/// <inheritdoc />
public override void Blend(Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount)
{
Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length));
Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length));
Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length));
using (Buffer<Vector4> buffer = new Buffer<Vector4>(destination.Length * 3))
{
Span<Vector4> destinationSpan = buffer.Slice(0, destination.Length);
Span<Vector4> backgroundSpan = buffer.Slice(destination.Length, destination.Length);
Span<Vector4> sourceSpan = buffer.Slice(destination.Length * 2, destination.Length);
PixelOperations<TPixel>.Instance.ToVector4(background, backgroundSpan, destination.Length);
PixelOperations<TPixel>.Instance.ToVector4(source, sourceSpan, destination.Length);
for (int i = 0; i < destination.Length; i++)
{
destinationSpan[i] = PorterDuffFunctions.Lighten(backgroundSpan[i], sourceSpan[i], amount[i]);
}
PixelOperations<TPixel>.Instance.PackFromVector4(destinationSpan, destination, destination.Length);
}
}
}
internal class Overlay : PixelBlender<TPixel>
{
/// <summary>
/// Gets the static instance of this blender.
/// </summary>
public static Overlay Instance { get; } = new Overlay();
/// <inheritdoc />
public override TPixel Blend(TPixel background, TPixel source, float amount)
{
return PorterDuffFunctions.Overlay(background, source, amount);
}
/// <inheritdoc />
public override void Blend(Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount)
{
Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length));
Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length));
Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length));
using (Buffer<Vector4> buffer = new Buffer<Vector4>(destination.Length * 3))
{
Span<Vector4> destinationSpan = buffer.Slice(0, destination.Length);
Span<Vector4> backgroundSpan = buffer.Slice(destination.Length, destination.Length);
Span<Vector4> sourceSpan = buffer.Slice(destination.Length * 2, destination.Length);
PixelOperations<TPixel>.Instance.ToVector4(background, backgroundSpan, destination.Length);
PixelOperations<TPixel>.Instance.ToVector4(source, sourceSpan, destination.Length);
for (int i = 0; i < destination.Length; i++)
{
destinationSpan[i] = PorterDuffFunctions.Overlay(backgroundSpan[i], sourceSpan[i], amount[i]);
}
PixelOperations<TPixel>.Instance.PackFromVector4(destinationSpan, destination, destination.Length);
}
}
}
internal class HardLight : PixelBlender<TPixel>
{
/// <summary>
/// Gets the static instance of this blender.
/// </summary>
public static HardLight Instance { get; } = new HardLight();
/// <inheritdoc />
public override TPixel Blend(TPixel background, TPixel source, float amount)
{
return PorterDuffFunctions.HardLight(background, source, amount);
}
/// <inheritdoc />
public override void Blend(Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount)
{
Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length));
Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length));
Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length));
using (Buffer<Vector4> buffer = new Buffer<Vector4>(destination.Length * 3))
{
Span<Vector4> destinationSpan = buffer.Slice(0, destination.Length);
Span<Vector4> backgroundSpan = buffer.Slice(destination.Length, destination.Length);
Span<Vector4> sourceSpan = buffer.Slice(destination.Length * 2, destination.Length);
PixelOperations<TPixel>.Instance.ToVector4(background, backgroundSpan, destination.Length);
PixelOperations<TPixel>.Instance.ToVector4(source, sourceSpan, destination.Length);
for (int i = 0; i < destination.Length; i++)
{
destinationSpan[i] = PorterDuffFunctions.HardLight(backgroundSpan[i], sourceSpan[i], amount[i]);
}
PixelOperations<TPixel>.Instance.PackFromVector4(destinationSpan, destination, destination.Length);
}
}
}
internal class Src : PixelBlender<TPixel>
{
/// <summary>
/// Gets the static instance of this blender.
/// </summary>
public static Src Instance { get; } = new Src();
/// <inheritdoc />
public override TPixel Blend(TPixel background, TPixel source, float amount)
{
return PorterDuffFunctions.Src(background, source, amount);
}
/// <inheritdoc />
public override void Blend(Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount)
{
Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length));
Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length));
Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length));
using (Buffer<Vector4> buffer = new Buffer<Vector4>(destination.Length * 3))
{
Span<Vector4> destinationSpan = buffer.Slice(0, destination.Length);
Span<Vector4> backgroundSpan = buffer.Slice(destination.Length, destination.Length);
Span<Vector4> sourceSpan = buffer.Slice(destination.Length * 2, destination.Length);
PixelOperations<TPixel>.Instance.ToVector4(background, backgroundSpan, destination.Length);
PixelOperations<TPixel>.Instance.ToVector4(source, sourceSpan, destination.Length);
for (int i = 0; i < destination.Length; i++)
{
destinationSpan[i] = PorterDuffFunctions.Src(backgroundSpan[i], sourceSpan[i], amount[i]);
}
PixelOperations<TPixel>.Instance.PackFromVector4(destinationSpan, destination, destination.Length);
}
}
}
internal class Atop : PixelBlender<TPixel>
{
/// <summary>
/// Gets the static instance of this blender.
/// </summary>
public static Atop Instance { get; } = new Atop();
/// <inheritdoc />
public override TPixel Blend(TPixel background, TPixel source, float amount)
{
return PorterDuffFunctions.Atop(background, source, amount);
}
/// <inheritdoc />
public override void Blend(Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount)
{
Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length));
Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length));
Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length));
using (Buffer<Vector4> buffer = new Buffer<Vector4>(destination.Length * 3))
{
Span<Vector4> destinationSpan = buffer.Slice(0, destination.Length);
Span<Vector4> backgroundSpan = buffer.Slice(destination.Length, destination.Length);
Span<Vector4> sourceSpan = buffer.Slice(destination.Length * 2, destination.Length);
PixelOperations<TPixel>.Instance.ToVector4(background, backgroundSpan, destination.Length);
PixelOperations<TPixel>.Instance.ToVector4(source, sourceSpan, destination.Length);
for (int i = 0; i < destination.Length; i++)
{
destinationSpan[i] = PorterDuffFunctions.Atop(backgroundSpan[i], sourceSpan[i], amount[i]);
}
PixelOperations<TPixel>.Instance.PackFromVector4(destinationSpan, destination, destination.Length);
}
}
}
internal class Over : PixelBlender<TPixel>
{
/// <summary>
/// Gets the static instance of this blender.
/// </summary>
public static Over Instance { get; } = new Over();
/// <inheritdoc />
public override TPixel Blend(TPixel background, TPixel source, float amount)
{
return PorterDuffFunctions.Over(background, source, amount);
}
/// <inheritdoc />
public override void Blend(Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount)
{
Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length));
Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length));
Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length));
using (Buffer<Vector4> buffer = new Buffer<Vector4>(destination.Length * 3))
{
Span<Vector4> destinationSpan = buffer.Slice(0, destination.Length);
Span<Vector4> backgroundSpan = buffer.Slice(destination.Length, destination.Length);
Span<Vector4> sourceSpan = buffer.Slice(destination.Length * 2, destination.Length);
PixelOperations<TPixel>.Instance.ToVector4(background, backgroundSpan, destination.Length);
PixelOperations<TPixel>.Instance.ToVector4(source, sourceSpan, destination.Length);
for (int i = 0; i < destination.Length; i++)
{
destinationSpan[i] = PorterDuffFunctions.Over(backgroundSpan[i], sourceSpan[i], amount[i]);
}
PixelOperations<TPixel>.Instance.PackFromVector4(destinationSpan, destination, destination.Length);
}
}
}
internal class In : PixelBlender<TPixel>
{
/// <summary>
/// Gets the static instance of this blender.
/// </summary>
public static In Instance { get; } = new In();
/// <inheritdoc />
public override TPixel Blend(TPixel background, TPixel source, float amount)
{
return PorterDuffFunctions.In(background, source, amount);
}
/// <inheritdoc />
public override void Blend(Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount)
{
Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length));
Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length));
Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length));
using (Buffer<Vector4> buffer = new Buffer<Vector4>(destination.Length * 3))
{
Span<Vector4> destinationSpan = buffer.Slice(0, destination.Length);
Span<Vector4> backgroundSpan = buffer.Slice(destination.Length, destination.Length);
Span<Vector4> sourceSpan = buffer.Slice(destination.Length * 2, destination.Length);
PixelOperations<TPixel>.Instance.ToVector4(background, backgroundSpan, destination.Length);
PixelOperations<TPixel>.Instance.ToVector4(source, sourceSpan, destination.Length);
for (int i = 0; i < destination.Length; i++)
{
destinationSpan[i] = PorterDuffFunctions.In(backgroundSpan[i], sourceSpan[i], amount[i]);
}
PixelOperations<TPixel>.Instance.PackFromVector4(destinationSpan, destination, destination.Length);
}
}
}
internal class Out : PixelBlender<TPixel>
{
/// <summary>
/// Gets the static instance of this blender.
/// </summary>
public static Out Instance { get; } = new Out();
/// <inheritdoc />
public override TPixel Blend(TPixel background, TPixel source, float amount)
{
return PorterDuffFunctions.Out(background, source, amount);
}
/// <inheritdoc />
public override void Blend(Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount)
{
Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length));
Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length));
Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length));
using (Buffer<Vector4> buffer = new Buffer<Vector4>(destination.Length * 3))
{
Span<Vector4> destinationSpan = buffer.Slice(0, destination.Length);
Span<Vector4> backgroundSpan = buffer.Slice(destination.Length, destination.Length);
Span<Vector4> sourceSpan = buffer.Slice(destination.Length * 2, destination.Length);
PixelOperations<TPixel>.Instance.ToVector4(background, backgroundSpan, destination.Length);
PixelOperations<TPixel>.Instance.ToVector4(source, sourceSpan, destination.Length);
for (int i = 0; i < destination.Length; i++)
{
destinationSpan[i] = PorterDuffFunctions.Out(backgroundSpan[i], sourceSpan[i], amount[i]);
}
PixelOperations<TPixel>.Instance.PackFromVector4(destinationSpan, destination, destination.Length);
}
}
}
internal class Dest : PixelBlender<TPixel>
{
/// <summary>
/// Gets the static instance of this blender.
/// </summary>
public static Dest Instance { get; } = new Dest();
/// <inheritdoc />
public override TPixel Blend(TPixel background, TPixel source, float amount)
{
return PorterDuffFunctions.Dest(background, source, amount);
}
/// <inheritdoc />
public override void Blend(Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount)
{
Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length));
Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length));
Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length));
using (Buffer<Vector4> buffer = new Buffer<Vector4>(destination.Length * 3))
{
Span<Vector4> destinationSpan = buffer.Slice(0, destination.Length);
Span<Vector4> backgroundSpan = buffer.Slice(destination.Length, destination.Length);
Span<Vector4> sourceSpan = buffer.Slice(destination.Length * 2, destination.Length);
PixelOperations<TPixel>.Instance.ToVector4(background, backgroundSpan, destination.Length);
PixelOperations<TPixel>.Instance.ToVector4(source, sourceSpan, destination.Length);
for (int i = 0; i < destination.Length; i++)
{
destinationSpan[i] = PorterDuffFunctions.Dest(backgroundSpan[i], sourceSpan[i], amount[i]);
}
PixelOperations<TPixel>.Instance.PackFromVector4(destinationSpan, destination, destination.Length);
}
}
}
internal class DestAtop : PixelBlender<TPixel>
{
/// <summary>
/// Gets the static instance of this blender.
/// </summary>
public static DestAtop Instance { get; } = new DestAtop();
/// <inheritdoc />
public override TPixel Blend(TPixel background, TPixel source, float amount)
{
return PorterDuffFunctions.DestAtop(background, source, amount);
}
/// <inheritdoc />
public override void Blend(Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount)
{
Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length));
Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length));
Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length));
using (Buffer<Vector4> buffer = new Buffer<Vector4>(destination.Length * 3))
{
Span<Vector4> destinationSpan = buffer.Slice(0, destination.Length);
Span<Vector4> backgroundSpan = buffer.Slice(destination.Length, destination.Length);
Span<Vector4> sourceSpan = buffer.Slice(destination.Length * 2, destination.Length);
PixelOperations<TPixel>.Instance.ToVector4(background, backgroundSpan, destination.Length);
PixelOperations<TPixel>.Instance.ToVector4(source, sourceSpan, destination.Length);
for (int i = 0; i < destination.Length; i++)
{
destinationSpan[i] = PorterDuffFunctions.DestAtop(backgroundSpan[i], sourceSpan[i], amount[i]);
}
PixelOperations<TPixel>.Instance.PackFromVector4(destinationSpan, destination, destination.Length);
}
}
}
internal class DestOver : PixelBlender<TPixel>
{
/// <summary>
/// Gets the static instance of this blender.
/// </summary>
public static DestOver Instance { get; } = new DestOver();
/// <inheritdoc />
public override TPixel Blend(TPixel background, TPixel source, float amount)
{
return PorterDuffFunctions.DestOver(background, source, amount);
}
/// <inheritdoc />
public override void Blend(Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount)
{
Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length));
Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length));
Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length));
using (Buffer<Vector4> buffer = new Buffer<Vector4>(destination.Length * 3))
{
Span<Vector4> destinationSpan = buffer.Slice(0, destination.Length);
Span<Vector4> backgroundSpan = buffer.Slice(destination.Length, destination.Length);
Span<Vector4> sourceSpan = buffer.Slice(destination.Length * 2, destination.Length);
PixelOperations<TPixel>.Instance.ToVector4(background, backgroundSpan, destination.Length);
PixelOperations<TPixel>.Instance.ToVector4(source, sourceSpan, destination.Length);
for (int i = 0; i < destination.Length; i++)
{
destinationSpan[i] = PorterDuffFunctions.DestOver(backgroundSpan[i], sourceSpan[i], amount[i]);
}
PixelOperations<TPixel>.Instance.PackFromVector4(destinationSpan, destination, destination.Length);
}
}
}
internal class DestIn : PixelBlender<TPixel>
{
/// <summary>
/// Gets the static instance of this blender.
/// </summary>
public static DestIn Instance { get; } = new DestIn();
/// <inheritdoc />
public override TPixel Blend(TPixel background, TPixel source, float amount)
{
return PorterDuffFunctions.DestIn(background, source, amount);
}
/// <inheritdoc />
public override void Blend(Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount)
{
Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length));
Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length));
Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length));
using (Buffer<Vector4> buffer = new Buffer<Vector4>(destination.Length * 3))
{
Span<Vector4> destinationSpan = buffer.Slice(0, destination.Length);
Span<Vector4> backgroundSpan = buffer.Slice(destination.Length, destination.Length);
Span<Vector4> sourceSpan = buffer.Slice(destination.Length * 2, destination.Length);
PixelOperations<TPixel>.Instance.ToVector4(background, backgroundSpan, destination.Length);
PixelOperations<TPixel>.Instance.ToVector4(source, sourceSpan, destination.Length);
for (int i = 0; i < destination.Length; i++)
{
destinationSpan[i] = PorterDuffFunctions.DestIn(backgroundSpan[i], sourceSpan[i], amount[i]);
}
PixelOperations<TPixel>.Instance.PackFromVector4(destinationSpan, destination, destination.Length);
}
}
}
internal class DestOut : PixelBlender<TPixel>
{
/// <summary>
/// Gets the static instance of this blender.
/// </summary>
public static DestOut Instance { get; } = new DestOut();
/// <inheritdoc />
public override TPixel Blend(TPixel background, TPixel source, float amount)
{
return PorterDuffFunctions.DestOut(background, source, amount);
}
/// <inheritdoc />
public override void Blend(Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount)
{
Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length));
Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length));
Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length));
using (Buffer<Vector4> buffer = new Buffer<Vector4>(destination.Length * 3))
{
Span<Vector4> destinationSpan = buffer.Slice(0, destination.Length);
Span<Vector4> backgroundSpan = buffer.Slice(destination.Length, destination.Length);
Span<Vector4> sourceSpan = buffer.Slice(destination.Length * 2, destination.Length);
PixelOperations<TPixel>.Instance.ToVector4(background, backgroundSpan, destination.Length);
PixelOperations<TPixel>.Instance.ToVector4(source, sourceSpan, destination.Length);
for (int i = 0; i < destination.Length; i++)
{
destinationSpan[i] = PorterDuffFunctions.DestOut(backgroundSpan[i], sourceSpan[i], amount[i]);
}
PixelOperations<TPixel>.Instance.PackFromVector4(destinationSpan, destination, destination.Length);
}
}
}
internal class Clear : PixelBlender<TPixel>
{
/// <summary>
/// Gets the static instance of this blender.
/// </summary>
public static Clear Instance { get; } = new Clear();
/// <inheritdoc />
public override TPixel Blend(TPixel background, TPixel source, float amount)
{
return PorterDuffFunctions.Clear(background, source, amount);
}
/// <inheritdoc />
public override void Blend(Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount)
{
Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length));
Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length));
Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length));
using (Buffer<Vector4> buffer = new Buffer<Vector4>(destination.Length * 3))
{
Span<Vector4> destinationSpan = buffer.Slice(0, destination.Length);
Span<Vector4> backgroundSpan = buffer.Slice(destination.Length, destination.Length);
Span<Vector4> sourceSpan = buffer.Slice(destination.Length * 2, destination.Length);
PixelOperations<TPixel>.Instance.ToVector4(background, backgroundSpan, destination.Length);
PixelOperations<TPixel>.Instance.ToVector4(source, sourceSpan, destination.Length);
for (int i = 0; i < destination.Length; i++)
{
destinationSpan[i] = PorterDuffFunctions.Clear(backgroundSpan[i], sourceSpan[i], amount[i]);
}
PixelOperations<TPixel>.Instance.PackFromVector4(destinationSpan, destination, destination.Length);
}
}
}
internal class Xor : PixelBlender<TPixel>
{
/// <summary>
/// Gets the static instance of this blender.
/// </summary>
public static Xor Instance { get; } = new Xor();
/// <inheritdoc />
public override TPixel Blend(TPixel background, TPixel source, float amount)
{
return PorterDuffFunctions.Xor(background, source, amount);
}
/// <inheritdoc />
public override void Blend(Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount)
{
Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length));
Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length));
Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length));
using (Buffer<Vector4> buffer = new Buffer<Vector4>(destination.Length * 3))
{
Span<Vector4> destinationSpan = buffer.Slice(0, destination.Length);
Span<Vector4> backgroundSpan = buffer.Slice(destination.Length, destination.Length);
Span<Vector4> sourceSpan = buffer.Slice(destination.Length * 2, destination.Length);
PixelOperations<TPixel>.Instance.ToVector4(background, backgroundSpan, destination.Length);
PixelOperations<TPixel>.Instance.ToVector4(source, sourceSpan, destination.Length);
for (int i = 0; i < destination.Length; i++)
{
destinationSpan[i] = PorterDuffFunctions.Xor(backgroundSpan[i], sourceSpan[i], amount[i]);
}
PixelOperations<TPixel>.Instance.PackFromVector4(destinationSpan, destination, destination.Length);
}
}
}
}
}

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

@ -0,0 +1,118 @@
<#
// <copyright file="DefaultPixelBlenders.Generated.tt" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
#>
<#@ template debug="false" hostspecific="false" language="C#" #>
<#@ assembly name="System.Core" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Text" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ output extension=".cs" #>
// <autogenerated />
// <copyright file="PorterDuffFunctions.Generated.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp.PixelFormats.PixelBlenders
{
using System;
using System.Numerics;
using ImageSharp.Memory;
/// <summary>
/// Collection of Porter Duff alpha blending functions applying different composition models.
/// </summary>
/// <remarks>
/// These functions are designed to be a general solution for all color cases,
/// that is, they take in account the alpha value of both the backdrop
/// and source, and there's no need to alpha-premultiply neither the backdrop
/// nor the source.
/// Note there are faster functions for when the backdrop color is known
/// to be opaque
/// </remarks>
internal static class DefaultPixelBlenders<TPixel>
where TPixel : struct, IPixel<TPixel>
{
<#
string[] blenders = new []{
"Normal",
"Multiply",
"Add",
"Substract",
"Screen",
"Darken",
"Lighten",
"Overlay",
"HardLight",
"Src" ,
"Atop" ,
"Over" ,
"In" ,
"Out" ,
"Dest" ,
"DestAtop" ,
"DestOver" ,
"DestIn" ,
"DestOut" ,
"Clear" ,
"Xor" ,
};
foreach(var blender in blenders) {
#>
internal class <#=blender#> : PixelBlender<TPixel>
{
/// <summary>
/// Gets the static instance of this blender.
/// </summary>
public static <#=blender#> Instance { get; } = new <#=blender#>();
/// <inheritdoc />
public override TPixel Blend(TPixel background, TPixel source, float amount)
{
return PorterDuffFunctions.<#=blender#>(background, source, amount);
}
/// <inheritdoc />
public override void Blend(Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount)
{
Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length));
Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length));
Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length));
using (Buffer<Vector4> buffer = new Buffer<Vector4>(destination.Length * 3))
{
Span<Vector4> destinationSpan = buffer.Slice(0, destination.Length);
Span<Vector4> backgroundSpan = buffer.Slice(destination.Length, destination.Length);
Span<Vector4> sourceSpan = buffer.Slice(destination.Length * 2, destination.Length);
PixelOperations<TPixel>.Instance.ToVector4(background, backgroundSpan, destination.Length);
PixelOperations<TPixel>.Instance.ToVector4(source, sourceSpan, destination.Length);
for (int i = 0; i < destination.Length; i++)
{
destinationSpan[i] = PorterDuffFunctions.<#=blender#>(backgroundSpan[i], sourceSpan[i], amount[i]);
}
PixelOperations<TPixel>.Instance.PackFromVector4(destinationSpan, destination, destination.Length);
}
}
}
<#
}
#>
}
}

57
src/ImageSharp/PixelFormats/PixelBlenders/DefaultScreenPixelBlender{TPixel}.cs

@ -1,57 +0,0 @@
// <copyright file="DefaultScreenPixelBlender{TPixel}.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp.PixelFormats.PixelBlenders
{
using System;
using System.Numerics;
using ImageSharp.Memory;
using ImageSharp.PixelFormats;
/// <summary>
/// Applies an "Screen" blending to pixels.
/// </summary>
/// <typeparam name="TPixel">The type of the pixel</typeparam>
internal class DefaultScreenPixelBlender<TPixel> : PixelBlender<TPixel>
where TPixel : struct, IPixel<TPixel>
{
/// <summary>
/// Gets the static instance of this blender.
/// </summary>
public static DefaultScreenPixelBlender<TPixel> Instance { get; } = new DefaultScreenPixelBlender<TPixel>();
/// <inheritdoc />
public override TPixel Blend(TPixel background, TPixel source, float amount)
{
return PorterDuffFunctions<TPixel>.ScreenFunction(background, source, amount);
}
/// <inheritdoc />
public override void Blend(Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount)
{
Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length));
Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length));
Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length));
using (Buffer<Vector4> buffer = new Buffer<Vector4>(destination.Length * 3))
{
Span<Vector4> destinationSpan = buffer.Slice(0, destination.Length);
Span<Vector4> backgroundSpan = buffer.Slice(destination.Length, destination.Length);
Span<Vector4> sourceSpan = buffer.Slice(destination.Length * 2, destination.Length);
PixelOperations<TPixel>.Instance.ToVector4(background, backgroundSpan, destination.Length);
PixelOperations<TPixel>.Instance.ToVector4(source, sourceSpan, destination.Length);
for (int i = 0; i < destination.Length; i++)
{
destinationSpan[i] = PorterDuffFunctions.ScreenFunction(backgroundSpan[i], sourceSpan[i], amount[i]);
}
PixelOperations<TPixel>.Instance.PackFromVector4(destinationSpan, destination, destination.Length);
}
}
}
}

57
src/ImageSharp/PixelFormats/PixelBlenders/DefaultSubstractPixelBlender{TPixel}.cs

@ -1,57 +0,0 @@
// <copyright file="DefaultSubstractPixelBlender{TPixel}.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp.PixelFormats.PixelBlenders
{
using System;
using System.Numerics;
using ImageSharp.Memory;
using ImageSharp.PixelFormats;
/// <summary>
/// Applies an "Subtract" blending to pixels.
/// </summary>
/// <typeparam name="TPixel">The type of the pixel</typeparam>
internal class DefaultSubstractPixelBlender<TPixel> : PixelBlender<TPixel>
where TPixel : struct, IPixel<TPixel>
{
/// <summary>
/// Gets the static instance of this blender.
/// </summary>
public static DefaultSubstractPixelBlender<TPixel> Instance { get; } = new DefaultSubstractPixelBlender<TPixel>();
/// <inheritdoc />
public override TPixel Blend(TPixel background, TPixel source, float amount)
{
return PorterDuffFunctions<TPixel>.SubstractFunction(background, source, amount);
}
/// <inheritdoc />
public override void Blend(Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount)
{
Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length));
Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length));
Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length));
using (Buffer<Vector4> buffer = new Buffer<Vector4>(destination.Length * 3))
{
Span<Vector4> destinationSpan = buffer.Slice(0, destination.Length);
Span<Vector4> backgroundSpan = buffer.Slice(destination.Length, destination.Length);
Span<Vector4> sourceSpan = buffer.Slice(destination.Length * 2, destination.Length);
PixelOperations<TPixel>.Instance.ToVector4(background, backgroundSpan, destination.Length);
PixelOperations<TPixel>.Instance.ToVector4(source, sourceSpan, destination.Length);
for (int i = 0; i < destination.Length; i++)
{
destinationSpan[i] = PorterDuffFunctions.SubstractFunction(backgroundSpan[i], sourceSpan[i], amount[i]);
}
PixelOperations<TPixel>.Instance.PackFromVector4(destinationSpan, destination, destination.Length);
}
}
}
}

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

@ -0,0 +1,314 @@
// <autogenerated />
// <copyright file="PorterDuffFunctions.Generated.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp.PixelFormats.PixelBlenders
{
using System.Numerics;
using System.Runtime.CompilerServices;
internal static partial class PorterDuffFunctions
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4 Src(Vector4 backdrop, Vector4 source, float amount)
{
source.W *= amount;
if (source.W == 0)
{
return Vector4.Zero;
}
return Compose(Vector4.Zero, source, source);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4 Atop(Vector4 backdrop, Vector4 source, float amount)
{
return backdrop;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4 Over(Vector4 backdrop, Vector4 source, float amount)
{
source.W *= amount;
if (source.W == 0)
{
return backdrop;
}
return Compose(backdrop, source, source);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4 In(Vector4 backdrop, Vector4 source, float amount)
{
return Vector4.Zero;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4 Out(Vector4 backdrop, Vector4 source, float amount)
{
source.W *= amount;
if (source.W == 0)
{
return Vector4.Zero;
}
return Compose(Vector4.Zero, source, Vector4.Zero);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4 Dest(Vector4 backdrop, Vector4 source, float amount)
{
return backdrop;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4 DestAtop(Vector4 backdrop, Vector4 source, float amount)
{
source.W *= amount;
if (source.W == 0)
{
return Vector4.Zero;
}
return Compose(Vector4.Zero, source, backdrop);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4 DestOver(Vector4 backdrop, Vector4 source, float amount)
{
source.W *= amount;
if (source.W == 0)
{
return backdrop;
}
return Compose(backdrop, source, backdrop);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4 DestIn(Vector4 backdrop, Vector4 source, float amount)
{
return Vector4.Zero;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4 DestOut(Vector4 backdrop, Vector4 source, float amount)
{
return backdrop;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4 Clear(Vector4 backdrop, Vector4 source, float amount)
{
return Vector4.Zero;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4 Xor(Vector4 backdrop, Vector4 source, float amount)
{
source.W *= amount;
if (source.W == 0)
{
return backdrop;
}
return Compose(backdrop, source, Vector4.Zero);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static TPixel Normal<TPixel>(TPixel backdrop, TPixel source, float amount)
where TPixel : struct, IPixel<TPixel>
{
TPixel dest = default(TPixel);
dest.PackFromVector4(Normal(backdrop.ToVector4(), source.ToVector4(), amount));
return dest;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static TPixel Multiply<TPixel>(TPixel backdrop, TPixel source, float amount)
where TPixel : struct, IPixel<TPixel>
{
TPixel dest = default(TPixel);
dest.PackFromVector4(Multiply(backdrop.ToVector4(), source.ToVector4(), amount));
return dest;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static TPixel Add<TPixel>(TPixel backdrop, TPixel source, float amount)
where TPixel : struct, IPixel<TPixel>
{
TPixel dest = default(TPixel);
dest.PackFromVector4(Add(backdrop.ToVector4(), source.ToVector4(), amount));
return dest;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static TPixel Substract<TPixel>(TPixel backdrop, TPixel source, float amount)
where TPixel : struct, IPixel<TPixel>
{
TPixel dest = default(TPixel);
dest.PackFromVector4(Substract(backdrop.ToVector4(), source.ToVector4(), amount));
return dest;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static TPixel Screen<TPixel>(TPixel backdrop, TPixel source, float amount)
where TPixel : struct, IPixel<TPixel>
{
TPixel dest = default(TPixel);
dest.PackFromVector4(Screen(backdrop.ToVector4(), source.ToVector4(), amount));
return dest;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static TPixel Darken<TPixel>(TPixel backdrop, TPixel source, float amount)
where TPixel : struct, IPixel<TPixel>
{
TPixel dest = default(TPixel);
dest.PackFromVector4(Darken(backdrop.ToVector4(), source.ToVector4(), amount));
return dest;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static TPixel Lighten<TPixel>(TPixel backdrop, TPixel source, float amount)
where TPixel : struct, IPixel<TPixel>
{
TPixel dest = default(TPixel);
dest.PackFromVector4(Lighten(backdrop.ToVector4(), source.ToVector4(), amount));
return dest;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static TPixel Overlay<TPixel>(TPixel backdrop, TPixel source, float amount)
where TPixel : struct, IPixel<TPixel>
{
TPixel dest = default(TPixel);
dest.PackFromVector4(Overlay(backdrop.ToVector4(), source.ToVector4(), amount));
return dest;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static TPixel HardLight<TPixel>(TPixel backdrop, TPixel source, float amount)
where TPixel : struct, IPixel<TPixel>
{
TPixel dest = default(TPixel);
dest.PackFromVector4(HardLight(backdrop.ToVector4(), source.ToVector4(), amount));
return dest;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static TPixel Src<TPixel>(TPixel backdrop, TPixel source, float amount)
where TPixel : struct, IPixel<TPixel>
{
TPixel dest = default(TPixel);
dest.PackFromVector4(Src(backdrop.ToVector4(), source.ToVector4(), amount));
return dest;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static TPixel Atop<TPixel>(TPixel backdrop, TPixel source, float amount)
where TPixel : struct, IPixel<TPixel>
{
TPixel dest = default(TPixel);
dest.PackFromVector4(Atop(backdrop.ToVector4(), source.ToVector4(), amount));
return dest;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static TPixel Over<TPixel>(TPixel backdrop, TPixel source, float amount)
where TPixel : struct, IPixel<TPixel>
{
TPixel dest = default(TPixel);
dest.PackFromVector4(Over(backdrop.ToVector4(), source.ToVector4(), amount));
return dest;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static TPixel In<TPixel>(TPixel backdrop, TPixel source, float amount)
where TPixel : struct, IPixel<TPixel>
{
TPixel dest = default(TPixel);
dest.PackFromVector4(In(backdrop.ToVector4(), source.ToVector4(), amount));
return dest;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static TPixel Out<TPixel>(TPixel backdrop, TPixel source, float amount)
where TPixel : struct, IPixel<TPixel>
{
TPixel dest = default(TPixel);
dest.PackFromVector4(Out(backdrop.ToVector4(), source.ToVector4(), amount));
return dest;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static TPixel Dest<TPixel>(TPixel backdrop, TPixel source, float amount)
where TPixel : struct, IPixel<TPixel>
{
TPixel dest = default(TPixel);
dest.PackFromVector4(Dest(backdrop.ToVector4(), source.ToVector4(), amount));
return dest;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static TPixel DestAtop<TPixel>(TPixel backdrop, TPixel source, float amount)
where TPixel : struct, IPixel<TPixel>
{
TPixel dest = default(TPixel);
dest.PackFromVector4(DestAtop(backdrop.ToVector4(), source.ToVector4(), amount));
return dest;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static TPixel DestOver<TPixel>(TPixel backdrop, TPixel source, float amount)
where TPixel : struct, IPixel<TPixel>
{
TPixel dest = default(TPixel);
dest.PackFromVector4(DestOver(backdrop.ToVector4(), source.ToVector4(), amount));
return dest;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static TPixel DestIn<TPixel>(TPixel backdrop, TPixel source, float amount)
where TPixel : struct, IPixel<TPixel>
{
TPixel dest = default(TPixel);
dest.PackFromVector4(DestIn(backdrop.ToVector4(), source.ToVector4(), amount));
return dest;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static TPixel DestOut<TPixel>(TPixel backdrop, TPixel source, float amount)
where TPixel : struct, IPixel<TPixel>
{
TPixel dest = default(TPixel);
dest.PackFromVector4(DestOut(backdrop.ToVector4(), source.ToVector4(), amount));
return dest;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static TPixel Clear<TPixel>(TPixel backdrop, TPixel source, float amount)
where TPixel : struct, IPixel<TPixel>
{
TPixel dest = default(TPixel);
dest.PackFromVector4(Clear(backdrop.ToVector4(), source.ToVector4(), amount));
return dest;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static TPixel Xor<TPixel>(TPixel backdrop, TPixel source, float amount)
where TPixel : struct, IPixel<TPixel>
{
TPixel dest = default(TPixel);
dest.PackFromVector4(Xor(backdrop.ToVector4(), source.ToVector4(), amount));
return dest;
}
}
}

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

@ -0,0 +1,126 @@
<#
// <copyright file="PorterDuffFunctions.Generated.tt" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
#>
<#@ template debug="false" hostspecific="false" language="C#" #>
<#@ assembly name="System.Core" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Text" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ output extension=".cs" #>
// <autogenerated />
// <copyright file="PorterDuffFunctions.Generated.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp.PixelFormats.PixelBlenders
{
using System.Numerics;
using System.Runtime.CompilerServices;
internal static partial class PorterDuffFunctions
{
<#
void GeneratePixelBlender (string blender)
{
#>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static TPixel <#=blender#><TPixel>(TPixel backdrop, TPixel source, float amount)
where TPixel : struct, IPixel<TPixel>
{
TPixel dest = default(TPixel);
dest.PackFromVector4(<#=blender#>(backdrop.ToVector4(), source.ToVector4(), amount));
return dest;
}
<#
}
void GenerateVectorCompositor(string name, string sourceVar, string destVar, string blendVar)
{
if(sourceVar == "0") sourceVar= "Vector4.Zero";
if(destVar == "0") destVar= "Vector4.Zero";
if(blendVar == "0") blendVar= "Vector4.Zero";
if(sourceVar == "s") sourceVar= "source";
if(destVar == "s") destVar= "source";
if(blendVar == "s") blendVar= "source";
if(sourceVar == "d") sourceVar= "backdrop";
if(destVar == "d") destVar= "backdrop";
if(blendVar == "d") blendVar= "backdrop";
#>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4 <#=name#>(Vector4 backdrop, Vector4 source, float amount)
{
<#
if(sourceVar == "Vector4.Zero")
{
#>
return <#=destVar#>;
<#
}else{
#>
<#=sourceVar#>.W *= amount;
if (<#=sourceVar#>.W == 0)
{
return <#=destVar#>;
}
return Compose(<#=destVar#>, <#=sourceVar#>, <#=blendVar#>);
<#
}
#>
}
<#
}
GenerateVectorCompositor("Src", "s", "0", "s");
GenerateVectorCompositor("Atop", "0", "d", "s");
GenerateVectorCompositor("Over", "s", "d", "s");
GenerateVectorCompositor("In", "0", "0", "s");
GenerateVectorCompositor("Out", "s", "0", "0");
GenerateVectorCompositor("Dest", "0", "d", "d");
GenerateVectorCompositor("DestAtop", "s", "0", "d");
GenerateVectorCompositor("DestOver", "s", "d", "d");
GenerateVectorCompositor("DestIn", "0", "0", "d");
GenerateVectorCompositor("DestOut", "0", "d", "0");
GenerateVectorCompositor("Clear", "0", "0", "0");
GenerateVectorCompositor("Xor", "s", "d", "0");
GeneratePixelBlender("Normal");
GeneratePixelBlender("Multiply");
GeneratePixelBlender("Add");
GeneratePixelBlender("Substract");
GeneratePixelBlender("Screen");
GeneratePixelBlender("Darken");
GeneratePixelBlender("Lighten");
GeneratePixelBlender("Overlay");
GeneratePixelBlender("HardLight");
GeneratePixelBlender("Src");
GeneratePixelBlender("Atop");
GeneratePixelBlender("Over");
GeneratePixelBlender("In");
GeneratePixelBlender("Out");
GeneratePixelBlender("Dest");
GeneratePixelBlender("DestAtop");
GeneratePixelBlender("DestOver");
GeneratePixelBlender("DestIn");
GeneratePixelBlender("DestOut");
GeneratePixelBlender("Clear");
GeneratePixelBlender("Xor");
#>
}
}

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

@ -29,7 +29,7 @@ namespace ImageSharp.PixelFormats.PixelBlenders
/// <param name="opacity">Opacity applied to Source Alpha</param>
/// <returns>Output color</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4 NormalBlendFunction(Vector4 backdrop, Vector4 source, float opacity)
public static Vector4 Normal(Vector4 backdrop, Vector4 source, float opacity)
{
source.W *= opacity;
if (source.W == 0)
@ -48,7 +48,7 @@ namespace ImageSharp.PixelFormats.PixelBlenders
/// <param name="opacity">Opacity applied to Source Alpha</param>
/// <returns>Output color</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4 MultiplyFunction(Vector4 backdrop, Vector4 source, float opacity)
public static Vector4 Multiply(Vector4 backdrop, Vector4 source, float opacity)
{
source.W *= opacity;
if (source.W == 0)
@ -67,7 +67,7 @@ namespace ImageSharp.PixelFormats.PixelBlenders
/// <param name="opacity">Opacity applied to Source Alpha</param>
/// <returns>Output color</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4 AddFunction(Vector4 backdrop, Vector4 source, float opacity)
public static Vector4 Add(Vector4 backdrop, Vector4 source, float opacity)
{
source.W *= opacity;
if (source.W == 0)
@ -86,7 +86,7 @@ namespace ImageSharp.PixelFormats.PixelBlenders
/// <param name="opacity">Opacity applied to Source Alpha</param>
/// <returns>Output color</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4 SubstractFunction(Vector4 backdrop, Vector4 source, float opacity)
public static Vector4 Substract(Vector4 backdrop, Vector4 source, float opacity)
{
source.W *= opacity;
if (source.W == 0)
@ -105,7 +105,7 @@ namespace ImageSharp.PixelFormats.PixelBlenders
/// <param name="opacity">Opacity applied to Source Alpha</param>
/// <returns>Output color</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4 ScreenFunction(Vector4 backdrop, Vector4 source, float opacity)
public static Vector4 Screen(Vector4 backdrop, Vector4 source, float opacity)
{
source.W *= opacity;
if (source.W == 0)
@ -124,7 +124,7 @@ namespace ImageSharp.PixelFormats.PixelBlenders
/// <param name="opacity">Opacity applied to Source Alpha</param>
/// <returns>Output color</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4 DarkenFunction(Vector4 backdrop, Vector4 source, float opacity)
public static Vector4 Darken(Vector4 backdrop, Vector4 source, float opacity)
{
source.W *= opacity;
if (source.W == 0)
@ -143,7 +143,7 @@ namespace ImageSharp.PixelFormats.PixelBlenders
/// <param name="opacity">Opacity applied to Source Alpha</param>
/// <returns>Output color</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4 LightenFunction(Vector4 backdrop, Vector4 source, float opacity)
public static Vector4 Lighten(Vector4 backdrop, Vector4 source, float opacity)
{
source.W *= opacity;
if (source.W == 0)
@ -162,7 +162,7 @@ namespace ImageSharp.PixelFormats.PixelBlenders
/// <param name="opacity">Opacity applied to Source Alpha</param>
/// <returns>Output color</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4 OverlayFunction(Vector4 backdrop, Vector4 source, float opacity)
public static Vector4 Overlay(Vector4 backdrop, Vector4 source, float opacity)
{
source.W *= opacity;
if (source.W == 0)
@ -185,7 +185,7 @@ namespace ImageSharp.PixelFormats.PixelBlenders
/// <param name="opacity">Opacity applied to Source Alpha</param>
/// <returns>Output color</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4 HardLightFunction(Vector4 backdrop, Vector4 source, float opacity)
public static Vector4 HardLight(Vector4 backdrop, Vector4 source, float opacity)
{
source.W *= opacity;
if (source.W == 0)
@ -222,7 +222,7 @@ namespace ImageSharp.PixelFormats.PixelBlenders
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static Vector4 Compose(Vector4 backdrop, Vector4 source, Vector4 xform)
{
DebugGuard.MustBeGreaterThan(source.W, 0, nameof(source.W));
//DebugGuard.MustBeGreaterThan(source.W, 0, nameof(source.W));
// calculate weights
float xw = backdrop.W * source.W;

151
src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions{TPixel}.cs

@ -1,151 +0,0 @@
// <copyright file="PorterDuffFunctions.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp.PixelFormats.PixelBlenders
{
using System.Numerics;
using System.Runtime.CompilerServices;
/// <summary>
/// Collection of Porter Duff alpha blending functions
/// </summary>
/// <typeparam name="TPixel">Pixel Format</typeparam>
/// <remarks>
/// These functions are designed to be a general solution for all color cases,
/// that is, they take in account the alpha value of both the backdrop
/// and source, and there's no need to alpha-premultiply neither the backdrop
/// nor the source.
/// Note there are faster functions for when the backdrop color is known
/// to be opaque
/// </remarks>
internal static class PorterDuffFunctions<TPixel>
where TPixel : IPixel
{
/// <summary>
/// Source over backdrop
/// </summary>
/// <param name="backdrop">Backgrop 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 TPixel NormalBlendFunction(TPixel backdrop, TPixel source, float opacity)
{
return ToPixel(PorterDuffFunctions.NormalBlendFunction(backdrop.ToVector4(), source.ToVector4(), opacity));
}
/// <summary>
/// Source multiplied by backdrop
/// </summary>
/// <param name="backdrop">Backgrop 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 TPixel MultiplyFunction(TPixel backdrop, TPixel source, float opacity)
{
return ToPixel(PorterDuffFunctions.MultiplyFunction(backdrop.ToVector4(), source.ToVector4(), opacity));
}
/// <summary>
/// Source added to backdrop
/// </summary>
/// <param name="backdrop">Backgrop 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 TPixel AddFunction(TPixel backdrop, TPixel source, float opacity)
{
return ToPixel(PorterDuffFunctions.AddFunction(backdrop.ToVector4(), source.ToVector4(), opacity));
}
/// <summary>
/// Source substracted from backdrop
/// </summary>
/// <param name="backdrop">Backgrop 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 TPixel SubstractFunction(TPixel backdrop, TPixel source, float opacity)
{
return ToPixel(PorterDuffFunctions.SubstractFunction(backdrop.ToVector4(), source.ToVector4(), opacity));
}
/// <summary>
/// Complement of source multiplied by the complement of backdrop
/// </summary>
/// <param name="backdrop">Backgrop 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 TPixel ScreenFunction(TPixel backdrop, TPixel source, float opacity)
{
return ToPixel(PorterDuffFunctions.ScreenFunction(backdrop.ToVector4(), source.ToVector4(), opacity));
}
/// <summary>
/// Per element, chooses the smallest value of source and backdrop
/// </summary>
/// <param name="backdrop">Backgrop 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 TPixel DarkenFunction(TPixel backdrop, TPixel source, float opacity)
{
return ToPixel(PorterDuffFunctions.DarkenFunction(backdrop.ToVector4(), source.ToVector4(), opacity));
}
/// <summary>
/// Per element, chooses the largest value of source and backdrop
/// </summary>
/// <param name="backdrop">Backgrop 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 TPixel LightenFunction(TPixel backdrop, TPixel source, float opacity)
{
return ToPixel(PorterDuffFunctions.LightenFunction(backdrop.ToVector4(), source.ToVector4(), opacity));
}
/// <summary>
/// Overlays source over backdrop
/// </summary>
/// <param name="backdrop">Backgrop 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 TPixel OverlayFunction(TPixel backdrop, TPixel source, float opacity)
{
return ToPixel(PorterDuffFunctions.OverlayFunction(backdrop.ToVector4(), source.ToVector4(), opacity));
}
/// <summary>
/// Hard light effect
/// </summary>
/// <param name="backdrop">Backgrop 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 TPixel HardLightFunction(TPixel backdrop, TPixel source, float opacity)
{
return ToPixel(PorterDuffFunctions.HardLightFunction(backdrop.ToVector4(), source.ToVector4(), opacity));
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static TPixel ToPixel(Vector4 vector)
{
TPixel p = default(TPixel);
p.PackFromVector4(vector);
return p;
}
}
}

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

@ -22,25 +22,30 @@ namespace ImageSharp.PixelFormats
{
switch (mode)
{
case PixelBlenderMode.Multiply:
return DefaultMultiplyPixelBlender<TPixel>.Instance;
case PixelBlenderMode.Add:
return DefaultAddPixelBlender<TPixel>.Instance;
case PixelBlenderMode.Substract:
return DefaultSubstractPixelBlender<TPixel>.Instance;
case PixelBlenderMode.Screen:
return DefaultScreenPixelBlender<TPixel>.Instance;
case PixelBlenderMode.Darken:
return DefaultDarkenPixelBlender<TPixel>.Instance;
case PixelBlenderMode.Lighten:
return DefaultLightenPixelBlender<TPixel>.Instance;
case PixelBlenderMode.Overlay:
return DefaultOverlayPixelBlender<TPixel>.Instance;
case PixelBlenderMode.HardLight:
return DefaultHardLightPixelBlender<TPixel>.Instance;
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.Screen: return DefaultPixelBlenders<TPixel>.Screen.Instance;
case PixelBlenderMode.Darken: return DefaultPixelBlenders<TPixel>.Darken.Instance;
case PixelBlenderMode.Lighten: return DefaultPixelBlenders<TPixel>.Lighten.Instance;
case PixelBlenderMode.Overlay: return DefaultPixelBlenders<TPixel>.Overlay.Instance;
case PixelBlenderMode.HardLight: return DefaultPixelBlenders<TPixel>.HardLight.Instance;
case PixelBlenderMode.Src: return DefaultPixelBlenders<TPixel>.Src.Instance;
case PixelBlenderMode.Atop: return DefaultPixelBlenders<TPixel>.Atop.Instance;
case PixelBlenderMode.Over: return DefaultPixelBlenders<TPixel>.Over.Instance;
case PixelBlenderMode.In: return DefaultPixelBlenders<TPixel>.In.Instance;
case PixelBlenderMode.Out: return DefaultPixelBlenders<TPixel>.Out.Instance;
case PixelBlenderMode.Dest: return DefaultPixelBlenders<TPixel>.Dest.Instance;
case PixelBlenderMode.DestAtop: return DefaultPixelBlenders<TPixel>.DestAtop.Instance;
case PixelBlenderMode.DestOver: return DefaultPixelBlenders<TPixel>.DestOver.Instance;
case PixelBlenderMode.DestIn: return DefaultPixelBlenders<TPixel>.DestIn.Instance;
case PixelBlenderMode.DestOut: return DefaultPixelBlenders<TPixel>.DestOut.Instance;
case PixelBlenderMode.Clear: return DefaultPixelBlenders<TPixel>.Clear.Instance;
case PixelBlenderMode.Xor: return DefaultPixelBlenders<TPixel>.Xor.Instance;
case PixelBlenderMode.Normal:
default:
return DefaultNormalPixelBlender<TPixel>.Instance;
return DefaultPixelBlenders<TPixel>.Normal.Instance;
}
}
}

4
tests/ImageSharp.Benchmarks/PixelBlenders/PorterDuffBulkVsPixel.cs

@ -35,7 +35,7 @@ namespace ImageSharp.Benchmarks
for (int i = 0; i < destination.Length; i++)
{
destinationSpan[i] = PorterDuffFunctions.NormalBlendFunction(backgroundSpan[i], sourceSpan[i], amount[i]);
destinationSpan[i] = PorterDuffFunctions.Normal(backgroundSpan[i], sourceSpan[i], amount[i]);
}
PixelOperations<TPixel>.Instance.PackFromVector4(destinationSpan, destination, destination.Length);
@ -50,7 +50,7 @@ namespace ImageSharp.Benchmarks
for (int i = 0; i < destination.Length; i++)
{
destination[i] = PorterDuffFunctions<TPixel>.NormalBlendFunction(destination[i], source[i], amount[i]);
destination[i] = PorterDuffFunctions.Normal(destination[i], source[i], amount[i]);
}
}

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

@ -24,7 +24,7 @@ namespace ImageSharp.Tests.PixelFormats.PixelBlenders
[MemberData(nameof(NormalBlendFunctionData))]
public void NormalBlendFunction(TestVector4 back, TestVector4 source, float amount, TestVector4 expected)
{
Vector4 actual = PorterDuffFunctions.NormalBlendFunction(back, source, amount);
Vector4 actual = PorterDuffFunctions.Normal((Vector4)back, source, amount);
Assert.Equal(expected, actual);
}
@ -43,7 +43,7 @@ namespace ImageSharp.Tests.PixelFormats.PixelBlenders
[MemberData(nameof(MultiplyFunctionData))]
public void MultiplyFunction(TestVector4 back, TestVector4 source, float amount, TestVector4 expected)
{
Vector4 actual = PorterDuffFunctions.MultiplyFunction(back, source, amount);
Vector4 actual = PorterDuffFunctions.Multiply((Vector4)back, source, amount);
VectorAssert.Equal(expected, actual, 5);
}
@ -62,7 +62,7 @@ namespace ImageSharp.Tests.PixelFormats.PixelBlenders
[MemberData(nameof(AddFunctionData))]
public void AddFunction(TestVector4 back, TestVector4 source, float amount, TestVector4 expected)
{
Vector4 actual = PorterDuffFunctions.MultiplyFunction(back, source, amount);
Vector4 actual = PorterDuffFunctions.Multiply((Vector4)back, source, amount);
VectorAssert.Equal(expected, actual, 5);
}
@ -81,7 +81,7 @@ namespace ImageSharp.Tests.PixelFormats.PixelBlenders
[MemberData(nameof(SubstractFunctionData))]
public void SubstractFunction(TestVector4 back, TestVector4 source, float amount, TestVector4 expected)
{
Vector4 actual = PorterDuffFunctions.SubstractFunction(back, source, amount);
Vector4 actual = PorterDuffFunctions.Substract((Vector4)back, source, amount);
VectorAssert.Equal(expected, actual, 5);
}
@ -100,7 +100,7 @@ namespace ImageSharp.Tests.PixelFormats.PixelBlenders
[MemberData(nameof(ScreenFunctionData))]
public void ScreenFunction(TestVector4 back, TestVector4 source, float amount, TestVector4 expected)
{
Vector4 actual = PorterDuffFunctions.ScreenFunction(back, source, amount);
Vector4 actual = PorterDuffFunctions.Screen((Vector4)back, source, amount);
VectorAssert.Equal(expected, actual, 5);
}
@ -119,7 +119,7 @@ namespace ImageSharp.Tests.PixelFormats.PixelBlenders
[MemberData(nameof(DarkenFunctionData))]
public void DarkenFunction(TestVector4 back, TestVector4 source, float amount, TestVector4 expected)
{
Vector4 actual = PorterDuffFunctions.DarkenFunction(back, source, amount);
Vector4 actual = PorterDuffFunctions.Darken((Vector4)back, source, amount);
VectorAssert.Equal(expected, actual, 5);
}
@ -138,7 +138,7 @@ namespace ImageSharp.Tests.PixelFormats.PixelBlenders
[MemberData(nameof(LightenFunctionData))]
public void LightenFunction(TestVector4 back, TestVector4 source, float amount, TestVector4 expected)
{
Vector4 actual = PorterDuffFunctions.LightenFunction(back, source, amount);
Vector4 actual = PorterDuffFunctions.Lighten((Vector4)back, source, amount);
VectorAssert.Equal(expected, actual, 5);
}
@ -157,7 +157,7 @@ namespace ImageSharp.Tests.PixelFormats.PixelBlenders
[MemberData(nameof(OverlayFunctionData))]
public void OverlayFunction(TestVector4 back, TestVector4 source, float amount, TestVector4 expected)
{
Vector4 actual = PorterDuffFunctions.OverlayFunction(back, source, amount);
Vector4 actual = PorterDuffFunctions.Overlay((Vector4)back, source, amount);
VectorAssert.Equal(expected, actual, 5);
}
@ -176,7 +176,7 @@ namespace ImageSharp.Tests.PixelFormats.PixelBlenders
[MemberData(nameof(HardLightFunctionData))]
public void HardLightFunction(TestVector4 back, TestVector4 source, float amount, TestVector4 expected)
{
Vector4 actual = PorterDuffFunctions.HardLightFunction(back, source, amount);
Vector4 actual = PorterDuffFunctions.HardLight((Vector4)back, source, amount);
VectorAssert.Equal(expected, actual, 5);
}
}

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

@ -32,7 +32,7 @@ namespace ImageSharp.Tests.PixelFormats.PixelBlenders
public void NormalBlendFunction<TPixel>(TestPixel<TPixel> back, TestPixel<TPixel> source, float amount, TestPixel<TPixel> expected)
where TPixel : struct, IPixel<TPixel>
{
TPixel actual = PorterDuffFunctions<TPixel>.NormalBlendFunction(back, source, amount);
TPixel actual = PorterDuffFunctions.Normal((TPixel)(TPixel)back, source, amount);
VectorAssert.Equal(expected, actual, 2);
}
@ -41,7 +41,7 @@ namespace ImageSharp.Tests.PixelFormats.PixelBlenders
public void NormalBlendFunction_Blender<TPixel>(TestPixel<TPixel> back, TestPixel<TPixel> source, float amount, TestPixel<TPixel> expected)
where TPixel : struct, IPixel<TPixel>
{
TPixel actual = new DefaultNormalPixelBlender<TPixel>().Blend(back, source, amount);
TPixel actual = new DefaultPixelBlenders<TPixel>.Normal().Blend(back, source, amount);
VectorAssert.Equal(expected, actual, 2);
}
@ -51,7 +51,7 @@ namespace ImageSharp.Tests.PixelFormats.PixelBlenders
where TPixel : struct, IPixel<TPixel>
{
Span<TPixel> dest = new Span<TPixel>(new TPixel[1]);
new DefaultNormalPixelBlender<TPixel>().Blend(dest, back.AsSpan(), source.AsSpan(), AsSpan(amount));
new DefaultPixelBlenders<TPixel>.Normal().Blend(dest, back.AsSpan(), source.AsSpan(), AsSpan(amount));
VectorAssert.Equal(expected, dest[0], 2);
}
@ -71,7 +71,7 @@ namespace ImageSharp.Tests.PixelFormats.PixelBlenders
public void MultiplyFunction<TPixel>(TestPixel<TPixel> back, TestPixel<TPixel> source, float amount, TestPixel<TPixel> expected)
where TPixel : struct, IPixel<TPixel>
{
TPixel actual = PorterDuffFunctions<TPixel>.MultiplyFunction(back, source, amount);
TPixel actual = PorterDuffFunctions.Multiply((TPixel)back, source, amount);
VectorAssert.Equal(expected, actual, 2);
}
@ -80,7 +80,7 @@ namespace ImageSharp.Tests.PixelFormats.PixelBlenders
public void MultiplyFunction_Blender<TPixel>(TestPixel<TPixel> back, TestPixel<TPixel> source, float amount, TestPixel<TPixel> expected)
where TPixel : struct, IPixel<TPixel>
{
TPixel actual = new DefaultMultiplyPixelBlender<TPixel>().Blend(back, source, amount);
TPixel actual = new DefaultPixelBlenders<TPixel>.Multiply().Blend(back, source, amount);
VectorAssert.Equal(expected, actual, 2);
}
@ -90,7 +90,7 @@ namespace ImageSharp.Tests.PixelFormats.PixelBlenders
where TPixel : struct, IPixel<TPixel>
{
Span<TPixel> dest = new Span<TPixel>(new TPixel[1]);
new DefaultMultiplyPixelBlender<TPixel>().Blend(dest, back.AsSpan(), source.AsSpan(), AsSpan(amount));
new DefaultPixelBlenders<TPixel>.Multiply().Blend(dest, back.AsSpan(), source.AsSpan(), AsSpan(amount));
VectorAssert.Equal(expected, dest[0], 2);
}
@ -110,7 +110,7 @@ namespace ImageSharp.Tests.PixelFormats.PixelBlenders
public void AddFunction<TPixel>(TestPixel<TPixel> back, TestPixel<TPixel> source, float amount, TestPixel<TPixel> expected)
where TPixel : struct, IPixel<TPixel>
{
TPixel actual = PorterDuffFunctions<TPixel>.AddFunction(back, source, amount);
TPixel actual = PorterDuffFunctions.Add((TPixel)back, source, amount);
VectorAssert.Equal(expected, actual, 2);
}
@ -119,7 +119,7 @@ namespace ImageSharp.Tests.PixelFormats.PixelBlenders
public void AddFunction_Blender<TPixel>(TestPixel<TPixel> back, TestPixel<TPixel> source, float amount, TestPixel<TPixel> expected)
where TPixel : struct, IPixel<TPixel>
{
TPixel actual = new DefaultAddPixelBlender<TPixel>().Blend(back, source, amount);
TPixel actual = new DefaultPixelBlenders<TPixel>.Add().Blend(back, source, amount);
VectorAssert.Equal(expected, actual, 2);
}
@ -129,7 +129,7 @@ namespace ImageSharp.Tests.PixelFormats.PixelBlenders
where TPixel : struct, IPixel<TPixel>
{
Span<TPixel> dest = new Span<TPixel>(new TPixel[1]);
new DefaultAddPixelBlender<TPixel>().Blend(dest, back.AsSpan(), source.AsSpan(), AsSpan(amount));
new DefaultPixelBlenders<TPixel>.Add().Blend(dest, back.AsSpan(), source.AsSpan(), AsSpan(amount));
VectorAssert.Equal(expected, dest[0], 2);
}
@ -149,7 +149,7 @@ namespace 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<TPixel>.SubstractFunction(back, source, amount);
TPixel actual = PorterDuffFunctions.Substract((TPixel)back, source, amount);
VectorAssert.Equal(expected, actual, 2);
}
@ -158,7 +158,7 @@ namespace 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 DefaultSubstractPixelBlender<TPixel>().Blend(back, source, amount);
TPixel actual = new DefaultPixelBlenders<TPixel>.Substract().Blend(back, source, amount);
VectorAssert.Equal(expected, actual, 2);
}
@ -168,7 +168,7 @@ namespace ImageSharp.Tests.PixelFormats.PixelBlenders
where TPixel : struct, IPixel<TPixel>
{
Span<TPixel> dest = new Span<TPixel>(new TPixel[1]);
new DefaultSubstractPixelBlender<TPixel>().Blend(dest, back.AsSpan(), source.AsSpan(), AsSpan(amount));
new DefaultPixelBlenders<TPixel>.Substract().Blend(dest, back.AsSpan(), source.AsSpan(), AsSpan(amount));
VectorAssert.Equal(expected, dest[0], 2);
}
@ -188,7 +188,7 @@ namespace ImageSharp.Tests.PixelFormats.PixelBlenders
public void ScreenFunction<TPixel>(TestPixel<TPixel> back, TestPixel<TPixel> source, float amount, TestPixel<TPixel> expected)
where TPixel : struct, IPixel<TPixel>
{
TPixel actual = PorterDuffFunctions<TPixel>.ScreenFunction(back, source, amount);
TPixel actual = PorterDuffFunctions.Screen((TPixel)back, source, amount);
VectorAssert.Equal(expected, actual, 2);
}
@ -197,7 +197,7 @@ namespace ImageSharp.Tests.PixelFormats.PixelBlenders
public void ScreenFunction_Blender<TPixel>(TestPixel<TPixel> back, TestPixel<TPixel> source, float amount, TestPixel<TPixel> expected)
where TPixel : struct, IPixel<TPixel>
{
TPixel actual = new DefaultScreenPixelBlender<TPixel>().Blend(back, source, amount);
TPixel actual = new DefaultPixelBlenders<TPixel>.Screen().Blend(back, source, amount);
VectorAssert.Equal(expected, actual, 2);
}
@ -207,7 +207,7 @@ namespace ImageSharp.Tests.PixelFormats.PixelBlenders
where TPixel : struct, IPixel<TPixel>
{
Span<TPixel> dest = new Span<TPixel>(new TPixel[1]);
new DefaultScreenPixelBlender<TPixel>().Blend(dest, back.AsSpan(), source.AsSpan(), AsSpan(amount));
new DefaultPixelBlenders<TPixel>.Screen().Blend(dest, back.AsSpan(), source.AsSpan(), AsSpan(amount));
VectorAssert.Equal(expected, dest[0], 2);
}
@ -227,7 +227,7 @@ namespace ImageSharp.Tests.PixelFormats.PixelBlenders
public void DarkenFunction<TPixel>(TestPixel<TPixel> back, TestPixel<TPixel> source, float amount, TestPixel<TPixel> expected)
where TPixel : struct, IPixel<TPixel>
{
TPixel actual = PorterDuffFunctions<TPixel>.DarkenFunction(back, source, amount);
TPixel actual = PorterDuffFunctions.Darken((TPixel)back, source, amount);
VectorAssert.Equal(expected, actual, 2);
}
@ -236,7 +236,7 @@ namespace ImageSharp.Tests.PixelFormats.PixelBlenders
public void DarkenFunction_Blender<TPixel>(TestPixel<TPixel> back, TestPixel<TPixel> source, float amount, TestPixel<TPixel> expected)
where TPixel : struct, IPixel<TPixel>
{
TPixel actual = new DefaultDarkenPixelBlender<TPixel>().Blend(back, source, amount);
TPixel actual = new DefaultPixelBlenders<TPixel>.Darken().Blend(back, source, amount);
VectorAssert.Equal(expected, actual, 2);
}
@ -246,7 +246,7 @@ namespace ImageSharp.Tests.PixelFormats.PixelBlenders
where TPixel : struct, IPixel<TPixel>
{
Span<TPixel> dest = new Span<TPixel>(new TPixel[1]);
new DefaultDarkenPixelBlender<TPixel>().Blend(dest, back.AsSpan(), source.AsSpan(), AsSpan(amount));
new DefaultPixelBlenders<TPixel>.Darken().Blend(dest, back.AsSpan(), source.AsSpan(), AsSpan(amount));
VectorAssert.Equal(expected, dest[0], 2);
}
@ -266,7 +266,7 @@ namespace ImageSharp.Tests.PixelFormats.PixelBlenders
public void LightenFunction<TPixel>(TestPixel<TPixel> back, TestPixel<TPixel> source, float amount, TestPixel<TPixel> expected)
where TPixel : struct, IPixel<TPixel>
{
TPixel actual = PorterDuffFunctions<TPixel>.LightenFunction(back, source, amount);
TPixel actual = PorterDuffFunctions.Lighten((TPixel)back, source, amount);
VectorAssert.Equal(expected, actual, 2);
}
@ -275,7 +275,7 @@ namespace ImageSharp.Tests.PixelFormats.PixelBlenders
public void LightenFunction_Blender<TPixel>(TestPixel<TPixel> back, TestPixel<TPixel> source, float amount, TestPixel<TPixel> expected)
where TPixel : struct, IPixel<TPixel>
{
TPixel actual = new DefaultLightenPixelBlender<TPixel>().Blend(back, source, amount);
TPixel actual = new DefaultPixelBlenders<TPixel>.Lighten().Blend(back, source, amount);
VectorAssert.Equal(expected, actual, 2);
}
@ -285,7 +285,7 @@ namespace ImageSharp.Tests.PixelFormats.PixelBlenders
where TPixel : struct, IPixel<TPixel>
{
Span<TPixel> dest = new Span<TPixel>(new TPixel[1]);
new DefaultLightenPixelBlender<TPixel>().Blend(dest, back.AsSpan(), source.AsSpan(), AsSpan(amount));
new DefaultPixelBlenders<TPixel>.Lighten().Blend(dest, back.AsSpan(), source.AsSpan(), AsSpan(amount));
VectorAssert.Equal(expected, dest[0], 2);
}
@ -305,7 +305,7 @@ namespace ImageSharp.Tests.PixelFormats.PixelBlenders
public void OverlayFunction<TPixel>(TestPixel<TPixel> back, TestPixel<TPixel> source, float amount, TestPixel<TPixel> expected)
where TPixel : struct, IPixel<TPixel>
{
TPixel actual = PorterDuffFunctions<TPixel>.OverlayFunction(back, source, amount);
TPixel actual = PorterDuffFunctions.Overlay((TPixel)back, source, amount);
VectorAssert.Equal(expected, actual, 2);
}
@ -314,7 +314,7 @@ namespace ImageSharp.Tests.PixelFormats.PixelBlenders
public void OverlayFunction_Blender<TPixel>(TestPixel<TPixel> back, TestPixel<TPixel> source, float amount, TestPixel<TPixel> expected)
where TPixel : struct, IPixel<TPixel>
{
TPixel actual = new DefaultOverlayPixelBlender<TPixel>().Blend(back, source, amount);
TPixel actual = new DefaultPixelBlenders<TPixel>.Overlay().Blend(back, source, amount);
VectorAssert.Equal(expected, actual, 2);
}
@ -324,7 +324,7 @@ namespace ImageSharp.Tests.PixelFormats.PixelBlenders
where TPixel : struct, IPixel<TPixel>
{
Span<TPixel> dest = new Span<TPixel>(new TPixel[1]);
new DefaultOverlayPixelBlender<TPixel>().Blend(dest, back.AsSpan(), source.AsSpan(), AsSpan(amount));
new DefaultPixelBlenders<TPixel>.Overlay().Blend(dest, back.AsSpan(), source.AsSpan(), AsSpan(amount));
VectorAssert.Equal(expected, dest[0], 2);
}
@ -344,7 +344,7 @@ namespace ImageSharp.Tests.PixelFormats.PixelBlenders
public void HardLightFunction<TPixel>(TestPixel<TPixel> back, TestPixel<TPixel> source, float amount, TestPixel<TPixel> expected)
where TPixel : struct, IPixel<TPixel>
{
TPixel actual = PorterDuffFunctions<TPixel>.HardLightFunction(back, source, amount);
TPixel actual = PorterDuffFunctions.HardLight((TPixel)back, source, amount);
VectorAssert.Equal(expected, actual, 2);
}
@ -353,7 +353,7 @@ namespace ImageSharp.Tests.PixelFormats.PixelBlenders
public void HardLightFunction_Blender<TPixel>(TestPixel<TPixel> back, TestPixel<TPixel> source, float amount, TestPixel<TPixel> expected)
where TPixel : struct, IPixel<TPixel>
{
TPixel actual = new DefaultHardLightPixelBlender<TPixel>().Blend(back, source, amount);
TPixel actual = new DefaultPixelBlenders<TPixel>.HardLight().Blend(back, source, amount);
VectorAssert.Equal(expected, actual, 2);
}
@ -363,7 +363,7 @@ namespace ImageSharp.Tests.PixelFormats.PixelBlenders
where TPixel : struct, IPixel<TPixel>
{
Span<TPixel> dest = new Span<TPixel>(new TPixel[1]);
new DefaultHardLightPixelBlender<TPixel>().Blend(dest, back.AsSpan(), source.AsSpan(), AsSpan(amount));
new DefaultPixelBlenders<TPixel>.HardLight().Blend(dest, back.AsSpan(), source.AsSpan(), AsSpan(amount));
VectorAssert.Equal(expected, dest[0], 2);
}
}

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

@ -15,27 +15,55 @@ namespace ImageSharp.Tests.PixelFormats
public partial class PixelOperationsTests
{
public static TheoryData<object, Type, PixelBlenderMode> BlenderMappings = new TheoryData<object, Type, PixelBlenderMode>()
{
{ new TestPixel<Rgba32>(), typeof(DefaultNormalPixelBlender<Rgba32>), PixelBlenderMode.Normal },
{ new TestPixel<Rgba32>(), typeof(DefaultScreenPixelBlender<Rgba32>), PixelBlenderMode.Screen },
{ new TestPixel<Rgba32>(), typeof(DefaultHardLightPixelBlender<Rgba32>), PixelBlenderMode.HardLight },
{ new TestPixel<Rgba32>(), typeof(DefaultOverlayPixelBlender<Rgba32>), PixelBlenderMode.Overlay },
{ new TestPixel<Rgba32>(), typeof(DefaultDarkenPixelBlender<Rgba32>), PixelBlenderMode.Darken },
{ new TestPixel<Rgba32>(), typeof(DefaultLightenPixelBlender<Rgba32>), PixelBlenderMode.Lighten },
{ new TestPixel<Rgba32>(), typeof(DefaultAddPixelBlender<Rgba32>), PixelBlenderMode.Add },
{ new TestPixel<Rgba32>(), typeof(DefaultSubstractPixelBlender<Rgba32>), PixelBlenderMode.Substract },
{ new TestPixel<Rgba32>(), typeof(DefaultMultiplyPixelBlender<Rgba32>), PixelBlenderMode.Multiply },
{ new TestPixel<RgbaVector>(), typeof(DefaultNormalPixelBlender<RgbaVector>), PixelBlenderMode.Normal },
{ new TestPixel<RgbaVector>(), typeof(DefaultScreenPixelBlender<RgbaVector>), PixelBlenderMode.Screen },
{ new TestPixel<RgbaVector>(), typeof(DefaultHardLightPixelBlender<RgbaVector>), PixelBlenderMode.HardLight },
{ new TestPixel<RgbaVector>(), typeof(DefaultOverlayPixelBlender<RgbaVector>), PixelBlenderMode.Overlay },
{ new TestPixel<RgbaVector>(), typeof(DefaultDarkenPixelBlender<RgbaVector>), PixelBlenderMode.Darken },
{ new TestPixel<RgbaVector>(), typeof(DefaultLightenPixelBlender<RgbaVector>), PixelBlenderMode.Lighten },
{ new TestPixel<RgbaVector>(), typeof(DefaultAddPixelBlender<RgbaVector>), PixelBlenderMode.Add },
{ new TestPixel<RgbaVector>(), typeof(DefaultSubstractPixelBlender<RgbaVector>), PixelBlenderMode.Substract },
{ new TestPixel<RgbaVector>(), typeof(DefaultMultiplyPixelBlender<RgbaVector>), 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>.Substract), PixelBlenderMode.Substract },
{ 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<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 },
};
[Theory]

Loading…
Cancel
Save