diff --git a/.editorconfig b/.editorconfig
index fa43757a9..b725c5cce 100644
--- a/.editorconfig
+++ b/.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
\ No newline at end of file
+dotnet_style_qualification_for_property = true:warning
+
+[*.tt]
+indent_style = space
+indent_size = 4
\ No newline at end of file
diff --git a/src/ImageSharp/ImageSharp.csproj b/src/ImageSharp/ImageSharp.csproj
index 17f7bf58f..3b72f12a8 100644
--- a/src/ImageSharp/ImageSharp.csproj
+++ b/src/ImageSharp/ImageSharp.csproj
@@ -63,6 +63,14 @@
TextTemplatingFileGenerator
Rgba32.PixelOperations.Generated.cs
+
+ PorterDuffFunctions.Generated.cs
+ TextTemplatingFileGenerator
+
+
+ DefaultPixelBlenders.Generated.cs
+ TextTemplatingFileGenerator
+
@@ -83,5 +91,15 @@
True
Rgba32.PixelOperations.Generated.tt
+
+ True
+ True
+ DefaultPixelBlenders.Generated.tt
+
+
+ True
+ True
+ PorterDuffFunctions.Generated.tt
+
\ No newline at end of file
diff --git a/src/ImageSharp/PixelFormats/PixelBlenderMode.cs b/src/ImageSharp/PixelFormats/PixelBlenderMode.cs
index d8031fe6e..1e48f7181 100644
--- a/src/ImageSharp/PixelFormats/PixelBlenderMode.cs
+++ b/src/ImageSharp/PixelFormats/PixelBlenderMode.cs
@@ -57,6 +57,66 @@ namespace ImageSharp.PixelFormats
///
/// Multiplies or screens the colors, depending on the source value.
///
- HardLight
+ HardLight,
+
+ ///
+ /// returns the source colors
+ ///
+ Src,
+
+ ///
+ /// returns the source over the destination
+ ///
+ Atop,
+
+ ///
+ /// returns the detination over the source
+ ///
+ Over,
+
+ ///
+ /// the source where the desitnation and source overlap
+ ///
+ In,
+
+ ///
+ /// the destination where the desitnation and source overlap
+ ///
+ Out,
+
+ ///
+ /// the destination where the source does not overlap it
+ ///
+ Dest,
+
+ ///
+ /// the source where they dont overlap othersie dest in overlapping parts
+ ///
+ DestAtop,
+
+ ///
+ /// the destnation over the source
+ ///
+ DestOver,
+
+ ///
+ /// the destination where the desitnation and source overlap
+ ///
+ DestIn,
+
+ ///
+ /// the source where the desitnation and source overlap
+ ///
+ DestOut,
+
+ ///
+ /// the clear.
+ ///
+ Clear,
+
+ ///
+ /// clear where they overlap
+ ///
+ Xor
}
}
diff --git a/src/ImageSharp/PixelFormats/PixelBlenders/DefaultAddPixelBlender{TPixel}.cs b/src/ImageSharp/PixelFormats/PixelBlenders/DefaultAddPixelBlender{TPixel}.cs
deleted file mode 100644
index 261a98674..000000000
--- a/src/ImageSharp/PixelFormats/PixelBlenders/DefaultAddPixelBlender{TPixel}.cs
+++ /dev/null
@@ -1,57 +0,0 @@
-//
-// Copyright (c) James Jackson-South and contributors.
-// Licensed under the Apache License, Version 2.0.
-//
-
-namespace ImageSharp.PixelFormats.PixelBlenders
-{
- using System;
- using System.Numerics;
-
- using ImageSharp.Memory;
- using ImageSharp.PixelFormats;
-
- ///
- /// Applies an "Add" blending to pixels.
- ///
- /// The type of the pixel
- internal class DefaultAddPixelBlender : PixelBlender
- where TPixel : struct, IPixel
- {
- ///
- /// Gets the static instance of this blender.
- ///
- public static DefaultAddPixelBlender Instance { get; } = new DefaultAddPixelBlender();
-
- ///
- public override TPixel Blend(TPixel background, TPixel source, float amount)
- {
- return PorterDuffFunctions.AddFunction(background, source, amount);
- }
-
- ///
- public override void Blend(Span destination, Span background, Span source, Span 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 buffer = new Buffer(destination.Length * 3))
- {
- Span destinationSpan = buffer.Slice(0, destination.Length);
- Span backgroundSpan = buffer.Slice(destination.Length, destination.Length);
- Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length);
-
- PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length);
- PixelOperations.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.Instance.PackFromVector4(destinationSpan, destination, destination.Length);
- }
- }
- }
-}
diff --git a/src/ImageSharp/PixelFormats/PixelBlenders/DefaultDarkenPixelBlender{TPixel}.cs b/src/ImageSharp/PixelFormats/PixelBlenders/DefaultDarkenPixelBlender{TPixel}.cs
deleted file mode 100644
index bca99e2f0..000000000
--- a/src/ImageSharp/PixelFormats/PixelBlenders/DefaultDarkenPixelBlender{TPixel}.cs
+++ /dev/null
@@ -1,57 +0,0 @@
-//
-// Copyright (c) James Jackson-South and contributors.
-// Licensed under the Apache License, Version 2.0.
-//
-
-namespace ImageSharp.PixelFormats.PixelBlenders
-{
- using System;
- using System.Numerics;
-
- using ImageSharp.Memory;
- using ImageSharp.PixelFormats;
-
- ///
- /// Applies an "Darken" blending to pixels.
- ///
- /// The type of the pixel
- internal class DefaultDarkenPixelBlender : PixelBlender
- where TPixel : struct, IPixel
- {
- ///
- /// Gets the static instance of this blender.
- ///
- public static DefaultDarkenPixelBlender Instance { get; } = new DefaultDarkenPixelBlender();
-
- ///
- public override TPixel Blend(TPixel background, TPixel source, float amount)
- {
- return PorterDuffFunctions.DarkenFunction(background, source, amount);
- }
-
- ///
- public override void Blend(Span destination, Span background, Span source, Span 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 buffer = new Buffer(destination.Length * 3))
- {
- Span destinationSpan = buffer.Slice(0, destination.Length);
- Span backgroundSpan = buffer.Slice(destination.Length, destination.Length);
- Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length);
-
- PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length);
- PixelOperations.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.Instance.PackFromVector4(destinationSpan, destination, destination.Length);
- }
- }
- }
-}
diff --git a/src/ImageSharp/PixelFormats/PixelBlenders/DefaultHardLightPixelBlender{TPixel}.cs b/src/ImageSharp/PixelFormats/PixelBlenders/DefaultHardLightPixelBlender{TPixel}.cs
deleted file mode 100644
index 646423cff..000000000
--- a/src/ImageSharp/PixelFormats/PixelBlenders/DefaultHardLightPixelBlender{TPixel}.cs
+++ /dev/null
@@ -1,57 +0,0 @@
-//
-// Copyright (c) James Jackson-South and contributors.
-// Licensed under the Apache License, Version 2.0.
-//
-
-namespace ImageSharp.PixelFormats.PixelBlenders
-{
- using System;
- using System.Numerics;
-
- using ImageSharp.Memory;
- using ImageSharp.PixelFormats;
-
- ///
- /// Applies an "Hard Light" blending to pixels.
- ///
- /// The type of the pixel
- internal class DefaultHardLightPixelBlender : PixelBlender
- where TPixel : struct, IPixel
- {
- ///
- /// Gets the static instance of this blender.
- ///
- public static DefaultHardLightPixelBlender Instance { get; } = new DefaultHardLightPixelBlender();
-
- ///
- public override TPixel Blend(TPixel background, TPixel source, float amount)
- {
- return PorterDuffFunctions.HardLightFunction(background, source, amount);
- }
-
- ///
- public override void Blend(Span destination, Span background, Span source, Span 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 buffer = new Buffer(destination.Length * 3))
- {
- Span destinationSpan = buffer.Slice(0, destination.Length);
- Span backgroundSpan = buffer.Slice(destination.Length, destination.Length);
- Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length);
-
- PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length);
- PixelOperations.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.Instance.PackFromVector4(destinationSpan, destination, destination.Length);
- }
- }
- }
-}
diff --git a/src/ImageSharp/PixelFormats/PixelBlenders/DefaultLightenPixelBlender{TPixel}.cs b/src/ImageSharp/PixelFormats/PixelBlenders/DefaultLightenPixelBlender{TPixel}.cs
deleted file mode 100644
index 55ad81e7a..000000000
--- a/src/ImageSharp/PixelFormats/PixelBlenders/DefaultLightenPixelBlender{TPixel}.cs
+++ /dev/null
@@ -1,57 +0,0 @@
-//
-// Copyright (c) James Jackson-South and contributors.
-// Licensed under the Apache License, Version 2.0.
-//
-
-namespace ImageSharp.PixelFormats.PixelBlenders
-{
- using System;
- using System.Numerics;
-
- using ImageSharp.Memory;
- using ImageSharp.PixelFormats;
-
- ///
- /// Applies an "Lighten" blending to pixels.
- ///
- /// The type of the pixel
- internal class DefaultLightenPixelBlender : PixelBlender
- where TPixel : struct, IPixel
- {
- ///
- /// Gets the static instance of this blender.
- ///
- public static DefaultLightenPixelBlender Instance { get; } = new DefaultLightenPixelBlender();
-
- ///
- public override TPixel Blend(TPixel background, TPixel source, float amount)
- {
- return PorterDuffFunctions.LightenFunction(background, source, amount);
- }
-
- ///
- public override void Blend(Span destination, Span background, Span source, Span 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 buffer = new Buffer(destination.Length * 3))
- {
- Span destinationSpan = buffer.Slice(0, destination.Length);
- Span backgroundSpan = buffer.Slice(destination.Length, destination.Length);
- Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length);
-
- PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length);
- PixelOperations.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.Instance.PackFromVector4(destinationSpan, destination, destination.Length);
- }
- }
- }
-}
diff --git a/src/ImageSharp/PixelFormats/PixelBlenders/DefaultMultiplyPixelBlender{TPixel}.cs b/src/ImageSharp/PixelFormats/PixelBlenders/DefaultMultiplyPixelBlender{TPixel}.cs
deleted file mode 100644
index e21efaed0..000000000
--- a/src/ImageSharp/PixelFormats/PixelBlenders/DefaultMultiplyPixelBlender{TPixel}.cs
+++ /dev/null
@@ -1,57 +0,0 @@
-//
-// Copyright (c) James Jackson-South and contributors.
-// Licensed under the Apache License, Version 2.0.
-//
-
-namespace ImageSharp.PixelFormats.PixelBlenders
-{
- using System;
- using System.Numerics;
-
- using ImageSharp.Memory;
- using ImageSharp.PixelFormats;
-
- ///
- /// Applies an "Multiply" blending to pixels.
- ///
- /// The type of the pixel
- internal class DefaultMultiplyPixelBlender : PixelBlender
- where TPixel : struct, IPixel
- {
- ///
- /// Gets the static instance of this blender.
- ///
- public static DefaultMultiplyPixelBlender Instance { get; } = new DefaultMultiplyPixelBlender();
-
- ///
- public override TPixel Blend(TPixel background, TPixel source, float amount)
- {
- return PorterDuffFunctions.MultiplyFunction(background, source, amount);
- }
-
- ///
- public override void Blend(Span destination, Span background, Span source, Span 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 buffer = new Buffer(destination.Length * 3))
- {
- Span destinationSpan = buffer.Slice(0, destination.Length);
- Span backgroundSpan = buffer.Slice(destination.Length, destination.Length);
- Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length);
-
- PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length);
- PixelOperations.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.Instance.PackFromVector4(destinationSpan, destination, destination.Length);
- }
- }
- }
-}
diff --git a/src/ImageSharp/PixelFormats/PixelBlenders/DefaultNormalPixelBlender{TPixel}.cs b/src/ImageSharp/PixelFormats/PixelBlenders/DefaultNormalPixelBlender{TPixel}.cs
deleted file mode 100644
index 9d63d11e0..000000000
--- a/src/ImageSharp/PixelFormats/PixelBlenders/DefaultNormalPixelBlender{TPixel}.cs
+++ /dev/null
@@ -1,57 +0,0 @@
-//
-// Copyright (c) James Jackson-South and contributors.
-// Licensed under the Apache License, Version 2.0.
-//
-
-namespace ImageSharp.PixelFormats.PixelBlenders
-{
- using System;
- using System.Numerics;
-
- using ImageSharp.Memory;
- using ImageSharp.PixelFormats;
-
- ///
- /// Applies a "Normal" otherwise nown as "Alpha Blending" blending to pixels.
- ///
- /// The type of the pixel
- internal class DefaultNormalPixelBlender : PixelBlender
- where TPixel : struct, IPixel
- {
- ///
- /// Gets the static instance of this blender.
- ///
- public static DefaultNormalPixelBlender Instance { get; } = new DefaultNormalPixelBlender();
-
- ///
- public override TPixel Blend(TPixel background, TPixel source, float amount)
- {
- return PorterDuffFunctions.NormalBlendFunction(background, source, amount);
- }
-
- ///
- public override void Blend(Span destination, Span background, Span source, Span 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 buffer = new Buffer(destination.Length * 3))
- {
- Span destinationSpan = buffer.Slice(0, destination.Length);
- Span backgroundSpan = buffer.Slice(destination.Length, destination.Length);
- Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length);
-
- PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length);
- PixelOperations.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.Instance.PackFromVector4(destinationSpan, destination, destination.Length);
- }
- }
- }
-}
diff --git a/src/ImageSharp/PixelFormats/PixelBlenders/DefaultOverlayPixelBlender{TPixel}.cs b/src/ImageSharp/PixelFormats/PixelBlenders/DefaultOverlayPixelBlender{TPixel}.cs
deleted file mode 100644
index 8172909ec..000000000
--- a/src/ImageSharp/PixelFormats/PixelBlenders/DefaultOverlayPixelBlender{TPixel}.cs
+++ /dev/null
@@ -1,57 +0,0 @@
-//
-// Copyright (c) James Jackson-South and contributors.
-// Licensed under the Apache License, Version 2.0.
-//
-
-namespace ImageSharp.PixelFormats.PixelBlenders
-{
- using System;
- using System.Numerics;
-
- using ImageSharp.Memory;
- using ImageSharp.PixelFormats;
-
- ///
- /// Applies an "Overlay" blending to pixels.
- ///
- /// The type of the pixel
- internal class DefaultOverlayPixelBlender : PixelBlender
- where TPixel : struct, IPixel
- {
- ///
- /// Gets the static instance of this blender.
- ///
- public static DefaultOverlayPixelBlender Instance { get; } = new DefaultOverlayPixelBlender();
-
- ///
- public override TPixel Blend(TPixel background, TPixel source, float amount)
- {
- return PorterDuffFunctions.OverlayFunction(background, source, amount);
- }
-
- ///
- public override void Blend(Span destination, Span background, Span source, Span 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 buffer = new Buffer(destination.Length * 3))
- {
- Span destinationSpan = buffer.Slice(0, destination.Length);
- Span backgroundSpan = buffer.Slice(destination.Length, destination.Length);
- Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length);
-
- PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length);
- PixelOperations.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.Instance.PackFromVector4(destinationSpan, destination, destination.Length);
- }
- }
- }
-}
diff --git a/src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.cs b/src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.cs
new file mode 100644
index 000000000..915d9a924
--- /dev/null
+++ b/src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.cs
@@ -0,0 +1,849 @@
+//
+//
+// Copyright (c) James Jackson-South and contributors.
+// Licensed under the Apache License, Version 2.0.
+//
+
+namespace ImageSharp.PixelFormats.PixelBlenders
+{
+ using System;
+ using System.Numerics;
+ using ImageSharp.Memory;
+
+
+ ///
+ /// Collection of Porter Duff alpha blending functions applying different composition models.
+ ///
+ ///
+ /// 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
+ ///
+ internal static class DefaultPixelBlenders
+ where TPixel : struct, IPixel
+ {
+
+ internal class Normal : PixelBlender
+ {
+
+ ///
+ /// Gets the static instance of this blender.
+ ///
+ public static Normal Instance { get; } = new Normal();
+
+ ///
+ public override TPixel Blend(TPixel background, TPixel source, float amount)
+ {
+ return PorterDuffFunctions.Normal(background, source, amount);
+ }
+
+ ///
+ public override void Blend(Span destination, Span background, Span source, Span 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 buffer = new Buffer(destination.Length * 3))
+ {
+ Span destinationSpan = buffer.Slice(0, destination.Length);
+ Span backgroundSpan = buffer.Slice(destination.Length, destination.Length);
+ Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length);
+
+ PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length);
+ PixelOperations.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.Instance.PackFromVector4(destinationSpan, destination, destination.Length);
+ }
+ }
+ }
+ internal class Multiply : PixelBlender
+ {
+
+ ///
+ /// Gets the static instance of this blender.
+ ///
+ public static Multiply Instance { get; } = new Multiply();
+
+ ///
+ public override TPixel Blend(TPixel background, TPixel source, float amount)
+ {
+ return PorterDuffFunctions.Multiply(background, source, amount);
+ }
+
+ ///
+ public override void Blend(Span destination, Span background, Span source, Span 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 buffer = new Buffer(destination.Length * 3))
+ {
+ Span destinationSpan = buffer.Slice(0, destination.Length);
+ Span backgroundSpan = buffer.Slice(destination.Length, destination.Length);
+ Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length);
+
+ PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length);
+ PixelOperations.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.Instance.PackFromVector4(destinationSpan, destination, destination.Length);
+ }
+ }
+ }
+ internal class Add : PixelBlender
+ {
+
+ ///
+ /// Gets the static instance of this blender.
+ ///
+ public static Add Instance { get; } = new Add();
+
+ ///
+ public override TPixel Blend(TPixel background, TPixel source, float amount)
+ {
+ return PorterDuffFunctions.Add(background, source, amount);
+ }
+
+ ///
+ public override void Blend(Span destination, Span background, Span source, Span 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 buffer = new Buffer(destination.Length * 3))
+ {
+ Span destinationSpan = buffer.Slice(0, destination.Length);
+ Span backgroundSpan = buffer.Slice(destination.Length, destination.Length);
+ Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length);
+
+ PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length);
+ PixelOperations.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.Instance.PackFromVector4(destinationSpan, destination, destination.Length);
+ }
+ }
+ }
+ internal class Substract : PixelBlender
+ {
+
+ ///
+ /// Gets the static instance of this blender.
+ ///
+ public static Substract Instance { get; } = new Substract();
+
+ ///
+ public override TPixel Blend(TPixel background, TPixel source, float amount)
+ {
+ return PorterDuffFunctions.Substract(background, source, amount);
+ }
+
+ ///
+ public override void Blend(Span destination, Span background, Span source, Span 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 buffer = new Buffer(destination.Length * 3))
+ {
+ Span destinationSpan = buffer.Slice(0, destination.Length);
+ Span backgroundSpan = buffer.Slice(destination.Length, destination.Length);
+ Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length);
+
+ PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length);
+ PixelOperations.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.Instance.PackFromVector4(destinationSpan, destination, destination.Length);
+ }
+ }
+ }
+ internal class Screen : PixelBlender
+ {
+
+ ///
+ /// Gets the static instance of this blender.
+ ///
+ public static Screen Instance { get; } = new Screen();
+
+ ///
+ public override TPixel Blend(TPixel background, TPixel source, float amount)
+ {
+ return PorterDuffFunctions.Screen(background, source, amount);
+ }
+
+ ///
+ public override void Blend(Span destination, Span background, Span source, Span 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 buffer = new Buffer(destination.Length * 3))
+ {
+ Span destinationSpan = buffer.Slice(0, destination.Length);
+ Span backgroundSpan = buffer.Slice(destination.Length, destination.Length);
+ Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length);
+
+ PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length);
+ PixelOperations.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.Instance.PackFromVector4(destinationSpan, destination, destination.Length);
+ }
+ }
+ }
+ internal class Darken : PixelBlender
+ {
+
+ ///
+ /// Gets the static instance of this blender.
+ ///
+ public static Darken Instance { get; } = new Darken();
+
+ ///
+ public override TPixel Blend(TPixel background, TPixel source, float amount)
+ {
+ return PorterDuffFunctions.Darken(background, source, amount);
+ }
+
+ ///
+ public override void Blend(Span destination, Span background, Span source, Span 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 buffer = new Buffer(destination.Length * 3))
+ {
+ Span destinationSpan = buffer.Slice(0, destination.Length);
+ Span backgroundSpan = buffer.Slice(destination.Length, destination.Length);
+ Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length);
+
+ PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length);
+ PixelOperations.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.Instance.PackFromVector4(destinationSpan, destination, destination.Length);
+ }
+ }
+ }
+ internal class Lighten : PixelBlender
+ {
+
+ ///
+ /// Gets the static instance of this blender.
+ ///
+ public static Lighten Instance { get; } = new Lighten();
+
+ ///
+ public override TPixel Blend(TPixel background, TPixel source, float amount)
+ {
+ return PorterDuffFunctions.Lighten(background, source, amount);
+ }
+
+ ///
+ public override void Blend(Span destination, Span background, Span source, Span 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 buffer = new Buffer(destination.Length * 3))
+ {
+ Span destinationSpan = buffer.Slice(0, destination.Length);
+ Span backgroundSpan = buffer.Slice(destination.Length, destination.Length);
+ Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length);
+
+ PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length);
+ PixelOperations.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.Instance.PackFromVector4(destinationSpan, destination, destination.Length);
+ }
+ }
+ }
+ internal class Overlay : PixelBlender
+ {
+
+ ///
+ /// Gets the static instance of this blender.
+ ///
+ public static Overlay Instance { get; } = new Overlay();
+
+ ///
+ public override TPixel Blend(TPixel background, TPixel source, float amount)
+ {
+ return PorterDuffFunctions.Overlay(background, source, amount);
+ }
+
+ ///
+ public override void Blend(Span destination, Span background, Span source, Span 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 buffer = new Buffer(destination.Length * 3))
+ {
+ Span destinationSpan = buffer.Slice(0, destination.Length);
+ Span backgroundSpan = buffer.Slice(destination.Length, destination.Length);
+ Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length);
+
+ PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length);
+ PixelOperations.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.Instance.PackFromVector4(destinationSpan, destination, destination.Length);
+ }
+ }
+ }
+ internal class HardLight : PixelBlender
+ {
+
+ ///
+ /// Gets the static instance of this blender.
+ ///
+ public static HardLight Instance { get; } = new HardLight();
+
+ ///
+ public override TPixel Blend(TPixel background, TPixel source, float amount)
+ {
+ return PorterDuffFunctions.HardLight(background, source, amount);
+ }
+
+ ///
+ public override void Blend(Span destination, Span background, Span source, Span 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 buffer = new Buffer(destination.Length * 3))
+ {
+ Span destinationSpan = buffer.Slice(0, destination.Length);
+ Span backgroundSpan = buffer.Slice(destination.Length, destination.Length);
+ Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length);
+
+ PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length);
+ PixelOperations.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.Instance.PackFromVector4(destinationSpan, destination, destination.Length);
+ }
+ }
+ }
+ internal class Src : PixelBlender
+ {
+
+ ///
+ /// Gets the static instance of this blender.
+ ///
+ public static Src Instance { get; } = new Src();
+
+ ///
+ public override TPixel Blend(TPixel background, TPixel source, float amount)
+ {
+ return PorterDuffFunctions.Src(background, source, amount);
+ }
+
+ ///
+ public override void Blend(Span destination, Span background, Span source, Span 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 buffer = new Buffer(destination.Length * 3))
+ {
+ Span destinationSpan = buffer.Slice(0, destination.Length);
+ Span backgroundSpan = buffer.Slice(destination.Length, destination.Length);
+ Span