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/.gitignore b/.gitignore
index fb8af2320..8034c8c89 100644
--- a/.gitignore
+++ b/.gitignore
@@ -217,3 +217,4 @@ artifacts/
#CodeCoverage
**/CodeCoverage/*
docs/
+/samples/AvatarWithRoundedCorner/output
diff --git a/ImageSharp.sln b/ImageSharp.sln
index 2e0cbd52e..35998e1aa 100644
--- a/ImageSharp.sln
+++ b/ImageSharp.sln
@@ -1,7 +1,7 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
-VisualStudioVersion = 15.0.26403.7
+VisualStudioVersion = 15.0.26430.6
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "SolutionItems", "SolutionItems", "{C317F1B1-D75E-4C6D-83EB-80367343E0D7}"
ProjectSection(SolutionItems) = preProject
@@ -45,6 +45,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ImageSharp.Benchmarks", "te
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ImageSharp.Sandbox46", "tests\ImageSharp.Sandbox46\ImageSharp.Sandbox46.csproj", "{96188137-5FA6-4924-AB6E-4EFF79C6E0BB}"
EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "samples", "samples", "{7CC6D57E-B916-43B8-B315-A0BB92F260A2}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AvatarWithRoundedCorner", "samples\AvatarWithRoundedCorner\AvatarWithRoundedCorner.csproj", "{844FC582-4E78-4371-847D-EFD4D1103578}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -127,6 +131,18 @@ Global
{96188137-5FA6-4924-AB6E-4EFF79C6E0BB}.Release|x64.Build.0 = Release|Any CPU
{96188137-5FA6-4924-AB6E-4EFF79C6E0BB}.Release|x86.ActiveCfg = Release|Any CPU
{96188137-5FA6-4924-AB6E-4EFF79C6E0BB}.Release|x86.Build.0 = Release|Any CPU
+ {844FC582-4E78-4371-847D-EFD4D1103578}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {844FC582-4E78-4371-847D-EFD4D1103578}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {844FC582-4E78-4371-847D-EFD4D1103578}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {844FC582-4E78-4371-847D-EFD4D1103578}.Debug|x64.Build.0 = Debug|Any CPU
+ {844FC582-4E78-4371-847D-EFD4D1103578}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {844FC582-4E78-4371-847D-EFD4D1103578}.Debug|x86.Build.0 = Debug|Any CPU
+ {844FC582-4E78-4371-847D-EFD4D1103578}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {844FC582-4E78-4371-847D-EFD4D1103578}.Release|Any CPU.Build.0 = Release|Any CPU
+ {844FC582-4E78-4371-847D-EFD4D1103578}.Release|x64.ActiveCfg = Release|Any CPU
+ {844FC582-4E78-4371-847D-EFD4D1103578}.Release|x64.Build.0 = Release|Any CPU
+ {844FC582-4E78-4371-847D-EFD4D1103578}.Release|x86.ActiveCfg = Release|Any CPU
+ {844FC582-4E78-4371-847D-EFD4D1103578}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -139,5 +155,6 @@ Global
{EA3000E9-2A91-4EC4-8A68-E566DEBDC4F6} = {56801022-D71A-4FBE-BC5B-CBA08E2284EC}
{2BF743D8-2A06-412D-96D7-F448F00C5EA5} = {56801022-D71A-4FBE-BC5B-CBA08E2284EC}
{96188137-5FA6-4924-AB6E-4EFF79C6E0BB} = {56801022-D71A-4FBE-BC5B-CBA08E2284EC}
+ {844FC582-4E78-4371-847D-EFD4D1103578} = {7CC6D57E-B916-43B8-B315-A0BB92F260A2}
EndGlobalSection
EndGlobal
diff --git a/samples/AvatarWithRoundedCorner/AvatarWithRoundedCorner.csproj b/samples/AvatarWithRoundedCorner/AvatarWithRoundedCorner.csproj
new file mode 100644
index 000000000..e000aacf1
--- /dev/null
+++ b/samples/AvatarWithRoundedCorner/AvatarWithRoundedCorner.csproj
@@ -0,0 +1,12 @@
+
+
+
+ Exe
+ netcoreapp1.1
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/samples/AvatarWithRoundedCorner/Program.cs b/samples/AvatarWithRoundedCorner/Program.cs
new file mode 100644
index 000000000..5516a73fb
--- /dev/null
+++ b/samples/AvatarWithRoundedCorner/Program.cs
@@ -0,0 +1,70 @@
+
+
+namespace AvatarWithRoundedCorner
+{
+ using System;
+ using System.Numerics;
+ using ImageSharp;
+ using SixLabors.Shapes;
+
+ class Program
+ {
+ static void Main(string[] args)
+ {
+ System.IO.Directory.CreateDirectory("output");
+
+ GenerateAvatar("fb.jpg", "output/fb.png", new ImageSharp.Size(200, 200), 20);
+ GenerateAvatar("fb.jpg", "output/fb-round.png", new ImageSharp.Size(200, 200), 100);
+ GenerateAvatar("fb.jpg", "output/fb-rounder.png", new ImageSharp.Size(200, 200), 150);
+ }
+
+ private static void GenerateAvatar(string source, string destination, ImageSharp.Size size, float cornerRadius)
+ {
+ using (var image = Image.Load(source))
+ {
+ image.Resize(new ImageSharp.Processing.ResizeOptions
+ {
+ Size = size,
+ Mode = ImageSharp.Processing.ResizeMode.Crop
+ });
+
+ ApplyRoundedCourners(image, cornerRadius);
+ image.Save(destination);
+ }
+ }
+
+ public static void ApplyRoundedCourners(Image img, float cornerRadius)
+ {
+ var corners = BuildCorners(img.Width, img.Height, cornerRadius);
+ // now we have our corners time to draw them
+ img.Fill(Rgba32.Transparent, corners, new GraphicsOptions(true)
+ {
+ BlenderMode = ImageSharp.PixelFormats.PixelBlenderMode.Src // enforces that any part of this shape that has color is punched out of the background
+ });
+ }
+
+ public static IPathCollection BuildCorners(int imageWidth, int imageHeight, float cornerRadius)
+ {
+ // first create a square
+ var rect = new SixLabors.Shapes.Rectangle(-0.5f, -0.5f, cornerRadius, cornerRadius);
+
+ // then cut out of the square a circle so we are left with a corner
+ var cornerToptLeft = rect.Clip(new SixLabors.Shapes.Ellipse(cornerRadius-0.5f, cornerRadius - 0.5f, cornerRadius));
+
+ // corner is now a corner shape positions top left
+ //lets make 3 more positioned correctly, we cando that by translating the orgional artound the center of the image
+ var center = new Vector2(imageWidth / 2, imageHeight / 2);
+ var angle = Math.PI / 2f;
+
+ float rightPos = imageWidth - cornerToptLeft.Bounds.Width +1;
+ float bottomPos = imageHeight - cornerToptLeft.Bounds.Height + 1;
+
+ // move it across the widthof the image - the width of the shape
+ var cornerTopRight = cornerToptLeft.RotateDegree(90).Translate(rightPos, 0);
+ var cornerBottomLeft = cornerToptLeft.RotateDegree(-90).Translate(0, bottomPos);
+ var cornerBottomRight = cornerToptLeft.RotateDegree(180).Translate(rightPos, bottomPos);
+
+ return new PathCollection(cornerToptLeft, cornerBottomLeft, cornerTopRight, cornerBottomRight);
+ }
+ }
+}
\ No newline at end of file
diff --git a/samples/AvatarWithRoundedCorner/fb.jpg b/samples/AvatarWithRoundedCorner/fb.jpg
new file mode 100644
index 000000000..7241890e2
--- /dev/null
+++ b/samples/AvatarWithRoundedCorner/fb.jpg
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:93bb4d6281dc1e845db57e836e0dca30b7a4062e81044efb27ad4d8b1a33130c
+size 15787
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