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/Formats/Png/ImageExtensions.cs b/src/ImageSharp/Formats/Png/ImageExtensions.cs
index 44f242b3f..3841b313c 100644
--- a/src/ImageSharp/Formats/Png/ImageExtensions.cs
+++ b/src/ImageSharp/Formats/Png/ImageExtensions.cs
@@ -46,7 +46,7 @@ namespace ImageSharp
public static Image SaveAsPng(this Image source, Stream stream, IPngEncoderOptions options)
where TPixel : struct, IPixel
{
- PngEncoder encoder = new PngEncoder();
+ var encoder = new PngEncoder();
encoder.Encode(source, stream, options);
return source;
diff --git a/src/ImageSharp/Image/Image.FromBytes.cs b/src/ImageSharp/Image/Image.FromBytes.cs
index c7309c4b1..628092359 100644
--- a/src/ImageSharp/Image/Image.FromBytes.cs
+++ b/src/ImageSharp/Image/Image.FromBytes.cs
@@ -126,7 +126,7 @@ namespace ImageSharp
public static Image Load(Configuration config, byte[] data, IDecoderOptions options)
where TPixel : struct, IPixel
{
- using (MemoryStream ms = new MemoryStream(data))
+ using (var ms = new MemoryStream(data))
{
return Load(config, ms, options);
}
@@ -143,7 +143,7 @@ namespace ImageSharp
public static Image Load(byte[] data, IImageDecoder decoder, IDecoderOptions options)
where TPixel : struct, IPixel
{
- using (MemoryStream ms = new MemoryStream(data))
+ using (var ms = new MemoryStream(data))
{
return Load(ms, decoder, options);
}
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/MetaData/Profiles/ICC/IccReader.cs b/src/ImageSharp/MetaData/Profiles/ICC/IccReader.cs
index d7f556a81..b24c96f02 100644
--- a/src/ImageSharp/MetaData/Profiles/ICC/IccReader.cs
+++ b/src/ImageSharp/MetaData/Profiles/ICC/IccReader.cs
@@ -5,6 +5,8 @@
namespace ImageSharp
{
+ using System.Collections.Generic;
+
///
/// Reads and parses ICC data from a byte array
///
@@ -85,9 +87,21 @@ namespace ImageSharp
{
IccTagTableEntry[] tagTable = this.ReadTagTable(reader);
IccTagDataEntry[] entries = new IccTagDataEntry[tagTable.Length];
+ var store = new Dictionary();
for (int i = 0; i < tagTable.Length; i++)
{
- IccTagDataEntry entry = reader.ReadTagDataEntry(tagTable[i]);
+ IccTagDataEntry entry;
+ uint offset = tagTable[i].Offset;
+ if (store.ContainsKey(offset))
+ {
+ entry = store[offset];
+ }
+ else
+ {
+ entry = reader.ReadTagDataEntry(tagTable[i]);
+ store.Add(offset, entry);
+ }
+
entry.TagSignature = tagTable[i].Signature;
entries[i] = entry;
}
diff --git a/src/ImageSharp/MetaData/Profiles/ICC/IccWriter.cs b/src/ImageSharp/MetaData/Profiles/ICC/IccWriter.cs
index b4e5f2868..19c00e8f5 100644
--- a/src/ImageSharp/MetaData/Profiles/ICC/IccWriter.cs
+++ b/src/ImageSharp/MetaData/Profiles/ICC/IccWriter.cs
@@ -5,6 +5,7 @@
namespace ImageSharp
{
+ using System;
using System.Collections.Generic;
using System.Linq;
@@ -76,30 +77,18 @@ namespace ImageSharp
private IccTagTableEntry[] WriteTagData(IccDataWriter writer, List entries)
{
- var inData = new List(entries);
- var dupData = new List();
-
- while (inData.Count > 0)
- {
- IccTagDataEntry[] items = inData.Where(t => inData[0].Equals(t)).ToArray();
- dupData.Add(items);
- foreach (IccTagDataEntry item in items)
- {
- inData.Remove(item);
- }
- }
-
- var table = new List();
+ IEnumerable> grouped = entries.GroupBy(t => t);
// (Header size) + (entry count) + (nr of entries) * (size of table entry)
writer.SetIndex(128 + 4 + (entries.Count * 12));
- foreach (IccTagDataEntry[] entry in dupData)
+ var table = new List();
+ foreach (IGrouping group in grouped)
{
- writer.WriteTagDataEntry(entry[0], out IccTagTableEntry tentry);
- foreach (IccTagDataEntry item in entry)
+ writer.WriteTagDataEntry(group.Key, out IccTagTableEntry tableEntry);
+ foreach (IccTagDataEntry item in group)
{
- table.Add(new IccTagTableEntry(item.TagSignature, tentry.Offset, tentry.DataSize));
+ table.Add(new IccTagTableEntry(item.TagSignature, tableEntry.Offset, tableEntry.DataSize));
}
}
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
+ {
+
+ ///