mirror of https://github.com/SixLabors/ImageSharp
36 changed files with 2050 additions and 944 deletions
@ -0,0 +1,12 @@ |
|||
<Project Sdk="Microsoft.NET.Sdk"> |
|||
|
|||
<PropertyGroup> |
|||
<OutputType>Exe</OutputType> |
|||
<TargetFramework>netcoreapp1.1</TargetFramework> |
|||
</PropertyGroup> |
|||
|
|||
<ItemGroup> |
|||
<ProjectReference Include="..\..\src\ImageSharp.Drawing\ImageSharp.Drawing.csproj" /> |
|||
</ItemGroup> |
|||
|
|||
</Project> |
|||
@ -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<Rgba32> 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); |
|||
} |
|||
} |
|||
} |
|||
|
After Width: | Height: | Size: 15 KiB |
@ -1,57 +0,0 @@ |
|||
// <copyright file="DefaultAddPixelBlender{TPixel}.cs" company="James Jackson-South">
|
|||
// Copyright (c) James Jackson-South and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
|
|||
namespace ImageSharp.PixelFormats.PixelBlenders |
|||
{ |
|||
using System; |
|||
using System.Numerics; |
|||
|
|||
using ImageSharp.Memory; |
|||
using ImageSharp.PixelFormats; |
|||
|
|||
/// <summary>
|
|||
/// Applies an "Add" blending to pixels.
|
|||
/// </summary>
|
|||
/// <typeparam name="TPixel">The type of the pixel</typeparam>
|
|||
internal class DefaultAddPixelBlender<TPixel> : PixelBlender<TPixel> |
|||
where TPixel : struct, IPixel<TPixel> |
|||
{ |
|||
/// <summary>
|
|||
/// Gets the static instance of this blender.
|
|||
/// </summary>
|
|||
public static DefaultAddPixelBlender<TPixel> Instance { get; } = new DefaultAddPixelBlender<TPixel>(); |
|||
|
|||
/// <inheritdoc />
|
|||
public override TPixel Blend(TPixel background, TPixel source, float amount) |
|||
{ |
|||
return PorterDuffFunctions<TPixel>.AddFunction(background, source, amount); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public override void Blend(Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount) |
|||
{ |
|||
Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); |
|||
Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); |
|||
Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); |
|||
|
|||
using (Buffer<Vector4> buffer = new Buffer<Vector4>(destination.Length * 3)) |
|||
{ |
|||
Span<Vector4> destinationSpan = buffer.Slice(0, destination.Length); |
|||
Span<Vector4> backgroundSpan = buffer.Slice(destination.Length, destination.Length); |
|||
Span<Vector4> sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); |
|||
|
|||
PixelOperations<TPixel>.Instance.ToVector4(background, backgroundSpan, destination.Length); |
|||
PixelOperations<TPixel>.Instance.ToVector4(source, sourceSpan, destination.Length); |
|||
|
|||
for (int i = 0; i < destination.Length; i++) |
|||
{ |
|||
destinationSpan[i] = PorterDuffFunctions.AddFunction(backgroundSpan[i], sourceSpan[i], amount[i]); |
|||
} |
|||
|
|||
PixelOperations<TPixel>.Instance.PackFromVector4(destinationSpan, destination, destination.Length); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -1,57 +0,0 @@ |
|||
// <copyright file="DefaultDarkenPixelBlender{TPixel}.cs" company="James Jackson-South">
|
|||
// Copyright (c) James Jackson-South and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
|
|||
namespace ImageSharp.PixelFormats.PixelBlenders |
|||
{ |
|||
using System; |
|||
using System.Numerics; |
|||
|
|||
using ImageSharp.Memory; |
|||
using ImageSharp.PixelFormats; |
|||
|
|||
/// <summary>
|
|||
/// Applies an "Darken" blending to pixels.
|
|||
/// </summary>
|
|||
/// <typeparam name="TPixel">The type of the pixel</typeparam>
|
|||
internal class DefaultDarkenPixelBlender<TPixel> : PixelBlender<TPixel> |
|||
where TPixel : struct, IPixel<TPixel> |
|||
{ |
|||
/// <summary>
|
|||
/// Gets the static instance of this blender.
|
|||
/// </summary>
|
|||
public static DefaultDarkenPixelBlender<TPixel> Instance { get; } = new DefaultDarkenPixelBlender<TPixel>(); |
|||
|
|||
/// <inheritdoc />
|
|||
public override TPixel Blend(TPixel background, TPixel source, float amount) |
|||
{ |
|||
return PorterDuffFunctions<TPixel>.DarkenFunction(background, source, amount); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public override void Blend(Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount) |
|||
{ |
|||
Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); |
|||
Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); |
|||
Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); |
|||
|
|||
using (Buffer<Vector4> buffer = new Buffer<Vector4>(destination.Length * 3)) |
|||
{ |
|||
Span<Vector4> destinationSpan = buffer.Slice(0, destination.Length); |
|||
Span<Vector4> backgroundSpan = buffer.Slice(destination.Length, destination.Length); |
|||
Span<Vector4> sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); |
|||
|
|||
PixelOperations<TPixel>.Instance.ToVector4(background, backgroundSpan, destination.Length); |
|||
PixelOperations<TPixel>.Instance.ToVector4(source, sourceSpan, destination.Length); |
|||
|
|||
for (int i = 0; i < destination.Length; i++) |
|||
{ |
|||
destinationSpan[i] = PorterDuffFunctions.DarkenFunction(backgroundSpan[i], sourceSpan[i], amount[i]); |
|||
} |
|||
|
|||
PixelOperations<TPixel>.Instance.PackFromVector4(destinationSpan, destination, destination.Length); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -1,57 +0,0 @@ |
|||
// <copyright file="DefaultHardLightPixelBlender{TPixel}.cs" company="James Jackson-South">
|
|||
// Copyright (c) James Jackson-South and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
|
|||
namespace ImageSharp.PixelFormats.PixelBlenders |
|||
{ |
|||
using System; |
|||
using System.Numerics; |
|||
|
|||
using ImageSharp.Memory; |
|||
using ImageSharp.PixelFormats; |
|||
|
|||
/// <summary>
|
|||
/// Applies an "Hard Light" blending to pixels.
|
|||
/// </summary>
|
|||
/// <typeparam name="TPixel">The type of the pixel</typeparam>
|
|||
internal class DefaultHardLightPixelBlender<TPixel> : PixelBlender<TPixel> |
|||
where TPixel : struct, IPixel<TPixel> |
|||
{ |
|||
/// <summary>
|
|||
/// Gets the static instance of this blender.
|
|||
/// </summary>
|
|||
public static DefaultHardLightPixelBlender<TPixel> Instance { get; } = new DefaultHardLightPixelBlender<TPixel>(); |
|||
|
|||
/// <inheritdoc />
|
|||
public override TPixel Blend(TPixel background, TPixel source, float amount) |
|||
{ |
|||
return PorterDuffFunctions<TPixel>.HardLightFunction(background, source, amount); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public override void Blend(Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount) |
|||
{ |
|||
Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); |
|||
Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); |
|||
Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); |
|||
|
|||
using (Buffer<Vector4> buffer = new Buffer<Vector4>(destination.Length * 3)) |
|||
{ |
|||
Span<Vector4> destinationSpan = buffer.Slice(0, destination.Length); |
|||
Span<Vector4> backgroundSpan = buffer.Slice(destination.Length, destination.Length); |
|||
Span<Vector4> sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); |
|||
|
|||
PixelOperations<TPixel>.Instance.ToVector4(background, backgroundSpan, destination.Length); |
|||
PixelOperations<TPixel>.Instance.ToVector4(source, sourceSpan, destination.Length); |
|||
|
|||
for (int i = 0; i < destination.Length; i++) |
|||
{ |
|||
destinationSpan[i] = PorterDuffFunctions.HardLightFunction(backgroundSpan[i], sourceSpan[i], amount[i]); |
|||
} |
|||
|
|||
PixelOperations<TPixel>.Instance.PackFromVector4(destinationSpan, destination, destination.Length); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -1,57 +0,0 @@ |
|||
// <copyright file="DefaultLightenPixelBlender{TPixel}.cs" company="James Jackson-South">
|
|||
// Copyright (c) James Jackson-South and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
|
|||
namespace ImageSharp.PixelFormats.PixelBlenders |
|||
{ |
|||
using System; |
|||
using System.Numerics; |
|||
|
|||
using ImageSharp.Memory; |
|||
using ImageSharp.PixelFormats; |
|||
|
|||
/// <summary>
|
|||
/// Applies an "Lighten" blending to pixels.
|
|||
/// </summary>
|
|||
/// <typeparam name="TPixel">The type of the pixel</typeparam>
|
|||
internal class DefaultLightenPixelBlender<TPixel> : PixelBlender<TPixel> |
|||
where TPixel : struct, IPixel<TPixel> |
|||
{ |
|||
/// <summary>
|
|||
/// Gets the static instance of this blender.
|
|||
/// </summary>
|
|||
public static DefaultLightenPixelBlender<TPixel> Instance { get; } = new DefaultLightenPixelBlender<TPixel>(); |
|||
|
|||
/// <inheritdoc />
|
|||
public override TPixel Blend(TPixel background, TPixel source, float amount) |
|||
{ |
|||
return PorterDuffFunctions<TPixel>.LightenFunction(background, source, amount); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public override void Blend(Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount) |
|||
{ |
|||
Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); |
|||
Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); |
|||
Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); |
|||
|
|||
using (Buffer<Vector4> buffer = new Buffer<Vector4>(destination.Length * 3)) |
|||
{ |
|||
Span<Vector4> destinationSpan = buffer.Slice(0, destination.Length); |
|||
Span<Vector4> backgroundSpan = buffer.Slice(destination.Length, destination.Length); |
|||
Span<Vector4> sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); |
|||
|
|||
PixelOperations<TPixel>.Instance.ToVector4(background, backgroundSpan, destination.Length); |
|||
PixelOperations<TPixel>.Instance.ToVector4(source, sourceSpan, destination.Length); |
|||
|
|||
for (int i = 0; i < destination.Length; i++) |
|||
{ |
|||
destinationSpan[i] = PorterDuffFunctions.LightenFunction(backgroundSpan[i], sourceSpan[i], amount[i]); |
|||
} |
|||
|
|||
PixelOperations<TPixel>.Instance.PackFromVector4(destinationSpan, destination, destination.Length); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -1,57 +0,0 @@ |
|||
// <copyright file="DefaultMultiplyPixelBlender{TPixel}.cs" company="James Jackson-South">
|
|||
// Copyright (c) James Jackson-South and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
|
|||
namespace ImageSharp.PixelFormats.PixelBlenders |
|||
{ |
|||
using System; |
|||
using System.Numerics; |
|||
|
|||
using ImageSharp.Memory; |
|||
using ImageSharp.PixelFormats; |
|||
|
|||
/// <summary>
|
|||
/// Applies an "Multiply" blending to pixels.
|
|||
/// </summary>
|
|||
/// <typeparam name="TPixel">The type of the pixel</typeparam>
|
|||
internal class DefaultMultiplyPixelBlender<TPixel> : PixelBlender<TPixel> |
|||
where TPixel : struct, IPixel<TPixel> |
|||
{ |
|||
/// <summary>
|
|||
/// Gets the static instance of this blender.
|
|||
/// </summary>
|
|||
public static DefaultMultiplyPixelBlender<TPixel> Instance { get; } = new DefaultMultiplyPixelBlender<TPixel>(); |
|||
|
|||
/// <inheritdoc />
|
|||
public override TPixel Blend(TPixel background, TPixel source, float amount) |
|||
{ |
|||
return PorterDuffFunctions<TPixel>.MultiplyFunction(background, source, amount); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public override void Blend(Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount) |
|||
{ |
|||
Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); |
|||
Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); |
|||
Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); |
|||
|
|||
using (Buffer<Vector4> buffer = new Buffer<Vector4>(destination.Length * 3)) |
|||
{ |
|||
Span<Vector4> destinationSpan = buffer.Slice(0, destination.Length); |
|||
Span<Vector4> backgroundSpan = buffer.Slice(destination.Length, destination.Length); |
|||
Span<Vector4> sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); |
|||
|
|||
PixelOperations<TPixel>.Instance.ToVector4(background, backgroundSpan, destination.Length); |
|||
PixelOperations<TPixel>.Instance.ToVector4(source, sourceSpan, destination.Length); |
|||
|
|||
for (int i = 0; i < destination.Length; i++) |
|||
{ |
|||
destinationSpan[i] = PorterDuffFunctions.MultiplyFunction(backgroundSpan[i], sourceSpan[i], amount[i]); |
|||
} |
|||
|
|||
PixelOperations<TPixel>.Instance.PackFromVector4(destinationSpan, destination, destination.Length); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -1,57 +0,0 @@ |
|||
// <copyright file="DefaultNormalPixelBlender{TPixel}.cs" company="James Jackson-South">
|
|||
// Copyright (c) James Jackson-South and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
|
|||
namespace ImageSharp.PixelFormats.PixelBlenders |
|||
{ |
|||
using System; |
|||
using System.Numerics; |
|||
|
|||
using ImageSharp.Memory; |
|||
using ImageSharp.PixelFormats; |
|||
|
|||
/// <summary>
|
|||
/// Applies a "Normal" otherwise nown as "Alpha Blending" blending to pixels.
|
|||
/// </summary>
|
|||
/// <typeparam name="TPixel">The type of the pixel</typeparam>
|
|||
internal class DefaultNormalPixelBlender<TPixel> : PixelBlender<TPixel> |
|||
where TPixel : struct, IPixel<TPixel> |
|||
{ |
|||
/// <summary>
|
|||
/// Gets the static instance of this blender.
|
|||
/// </summary>
|
|||
public static DefaultNormalPixelBlender<TPixel> Instance { get; } = new DefaultNormalPixelBlender<TPixel>(); |
|||
|
|||
/// <inheritdoc />
|
|||
public override TPixel Blend(TPixel background, TPixel source, float amount) |
|||
{ |
|||
return PorterDuffFunctions<TPixel>.NormalBlendFunction(background, source, amount); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public override void Blend(Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount) |
|||
{ |
|||
Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); |
|||
Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); |
|||
Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); |
|||
|
|||
using (Buffer<Vector4> buffer = new Buffer<Vector4>(destination.Length * 3)) |
|||
{ |
|||
Span<Vector4> destinationSpan = buffer.Slice(0, destination.Length); |
|||
Span<Vector4> backgroundSpan = buffer.Slice(destination.Length, destination.Length); |
|||
Span<Vector4> sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); |
|||
|
|||
PixelOperations<TPixel>.Instance.ToVector4(background, backgroundSpan, destination.Length); |
|||
PixelOperations<TPixel>.Instance.ToVector4(source, sourceSpan, destination.Length); |
|||
|
|||
for (int i = 0; i < destination.Length; i++) |
|||
{ |
|||
destinationSpan[i] = PorterDuffFunctions.NormalBlendFunction(backgroundSpan[i], sourceSpan[i], amount[i]); |
|||
} |
|||
|
|||
PixelOperations<TPixel>.Instance.PackFromVector4(destinationSpan, destination, destination.Length); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -1,57 +0,0 @@ |
|||
// <copyright file="DefaultOverlayPixelBlender{TPixel}.cs" company="James Jackson-South">
|
|||
// Copyright (c) James Jackson-South and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
|
|||
namespace ImageSharp.PixelFormats.PixelBlenders |
|||
{ |
|||
using System; |
|||
using System.Numerics; |
|||
|
|||
using ImageSharp.Memory; |
|||
using ImageSharp.PixelFormats; |
|||
|
|||
/// <summary>
|
|||
/// Applies an "Overlay" blending to pixels.
|
|||
/// </summary>
|
|||
/// <typeparam name="TPixel">The type of the pixel</typeparam>
|
|||
internal class DefaultOverlayPixelBlender<TPixel> : PixelBlender<TPixel> |
|||
where TPixel : struct, IPixel<TPixel> |
|||
{ |
|||
/// <summary>
|
|||
/// Gets the static instance of this blender.
|
|||
/// </summary>
|
|||
public static DefaultOverlayPixelBlender<TPixel> Instance { get; } = new DefaultOverlayPixelBlender<TPixel>(); |
|||
|
|||
/// <inheritdoc />
|
|||
public override TPixel Blend(TPixel background, TPixel source, float amount) |
|||
{ |
|||
return PorterDuffFunctions<TPixel>.OverlayFunction(background, source, amount); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public override void Blend(Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount) |
|||
{ |
|||
Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); |
|||
Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); |
|||
Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); |
|||
|
|||
using (Buffer<Vector4> buffer = new Buffer<Vector4>(destination.Length * 3)) |
|||
{ |
|||
Span<Vector4> destinationSpan = buffer.Slice(0, destination.Length); |
|||
Span<Vector4> backgroundSpan = buffer.Slice(destination.Length, destination.Length); |
|||
Span<Vector4> sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); |
|||
|
|||
PixelOperations<TPixel>.Instance.ToVector4(background, backgroundSpan, destination.Length); |
|||
PixelOperations<TPixel>.Instance.ToVector4(source, sourceSpan, destination.Length); |
|||
|
|||
for (int i = 0; i < destination.Length; i++) |
|||
{ |
|||
destinationSpan[i] = PorterDuffFunctions.OverlayFunction(backgroundSpan[i], sourceSpan[i], amount[i]); |
|||
} |
|||
|
|||
PixelOperations<TPixel>.Instance.PackFromVector4(destinationSpan, destination, destination.Length); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,849 @@ |
|||
// <autogenerated />
|
|||
// <copyright file="PorterDuffFunctions.Generated.cs" company="James Jackson-South">
|
|||
// Copyright (c) James Jackson-South and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
|
|||
namespace ImageSharp.PixelFormats.PixelBlenders |
|||
{ |
|||
using System; |
|||
using System.Numerics; |
|||
using ImageSharp.Memory; |
|||
|
|||
|
|||
/// <summary>
|
|||
/// Collection of Porter Duff alpha blending functions applying different composition models.
|
|||
/// </summary>
|
|||
/// <remarks>
|
|||
/// These functions are designed to be a general solution for all color cases,
|
|||
/// that is, they take in account the alpha value of both the backdrop
|
|||
/// and source, and there's no need to alpha-premultiply neither the backdrop
|
|||
/// nor the source.
|
|||
/// Note there are faster functions for when the backdrop color is known
|
|||
/// to be opaque
|
|||
/// </remarks>
|
|||
internal static class DefaultPixelBlenders<TPixel> |
|||
where TPixel : struct, IPixel<TPixel> |
|||
{ |
|||
|
|||
internal class Normal : PixelBlender<TPixel> |
|||
{ |
|||
|
|||
/// <summary>
|
|||
/// Gets the static instance of this blender.
|
|||
/// </summary>
|
|||
public static Normal Instance { get; } = new Normal(); |
|||
|
|||
/// <inheritdoc />
|
|||
public override TPixel Blend(TPixel background, TPixel source, float amount) |
|||
{ |
|||
return PorterDuffFunctions.Normal(background, source, amount); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public override void Blend(Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount) |
|||
{ |
|||
Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); |
|||
Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); |
|||
Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); |
|||
|
|||
using (Buffer<Vector4> buffer = new Buffer<Vector4>(destination.Length * 3)) |
|||
{ |
|||
Span<Vector4> destinationSpan = buffer.Slice(0, destination.Length); |
|||
Span<Vector4> backgroundSpan = buffer.Slice(destination.Length, destination.Length); |
|||
Span<Vector4> sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); |
|||
|
|||
PixelOperations<TPixel>.Instance.ToVector4(background, backgroundSpan, destination.Length); |
|||
PixelOperations<TPixel>.Instance.ToVector4(source, sourceSpan, destination.Length); |
|||
|
|||
for (int i = 0; i < destination.Length; i++) |
|||
{ |
|||
destinationSpan[i] = PorterDuffFunctions.Normal(backgroundSpan[i], sourceSpan[i], amount[i]); |
|||
} |
|||
|
|||
PixelOperations<TPixel>.Instance.PackFromVector4(destinationSpan, destination, destination.Length); |
|||
} |
|||
} |
|||
} |
|||
internal class Multiply : PixelBlender<TPixel> |
|||
{ |
|||
|
|||
/// <summary>
|
|||
/// Gets the static instance of this blender.
|
|||
/// </summary>
|
|||
public static Multiply Instance { get; } = new Multiply(); |
|||
|
|||
/// <inheritdoc />
|
|||
public override TPixel Blend(TPixel background, TPixel source, float amount) |
|||
{ |
|||
return PorterDuffFunctions.Multiply(background, source, amount); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public override void Blend(Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount) |
|||
{ |
|||
Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); |
|||
Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); |
|||
Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); |
|||
|
|||
using (Buffer<Vector4> buffer = new Buffer<Vector4>(destination.Length * 3)) |
|||
{ |
|||
Span<Vector4> destinationSpan = buffer.Slice(0, destination.Length); |
|||
Span<Vector4> backgroundSpan = buffer.Slice(destination.Length, destination.Length); |
|||
Span<Vector4> sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); |
|||
|
|||
PixelOperations<TPixel>.Instance.ToVector4(background, backgroundSpan, destination.Length); |
|||
PixelOperations<TPixel>.Instance.ToVector4(source, sourceSpan, destination.Length); |
|||
|
|||
for (int i = 0; i < destination.Length; i++) |
|||
{ |
|||
destinationSpan[i] = PorterDuffFunctions.Multiply(backgroundSpan[i], sourceSpan[i], amount[i]); |
|||
} |
|||
|
|||
PixelOperations<TPixel>.Instance.PackFromVector4(destinationSpan, destination, destination.Length); |
|||
} |
|||
} |
|||
} |
|||
internal class Add : PixelBlender<TPixel> |
|||
{ |
|||
|
|||
/// <summary>
|
|||
/// Gets the static instance of this blender.
|
|||
/// </summary>
|
|||
public static Add Instance { get; } = new Add(); |
|||
|
|||
/// <inheritdoc />
|
|||
public override TPixel Blend(TPixel background, TPixel source, float amount) |
|||
{ |
|||
return PorterDuffFunctions.Add(background, source, amount); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public override void Blend(Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount) |
|||
{ |
|||
Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); |
|||
Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); |
|||
Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); |
|||
|
|||
using (Buffer<Vector4> buffer = new Buffer<Vector4>(destination.Length * 3)) |
|||
{ |
|||
Span<Vector4> destinationSpan = buffer.Slice(0, destination.Length); |
|||
Span<Vector4> backgroundSpan = buffer.Slice(destination.Length, destination.Length); |
|||
Span<Vector4> sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); |
|||
|
|||
PixelOperations<TPixel>.Instance.ToVector4(background, backgroundSpan, destination.Length); |
|||
PixelOperations<TPixel>.Instance.ToVector4(source, sourceSpan, destination.Length); |
|||
|
|||
for (int i = 0; i < destination.Length; i++) |
|||
{ |
|||
destinationSpan[i] = PorterDuffFunctions.Add(backgroundSpan[i], sourceSpan[i], amount[i]); |
|||
} |
|||
|
|||
PixelOperations<TPixel>.Instance.PackFromVector4(destinationSpan, destination, destination.Length); |
|||
} |
|||
} |
|||
} |
|||
internal class Substract : PixelBlender<TPixel> |
|||
{ |
|||
|
|||
/// <summary>
|
|||
/// Gets the static instance of this blender.
|
|||
/// </summary>
|
|||
public static Substract Instance { get; } = new Substract(); |
|||
|
|||
/// <inheritdoc />
|
|||
public override TPixel Blend(TPixel background, TPixel source, float amount) |
|||
{ |
|||
return PorterDuffFunctions.Substract(background, source, amount); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public override void Blend(Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount) |
|||
{ |
|||
Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); |
|||
Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); |
|||
Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); |
|||
|
|||
using (Buffer<Vector4> buffer = new Buffer<Vector4>(destination.Length * 3)) |
|||
{ |
|||
Span<Vector4> destinationSpan = buffer.Slice(0, destination.Length); |
|||
Span<Vector4> backgroundSpan = buffer.Slice(destination.Length, destination.Length); |
|||
Span<Vector4> sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); |
|||
|
|||
PixelOperations<TPixel>.Instance.ToVector4(background, backgroundSpan, destination.Length); |
|||
PixelOperations<TPixel>.Instance.ToVector4(source, sourceSpan, destination.Length); |
|||
|
|||
for (int i = 0; i < destination.Length; i++) |
|||
{ |
|||
destinationSpan[i] = PorterDuffFunctions.Substract(backgroundSpan[i], sourceSpan[i], amount[i]); |
|||
} |
|||
|
|||
PixelOperations<TPixel>.Instance.PackFromVector4(destinationSpan, destination, destination.Length); |
|||
} |
|||
} |
|||
} |
|||
internal class Screen : PixelBlender<TPixel> |
|||
{ |
|||
|
|||
/// <summary>
|
|||
/// Gets the static instance of this blender.
|
|||
/// </summary>
|
|||
public static Screen Instance { get; } = new Screen(); |
|||
|
|||
/// <inheritdoc />
|
|||
public override TPixel Blend(TPixel background, TPixel source, float amount) |
|||
{ |
|||
return PorterDuffFunctions.Screen(background, source, amount); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public override void Blend(Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount) |
|||
{ |
|||
Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); |
|||
Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); |
|||
Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); |
|||
|
|||
using (Buffer<Vector4> buffer = new Buffer<Vector4>(destination.Length * 3)) |
|||
{ |
|||
Span<Vector4> destinationSpan = buffer.Slice(0, destination.Length); |
|||
Span<Vector4> backgroundSpan = buffer.Slice(destination.Length, destination.Length); |
|||
Span<Vector4> sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); |
|||
|
|||
PixelOperations<TPixel>.Instance.ToVector4(background, backgroundSpan, destination.Length); |
|||
PixelOperations<TPixel>.Instance.ToVector4(source, sourceSpan, destination.Length); |
|||
|
|||
for (int i = 0; i < destination.Length; i++) |
|||
{ |
|||
destinationSpan[i] = PorterDuffFunctions.Screen(backgroundSpan[i], sourceSpan[i], amount[i]); |
|||
} |
|||
|
|||
PixelOperations<TPixel>.Instance.PackFromVector4(destinationSpan, destination, destination.Length); |
|||
} |
|||
} |
|||
} |
|||
internal class Darken : PixelBlender<TPixel> |
|||
{ |
|||
|
|||
/// <summary>
|
|||
/// Gets the static instance of this blender.
|
|||
/// </summary>
|
|||
public static Darken Instance { get; } = new Darken(); |
|||
|
|||
/// <inheritdoc />
|
|||
public override TPixel Blend(TPixel background, TPixel source, float amount) |
|||
{ |
|||
return PorterDuffFunctions.Darken(background, source, amount); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public override void Blend(Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount) |
|||
{ |
|||
Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); |
|||
Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); |
|||
Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); |
|||
|
|||
using (Buffer<Vector4> buffer = new Buffer<Vector4>(destination.Length * 3)) |
|||
{ |
|||
Span<Vector4> destinationSpan = buffer.Slice(0, destination.Length); |
|||
Span<Vector4> backgroundSpan = buffer.Slice(destination.Length, destination.Length); |
|||
Span<Vector4> sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); |
|||
|
|||
PixelOperations<TPixel>.Instance.ToVector4(background, backgroundSpan, destination.Length); |
|||
PixelOperations<TPixel>.Instance.ToVector4(source, sourceSpan, destination.Length); |
|||
|
|||
for (int i = 0; i < destination.Length; i++) |
|||
{ |
|||
destinationSpan[i] = PorterDuffFunctions.Darken(backgroundSpan[i], sourceSpan[i], amount[i]); |
|||
} |
|||
|
|||
PixelOperations<TPixel>.Instance.PackFromVector4(destinationSpan, destination, destination.Length); |
|||
} |
|||
} |
|||
} |
|||
internal class Lighten : PixelBlender<TPixel> |
|||
{ |
|||
|
|||
/// <summary>
|
|||
/// Gets the static instance of this blender.
|
|||
/// </summary>
|
|||
public static Lighten Instance { get; } = new Lighten(); |
|||
|
|||
/// <inheritdoc />
|
|||
public override TPixel Blend(TPixel background, TPixel source, float amount) |
|||
{ |
|||
return PorterDuffFunctions.Lighten(background, source, amount); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public override void Blend(Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount) |
|||
{ |
|||
Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); |
|||
Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); |
|||
Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); |
|||
|
|||
using (Buffer<Vector4> buffer = new Buffer<Vector4>(destination.Length * 3)) |
|||
{ |
|||
Span<Vector4> destinationSpan = buffer.Slice(0, destination.Length); |
|||
Span<Vector4> backgroundSpan = buffer.Slice(destination.Length, destination.Length); |
|||
Span<Vector4> sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); |
|||
|
|||
PixelOperations<TPixel>.Instance.ToVector4(background, backgroundSpan, destination.Length); |
|||
PixelOperations<TPixel>.Instance.ToVector4(source, sourceSpan, destination.Length); |
|||
|
|||
for (int i = 0; i < destination.Length; i++) |
|||
{ |
|||
destinationSpan[i] = PorterDuffFunctions.Lighten(backgroundSpan[i], sourceSpan[i], amount[i]); |
|||
} |
|||
|
|||
PixelOperations<TPixel>.Instance.PackFromVector4(destinationSpan, destination, destination.Length); |
|||
} |
|||
} |
|||
} |
|||
internal class Overlay : PixelBlender<TPixel> |
|||
{ |
|||
|
|||
/// <summary>
|
|||
/// Gets the static instance of this blender.
|
|||
/// </summary>
|
|||
public static Overlay Instance { get; } = new Overlay(); |
|||
|
|||
/// <inheritdoc />
|
|||
public override TPixel Blend(TPixel background, TPixel source, float amount) |
|||
{ |
|||
return PorterDuffFunctions.Overlay(background, source, amount); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public override void Blend(Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount) |
|||
{ |
|||
Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); |
|||
Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); |
|||
Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); |
|||
|
|||
using (Buffer<Vector4> buffer = new Buffer<Vector4>(destination.Length * 3)) |
|||
{ |
|||
Span<Vector4> destinationSpan = buffer.Slice(0, destination.Length); |
|||
Span<Vector4> backgroundSpan = buffer.Slice(destination.Length, destination.Length); |
|||
Span<Vector4> sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); |
|||
|
|||
PixelOperations<TPixel>.Instance.ToVector4(background, backgroundSpan, destination.Length); |
|||
PixelOperations<TPixel>.Instance.ToVector4(source, sourceSpan, destination.Length); |
|||
|
|||
for (int i = 0; i < destination.Length; i++) |
|||
{ |
|||
destinationSpan[i] = PorterDuffFunctions.Overlay(backgroundSpan[i], sourceSpan[i], amount[i]); |
|||
} |
|||
|
|||
PixelOperations<TPixel>.Instance.PackFromVector4(destinationSpan, destination, destination.Length); |
|||
} |
|||
} |
|||
} |
|||
internal class HardLight : PixelBlender<TPixel> |
|||
{ |
|||
|
|||
/// <summary>
|
|||
/// Gets the static instance of this blender.
|
|||
/// </summary>
|
|||
public static HardLight Instance { get; } = new HardLight(); |
|||
|
|||
/// <inheritdoc />
|
|||
public override TPixel Blend(TPixel background, TPixel source, float amount) |
|||
{ |
|||
return PorterDuffFunctions.HardLight(background, source, amount); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public override void Blend(Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount) |
|||
{ |
|||
Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); |
|||
Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); |
|||
Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); |
|||
|
|||
using (Buffer<Vector4> buffer = new Buffer<Vector4>(destination.Length * 3)) |
|||
{ |
|||
Span<Vector4> destinationSpan = buffer.Slice(0, destination.Length); |
|||
Span<Vector4> backgroundSpan = buffer.Slice(destination.Length, destination.Length); |
|||
Span<Vector4> sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); |
|||
|
|||
PixelOperations<TPixel>.Instance.ToVector4(background, backgroundSpan, destination.Length); |
|||
PixelOperations<TPixel>.Instance.ToVector4(source, sourceSpan, destination.Length); |
|||
|
|||
for (int i = 0; i < destination.Length; i++) |
|||
{ |
|||
destinationSpan[i] = PorterDuffFunctions.HardLight(backgroundSpan[i], sourceSpan[i], amount[i]); |
|||
} |
|||
|
|||
PixelOperations<TPixel>.Instance.PackFromVector4(destinationSpan, destination, destination.Length); |
|||
} |
|||
} |
|||
} |
|||
internal class Src : PixelBlender<TPixel> |
|||
{ |
|||
|
|||
/// <summary>
|
|||
/// Gets the static instance of this blender.
|
|||
/// </summary>
|
|||
public static Src Instance { get; } = new Src(); |
|||
|
|||
/// <inheritdoc />
|
|||
public override TPixel Blend(TPixel background, TPixel source, float amount) |
|||
{ |
|||
return PorterDuffFunctions.Src(background, source, amount); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public override void Blend(Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount) |
|||
{ |
|||
Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); |
|||
Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); |
|||
Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); |
|||
|
|||
using (Buffer<Vector4> buffer = new Buffer<Vector4>(destination.Length * 3)) |
|||
{ |
|||
Span<Vector4> destinationSpan = buffer.Slice(0, destination.Length); |
|||
Span<Vector4> backgroundSpan = buffer.Slice(destination.Length, destination.Length); |
|||
Span<Vector4> sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); |
|||
|
|||
PixelOperations<TPixel>.Instance.ToVector4(background, backgroundSpan, destination.Length); |
|||
PixelOperations<TPixel>.Instance.ToVector4(source, sourceSpan, destination.Length); |
|||
|
|||
for (int i = 0; i < destination.Length; i++) |
|||
{ |
|||
destinationSpan[i] = PorterDuffFunctions.Src(backgroundSpan[i], sourceSpan[i], amount[i]); |
|||
} |
|||
|
|||
PixelOperations<TPixel>.Instance.PackFromVector4(destinationSpan, destination, destination.Length); |
|||
} |
|||
} |
|||
} |
|||
internal class Atop : PixelBlender<TPixel> |
|||
{ |
|||
|
|||
/// <summary>
|
|||
/// Gets the static instance of this blender.
|
|||
/// </summary>
|
|||
public static Atop Instance { get; } = new Atop(); |
|||
|
|||
/// <inheritdoc />
|
|||
public override TPixel Blend(TPixel background, TPixel source, float amount) |
|||
{ |
|||
return PorterDuffFunctions.Atop(background, source, amount); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public override void Blend(Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount) |
|||
{ |
|||
Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); |
|||
Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); |
|||
Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); |
|||
|
|||
using (Buffer<Vector4> buffer = new Buffer<Vector4>(destination.Length * 3)) |
|||
{ |
|||
Span<Vector4> destinationSpan = buffer.Slice(0, destination.Length); |
|||
Span<Vector4> backgroundSpan = buffer.Slice(destination.Length, destination.Length); |
|||
Span<Vector4> sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); |
|||
|
|||
PixelOperations<TPixel>.Instance.ToVector4(background, backgroundSpan, destination.Length); |
|||
PixelOperations<TPixel>.Instance.ToVector4(source, sourceSpan, destination.Length); |
|||
|
|||
for (int i = 0; i < destination.Length; i++) |
|||
{ |
|||
destinationSpan[i] = PorterDuffFunctions.Atop(backgroundSpan[i], sourceSpan[i], amount[i]); |
|||
} |
|||
|
|||
PixelOperations<TPixel>.Instance.PackFromVector4(destinationSpan, destination, destination.Length); |
|||
} |
|||
} |
|||
} |
|||
internal class Over : PixelBlender<TPixel> |
|||
{ |
|||
|
|||
/// <summary>
|
|||
/// Gets the static instance of this blender.
|
|||
/// </summary>
|
|||
public static Over Instance { get; } = new Over(); |
|||
|
|||
/// <inheritdoc />
|
|||
public override TPixel Blend(TPixel background, TPixel source, float amount) |
|||
{ |
|||
return PorterDuffFunctions.Over(background, source, amount); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public override void Blend(Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount) |
|||
{ |
|||
Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); |
|||
Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); |
|||
Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); |
|||
|
|||
using (Buffer<Vector4> buffer = new Buffer<Vector4>(destination.Length * 3)) |
|||
{ |
|||
Span<Vector4> destinationSpan = buffer.Slice(0, destination.Length); |
|||
Span<Vector4> backgroundSpan = buffer.Slice(destination.Length, destination.Length); |
|||
Span<Vector4> sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); |
|||
|
|||
PixelOperations<TPixel>.Instance.ToVector4(background, backgroundSpan, destination.Length); |
|||
PixelOperations<TPixel>.Instance.ToVector4(source, sourceSpan, destination.Length); |
|||
|
|||
for (int i = 0; i < destination.Length; i++) |
|||
{ |
|||
destinationSpan[i] = PorterDuffFunctions.Over(backgroundSpan[i], sourceSpan[i], amount[i]); |
|||
} |
|||
|
|||
PixelOperations<TPixel>.Instance.PackFromVector4(destinationSpan, destination, destination.Length); |
|||
} |
|||
} |
|||
} |
|||
internal class In : PixelBlender<TPixel> |
|||
{ |
|||
|
|||
/// <summary>
|
|||
/// Gets the static instance of this blender.
|
|||
/// </summary>
|
|||
public static In Instance { get; } = new In(); |
|||
|
|||
/// <inheritdoc />
|
|||
public override TPixel Blend(TPixel background, TPixel source, float amount) |
|||
{ |
|||
return PorterDuffFunctions.In(background, source, amount); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public override void Blend(Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount) |
|||
{ |
|||
Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); |
|||
Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); |
|||
Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); |
|||
|
|||
using (Buffer<Vector4> buffer = new Buffer<Vector4>(destination.Length * 3)) |
|||
{ |
|||
Span<Vector4> destinationSpan = buffer.Slice(0, destination.Length); |
|||
Span<Vector4> backgroundSpan = buffer.Slice(destination.Length, destination.Length); |
|||
Span<Vector4> sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); |
|||
|
|||
PixelOperations<TPixel>.Instance.ToVector4(background, backgroundSpan, destination.Length); |
|||
PixelOperations<TPixel>.Instance.ToVector4(source, sourceSpan, destination.Length); |
|||
|
|||
for (int i = 0; i < destination.Length; i++) |
|||
{ |
|||
destinationSpan[i] = PorterDuffFunctions.In(backgroundSpan[i], sourceSpan[i], amount[i]); |
|||
} |
|||
|
|||
PixelOperations<TPixel>.Instance.PackFromVector4(destinationSpan, destination, destination.Length); |
|||
} |
|||
} |
|||
} |
|||
internal class Out : PixelBlender<TPixel> |
|||
{ |
|||
|
|||
/// <summary>
|
|||
/// Gets the static instance of this blender.
|
|||
/// </summary>
|
|||
public static Out Instance { get; } = new Out(); |
|||
|
|||
/// <inheritdoc />
|
|||
public override TPixel Blend(TPixel background, TPixel source, float amount) |
|||
{ |
|||
return PorterDuffFunctions.Out(background, source, amount); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public override void Blend(Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount) |
|||
{ |
|||
Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); |
|||
Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); |
|||
Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); |
|||
|
|||
using (Buffer<Vector4> buffer = new Buffer<Vector4>(destination.Length * 3)) |
|||
{ |
|||
Span<Vector4> destinationSpan = buffer.Slice(0, destination.Length); |
|||
Span<Vector4> backgroundSpan = buffer.Slice(destination.Length, destination.Length); |
|||
Span<Vector4> sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); |
|||
|
|||
PixelOperations<TPixel>.Instance.ToVector4(background, backgroundSpan, destination.Length); |
|||
PixelOperations<TPixel>.Instance.ToVector4(source, sourceSpan, destination.Length); |
|||
|
|||
for (int i = 0; i < destination.Length; i++) |
|||
{ |
|||
destinationSpan[i] = PorterDuffFunctions.Out(backgroundSpan[i], sourceSpan[i], amount[i]); |
|||
} |
|||
|
|||
PixelOperations<TPixel>.Instance.PackFromVector4(destinationSpan, destination, destination.Length); |
|||
} |
|||
} |
|||
} |
|||
internal class Dest : PixelBlender<TPixel> |
|||
{ |
|||
|
|||
/// <summary>
|
|||
/// Gets the static instance of this blender.
|
|||
/// </summary>
|
|||
public static Dest Instance { get; } = new Dest(); |
|||
|
|||
/// <inheritdoc />
|
|||
public override TPixel Blend(TPixel background, TPixel source, float amount) |
|||
{ |
|||
return PorterDuffFunctions.Dest(background, source, amount); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public override void Blend(Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount) |
|||
{ |
|||
Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); |
|||
Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); |
|||
Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); |
|||
|
|||
using (Buffer<Vector4> buffer = new Buffer<Vector4>(destination.Length * 3)) |
|||
{ |
|||
Span<Vector4> destinationSpan = buffer.Slice(0, destination.Length); |
|||
Span<Vector4> backgroundSpan = buffer.Slice(destination.Length, destination.Length); |
|||
Span<Vector4> sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); |
|||
|
|||
PixelOperations<TPixel>.Instance.ToVector4(background, backgroundSpan, destination.Length); |
|||
PixelOperations<TPixel>.Instance.ToVector4(source, sourceSpan, destination.Length); |
|||
|
|||
for (int i = 0; i < destination.Length; i++) |
|||
{ |
|||
destinationSpan[i] = PorterDuffFunctions.Dest(backgroundSpan[i], sourceSpan[i], amount[i]); |
|||
} |
|||
|
|||
PixelOperations<TPixel>.Instance.PackFromVector4(destinationSpan, destination, destination.Length); |
|||
} |
|||
} |
|||
} |
|||
internal class DestAtop : PixelBlender<TPixel> |
|||
{ |
|||
|
|||
/// <summary>
|
|||
/// Gets the static instance of this blender.
|
|||
/// </summary>
|
|||
public static DestAtop Instance { get; } = new DestAtop(); |
|||
|
|||
/// <inheritdoc />
|
|||
public override TPixel Blend(TPixel background, TPixel source, float amount) |
|||
{ |
|||
return PorterDuffFunctions.DestAtop(background, source, amount); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public override void Blend(Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount) |
|||
{ |
|||
Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); |
|||
Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); |
|||
Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); |
|||
|
|||
using (Buffer<Vector4> buffer = new Buffer<Vector4>(destination.Length * 3)) |
|||
{ |
|||
Span<Vector4> destinationSpan = buffer.Slice(0, destination.Length); |
|||
Span<Vector4> backgroundSpan = buffer.Slice(destination.Length, destination.Length); |
|||
Span<Vector4> sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); |
|||
|
|||
PixelOperations<TPixel>.Instance.ToVector4(background, backgroundSpan, destination.Length); |
|||
PixelOperations<TPixel>.Instance.ToVector4(source, sourceSpan, destination.Length); |
|||
|
|||
for (int i = 0; i < destination.Length; i++) |
|||
{ |
|||
destinationSpan[i] = PorterDuffFunctions.DestAtop(backgroundSpan[i], sourceSpan[i], amount[i]); |
|||
} |
|||
|
|||
PixelOperations<TPixel>.Instance.PackFromVector4(destinationSpan, destination, destination.Length); |
|||
} |
|||
} |
|||
} |
|||
internal class DestOver : PixelBlender<TPixel> |
|||
{ |
|||
|
|||
/// <summary>
|
|||
/// Gets the static instance of this blender.
|
|||
/// </summary>
|
|||
public static DestOver Instance { get; } = new DestOver(); |
|||
|
|||
/// <inheritdoc />
|
|||
public override TPixel Blend(TPixel background, TPixel source, float amount) |
|||
{ |
|||
return PorterDuffFunctions.DestOver(background, source, amount); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public override void Blend(Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount) |
|||
{ |
|||
Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); |
|||
Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); |
|||
Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); |
|||
|
|||
using (Buffer<Vector4> buffer = new Buffer<Vector4>(destination.Length * 3)) |
|||
{ |
|||
Span<Vector4> destinationSpan = buffer.Slice(0, destination.Length); |
|||
Span<Vector4> backgroundSpan = buffer.Slice(destination.Length, destination.Length); |
|||
Span<Vector4> sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); |
|||
|
|||
PixelOperations<TPixel>.Instance.ToVector4(background, backgroundSpan, destination.Length); |
|||
PixelOperations<TPixel>.Instance.ToVector4(source, sourceSpan, destination.Length); |
|||
|
|||
for (int i = 0; i < destination.Length; i++) |
|||
{ |
|||
destinationSpan[i] = PorterDuffFunctions.DestOver(backgroundSpan[i], sourceSpan[i], amount[i]); |
|||
} |
|||
|
|||
PixelOperations<TPixel>.Instance.PackFromVector4(destinationSpan, destination, destination.Length); |
|||
} |
|||
} |
|||
} |
|||
internal class DestIn : PixelBlender<TPixel> |
|||
{ |
|||
|
|||
/// <summary>
|
|||
/// Gets the static instance of this blender.
|
|||
/// </summary>
|
|||
public static DestIn Instance { get; } = new DestIn(); |
|||
|
|||
/// <inheritdoc />
|
|||
public override TPixel Blend(TPixel background, TPixel source, float amount) |
|||
{ |
|||
return PorterDuffFunctions.DestIn(background, source, amount); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public override void Blend(Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount) |
|||
{ |
|||
Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); |
|||
Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); |
|||
Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); |
|||
|
|||
using (Buffer<Vector4> buffer = new Buffer<Vector4>(destination.Length * 3)) |
|||
{ |
|||
Span<Vector4> destinationSpan = buffer.Slice(0, destination.Length); |
|||
Span<Vector4> backgroundSpan = buffer.Slice(destination.Length, destination.Length); |
|||
Span<Vector4> sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); |
|||
|
|||
PixelOperations<TPixel>.Instance.ToVector4(background, backgroundSpan, destination.Length); |
|||
PixelOperations<TPixel>.Instance.ToVector4(source, sourceSpan, destination.Length); |
|||
|
|||
for (int i = 0; i < destination.Length; i++) |
|||
{ |
|||
destinationSpan[i] = PorterDuffFunctions.DestIn(backgroundSpan[i], sourceSpan[i], amount[i]); |
|||
} |
|||
|
|||
PixelOperations<TPixel>.Instance.PackFromVector4(destinationSpan, destination, destination.Length); |
|||
} |
|||
} |
|||
} |
|||
internal class DestOut : PixelBlender<TPixel> |
|||
{ |
|||
|
|||
/// <summary>
|
|||
/// Gets the static instance of this blender.
|
|||
/// </summary>
|
|||
public static DestOut Instance { get; } = new DestOut(); |
|||
|
|||
/// <inheritdoc />
|
|||
public override TPixel Blend(TPixel background, TPixel source, float amount) |
|||
{ |
|||
return PorterDuffFunctions.DestOut(background, source, amount); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public override void Blend(Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount) |
|||
{ |
|||
Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); |
|||
Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); |
|||
Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); |
|||
|
|||
using (Buffer<Vector4> buffer = new Buffer<Vector4>(destination.Length * 3)) |
|||
{ |
|||
Span<Vector4> destinationSpan = buffer.Slice(0, destination.Length); |
|||
Span<Vector4> backgroundSpan = buffer.Slice(destination.Length, destination.Length); |
|||
Span<Vector4> sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); |
|||
|
|||
PixelOperations<TPixel>.Instance.ToVector4(background, backgroundSpan, destination.Length); |
|||
PixelOperations<TPixel>.Instance.ToVector4(source, sourceSpan, destination.Length); |
|||
|
|||
for (int i = 0; i < destination.Length; i++) |
|||
{ |
|||
destinationSpan[i] = PorterDuffFunctions.DestOut(backgroundSpan[i], sourceSpan[i], amount[i]); |
|||
} |
|||
|
|||
PixelOperations<TPixel>.Instance.PackFromVector4(destinationSpan, destination, destination.Length); |
|||
} |
|||
} |
|||
} |
|||
internal class Clear : PixelBlender<TPixel> |
|||
{ |
|||
|
|||
/// <summary>
|
|||
/// Gets the static instance of this blender.
|
|||
/// </summary>
|
|||
public static Clear Instance { get; } = new Clear(); |
|||
|
|||
/// <inheritdoc />
|
|||
public override TPixel Blend(TPixel background, TPixel source, float amount) |
|||
{ |
|||
return PorterDuffFunctions.Clear(background, source, amount); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public override void Blend(Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount) |
|||
{ |
|||
Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); |
|||
Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); |
|||
Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); |
|||
|
|||
using (Buffer<Vector4> buffer = new Buffer<Vector4>(destination.Length * 3)) |
|||
{ |
|||
Span<Vector4> destinationSpan = buffer.Slice(0, destination.Length); |
|||
Span<Vector4> backgroundSpan = buffer.Slice(destination.Length, destination.Length); |
|||
Span<Vector4> sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); |
|||
|
|||
PixelOperations<TPixel>.Instance.ToVector4(background, backgroundSpan, destination.Length); |
|||
PixelOperations<TPixel>.Instance.ToVector4(source, sourceSpan, destination.Length); |
|||
|
|||
for (int i = 0; i < destination.Length; i++) |
|||
{ |
|||
destinationSpan[i] = PorterDuffFunctions.Clear(backgroundSpan[i], sourceSpan[i], amount[i]); |
|||
} |
|||
|
|||
PixelOperations<TPixel>.Instance.PackFromVector4(destinationSpan, destination, destination.Length); |
|||
} |
|||
} |
|||
} |
|||
internal class Xor : PixelBlender<TPixel> |
|||
{ |
|||
|
|||
/// <summary>
|
|||
/// Gets the static instance of this blender.
|
|||
/// </summary>
|
|||
public static Xor Instance { get; } = new Xor(); |
|||
|
|||
/// <inheritdoc />
|
|||
public override TPixel Blend(TPixel background, TPixel source, float amount) |
|||
{ |
|||
return PorterDuffFunctions.Xor(background, source, amount); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public override void Blend(Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount) |
|||
{ |
|||
Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); |
|||
Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); |
|||
Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); |
|||
|
|||
using (Buffer<Vector4> buffer = new Buffer<Vector4>(destination.Length * 3)) |
|||
{ |
|||
Span<Vector4> destinationSpan = buffer.Slice(0, destination.Length); |
|||
Span<Vector4> backgroundSpan = buffer.Slice(destination.Length, destination.Length); |
|||
Span<Vector4> sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); |
|||
|
|||
PixelOperations<TPixel>.Instance.ToVector4(background, backgroundSpan, destination.Length); |
|||
PixelOperations<TPixel>.Instance.ToVector4(source, sourceSpan, destination.Length); |
|||
|
|||
for (int i = 0; i < destination.Length; i++) |
|||
{ |
|||
destinationSpan[i] = PorterDuffFunctions.Xor(backgroundSpan[i], sourceSpan[i], amount[i]); |
|||
} |
|||
|
|||
PixelOperations<TPixel>.Instance.PackFromVector4(destinationSpan, destination, destination.Length); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,118 @@ |
|||
<# |
|||
// <copyright file="DefaultPixelBlenders.Generated.tt" company="James Jackson-South"> |
|||
// Copyright (c) James Jackson-South and contributors. |
|||
// Licensed under the Apache License, Version 2.0. |
|||
// </copyright> |
|||
#> |
|||
<#@ template debug="false" hostspecific="false" language="C#" #> |
|||
<#@ assembly name="System.Core" #> |
|||
<#@ import namespace="System.Linq" #> |
|||
<#@ import namespace="System.Text" #> |
|||
<#@ import namespace="System.Collections.Generic" #> |
|||
<#@ output extension=".cs" #> |
|||
// <autogenerated /> |
|||
// <copyright file="PorterDuffFunctions.Generated.cs" company="James Jackson-South"> |
|||
// Copyright (c) James Jackson-South and contributors. |
|||
// Licensed under the Apache License, Version 2.0. |
|||
// </copyright> |
|||
|
|||
namespace ImageSharp.PixelFormats.PixelBlenders |
|||
{ |
|||
using System; |
|||
using System.Numerics; |
|||
using ImageSharp.Memory; |
|||
|
|||
|
|||
/// <summary> |
|||
/// Collection of Porter Duff alpha blending functions applying different composition models. |
|||
/// </summary> |
|||
/// <remarks> |
|||
/// These functions are designed to be a general solution for all color cases, |
|||
/// that is, they take in account the alpha value of both the backdrop |
|||
/// and source, and there's no need to alpha-premultiply neither the backdrop |
|||
/// nor the source. |
|||
/// Note there are faster functions for when the backdrop color is known |
|||
/// to be opaque |
|||
/// </remarks> |
|||
internal static class DefaultPixelBlenders<TPixel> |
|||
where TPixel : struct, IPixel<TPixel> |
|||
{ |
|||
|
|||
<# |
|||
|
|||
|
|||
|
|||
string[] blenders = new []{ |
|||
"Normal", |
|||
"Multiply", |
|||
"Add", |
|||
"Substract", |
|||
"Screen", |
|||
"Darken", |
|||
"Lighten", |
|||
"Overlay", |
|||
"HardLight", |
|||
"Src" , |
|||
"Atop" , |
|||
"Over" , |
|||
"In" , |
|||
"Out" , |
|||
"Dest" , |
|||
"DestAtop" , |
|||
"DestOver" , |
|||
"DestIn" , |
|||
"DestOut" , |
|||
"Clear" , |
|||
"Xor" , |
|||
}; |
|||
|
|||
|
|||
|
|||
foreach(var blender in blenders) { |
|||
#> |
|||
internal class <#=blender#> : PixelBlender<TPixel> |
|||
{ |
|||
|
|||
/// <summary> |
|||
/// Gets the static instance of this blender. |
|||
/// </summary> |
|||
public static <#=blender#> Instance { get; } = new <#=blender#>(); |
|||
|
|||
/// <inheritdoc /> |
|||
public override TPixel Blend(TPixel background, TPixel source, float amount) |
|||
{ |
|||
return PorterDuffFunctions.<#=blender#>(background, source, amount); |
|||
} |
|||
|
|||
/// <inheritdoc /> |
|||
public override void Blend(Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount) |
|||
{ |
|||
Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); |
|||
Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); |
|||
Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); |
|||
|
|||
using (Buffer<Vector4> buffer = new Buffer<Vector4>(destination.Length * 3)) |
|||
{ |
|||
Span<Vector4> destinationSpan = buffer.Slice(0, destination.Length); |
|||
Span<Vector4> backgroundSpan = buffer.Slice(destination.Length, destination.Length); |
|||
Span<Vector4> sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); |
|||
|
|||
PixelOperations<TPixel>.Instance.ToVector4(background, backgroundSpan, destination.Length); |
|||
PixelOperations<TPixel>.Instance.ToVector4(source, sourceSpan, destination.Length); |
|||
|
|||
for (int i = 0; i < destination.Length; i++) |
|||
{ |
|||
destinationSpan[i] = PorterDuffFunctions.<#=blender#>(backgroundSpan[i], sourceSpan[i], amount[i]); |
|||
} |
|||
|
|||
PixelOperations<TPixel>.Instance.PackFromVector4(destinationSpan, destination, destination.Length); |
|||
} |
|||
} |
|||
} |
|||
<# |
|||
|
|||
} |
|||
|
|||
#> |
|||
} |
|||
} |
|||
@ -1,57 +0,0 @@ |
|||
// <copyright file="DefaultScreenPixelBlender{TPixel}.cs" company="James Jackson-South">
|
|||
// Copyright (c) James Jackson-South and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
|
|||
namespace ImageSharp.PixelFormats.PixelBlenders |
|||
{ |
|||
using System; |
|||
using System.Numerics; |
|||
|
|||
using ImageSharp.Memory; |
|||
using ImageSharp.PixelFormats; |
|||
|
|||
/// <summary>
|
|||
/// Applies an "Screen" blending to pixels.
|
|||
/// </summary>
|
|||
/// <typeparam name="TPixel">The type of the pixel</typeparam>
|
|||
internal class DefaultScreenPixelBlender<TPixel> : PixelBlender<TPixel> |
|||
where TPixel : struct, IPixel<TPixel> |
|||
{ |
|||
/// <summary>
|
|||
/// Gets the static instance of this blender.
|
|||
/// </summary>
|
|||
public static DefaultScreenPixelBlender<TPixel> Instance { get; } = new DefaultScreenPixelBlender<TPixel>(); |
|||
|
|||
/// <inheritdoc />
|
|||
public override TPixel Blend(TPixel background, TPixel source, float amount) |
|||
{ |
|||
return PorterDuffFunctions<TPixel>.ScreenFunction(background, source, amount); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public override void Blend(Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount) |
|||
{ |
|||
Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); |
|||
Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); |
|||
Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); |
|||
|
|||
using (Buffer<Vector4> buffer = new Buffer<Vector4>(destination.Length * 3)) |
|||
{ |
|||
Span<Vector4> destinationSpan = buffer.Slice(0, destination.Length); |
|||
Span<Vector4> backgroundSpan = buffer.Slice(destination.Length, destination.Length); |
|||
Span<Vector4> sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); |
|||
|
|||
PixelOperations<TPixel>.Instance.ToVector4(background, backgroundSpan, destination.Length); |
|||
PixelOperations<TPixel>.Instance.ToVector4(source, sourceSpan, destination.Length); |
|||
|
|||
for (int i = 0; i < destination.Length; i++) |
|||
{ |
|||
destinationSpan[i] = PorterDuffFunctions.ScreenFunction(backgroundSpan[i], sourceSpan[i], amount[i]); |
|||
} |
|||
|
|||
PixelOperations<TPixel>.Instance.PackFromVector4(destinationSpan, destination, destination.Length); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -1,57 +0,0 @@ |
|||
// <copyright file="DefaultSubstractPixelBlender{TPixel}.cs" company="James Jackson-South">
|
|||
// Copyright (c) James Jackson-South and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
|
|||
namespace ImageSharp.PixelFormats.PixelBlenders |
|||
{ |
|||
using System; |
|||
using System.Numerics; |
|||
|
|||
using ImageSharp.Memory; |
|||
using ImageSharp.PixelFormats; |
|||
|
|||
/// <summary>
|
|||
/// Applies an "Subtract" blending to pixels.
|
|||
/// </summary>
|
|||
/// <typeparam name="TPixel">The type of the pixel</typeparam>
|
|||
internal class DefaultSubstractPixelBlender<TPixel> : PixelBlender<TPixel> |
|||
where TPixel : struct, IPixel<TPixel> |
|||
{ |
|||
/// <summary>
|
|||
/// Gets the static instance of this blender.
|
|||
/// </summary>
|
|||
public static DefaultSubstractPixelBlender<TPixel> Instance { get; } = new DefaultSubstractPixelBlender<TPixel>(); |
|||
|
|||
/// <inheritdoc />
|
|||
public override TPixel Blend(TPixel background, TPixel source, float amount) |
|||
{ |
|||
return PorterDuffFunctions<TPixel>.SubstractFunction(background, source, amount); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public override void Blend(Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount) |
|||
{ |
|||
Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); |
|||
Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); |
|||
Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); |
|||
|
|||
using (Buffer<Vector4> buffer = new Buffer<Vector4>(destination.Length * 3)) |
|||
{ |
|||
Span<Vector4> destinationSpan = buffer.Slice(0, destination.Length); |
|||
Span<Vector4> backgroundSpan = buffer.Slice(destination.Length, destination.Length); |
|||
Span<Vector4> sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); |
|||
|
|||
PixelOperations<TPixel>.Instance.ToVector4(background, backgroundSpan, destination.Length); |
|||
PixelOperations<TPixel>.Instance.ToVector4(source, sourceSpan, destination.Length); |
|||
|
|||
for (int i = 0; i < destination.Length; i++) |
|||
{ |
|||
destinationSpan[i] = PorterDuffFunctions.SubstractFunction(backgroundSpan[i], sourceSpan[i], amount[i]); |
|||
} |
|||
|
|||
PixelOperations<TPixel>.Instance.PackFromVector4(destinationSpan, destination, destination.Length); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,451 @@ |
|||
// <autogenerated />
|
|||
// <copyright file="PorterDuffFunctions.Generated.cs" company="James Jackson-South">
|
|||
// Copyright (c) James Jackson-South and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
|
|||
namespace ImageSharp.PixelFormats.PixelBlenders |
|||
{ |
|||
using System.Numerics; |
|||
using System.Runtime.CompilerServices; |
|||
|
|||
|
|||
internal static partial class PorterDuffFunctions |
|||
{ |
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static Vector4 Src(Vector4 backdrop, Vector4 source, float opacity) |
|||
{ |
|||
opacity = opacity.Clamp(0, 1); |
|||
source.W *= opacity; |
|||
Vector4 xform = source; |
|||
|
|||
// calculate weights
|
|||
float xw = Vector4.Zero.W * source.W; |
|||
float bw = Vector4.Zero.W - xw; |
|||
float sw = source.W - xw; |
|||
|
|||
// calculate final alpha
|
|||
float a = xw + bw + sw; |
|||
|
|||
// calculate final value
|
|||
xform = ((xform * xw) + (Vector4.Zero * bw) + (source * sw)) / MathF.Max(a, Constants.Epsilon); |
|||
|
|||
return Vector4.Lerp(backdrop, xform, opacity); |
|||
} |
|||
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static Vector4 Atop(Vector4 backdrop, Vector4 source, float opacity) |
|||
{ |
|||
opacity = opacity.Clamp(0, 1); |
|||
Vector4 xform = source; |
|||
|
|||
// calculate weights
|
|||
float xw = backdrop.W * Vector4.Zero.W; |
|||
float bw = backdrop.W - xw; |
|||
float sw = Vector4.Zero.W - xw; |
|||
|
|||
// calculate final alpha
|
|||
float a = xw + bw + sw; |
|||
|
|||
// calculate final value
|
|||
xform = ((xform * xw) + (backdrop * bw) + (Vector4.Zero * sw)) / MathF.Max(a, Constants.Epsilon); |
|||
|
|||
return Vector4.Lerp(backdrop, xform, opacity); |
|||
} |
|||
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static Vector4 Over(Vector4 backdrop, Vector4 source, float opacity) |
|||
{ |
|||
opacity = opacity.Clamp(0, 1); |
|||
source.W *= opacity; |
|||
Vector4 xform = source; |
|||
|
|||
// calculate weights
|
|||
float xw = backdrop.W * source.W; |
|||
float bw = backdrop.W - xw; |
|||
float sw = source.W - xw; |
|||
|
|||
// calculate final alpha
|
|||
float a = xw + bw + sw; |
|||
|
|||
// calculate final value
|
|||
xform = ((xform * xw) + (backdrop * bw) + (source * sw)) / MathF.Max(a, Constants.Epsilon); |
|||
|
|||
return Vector4.Lerp(backdrop, xform, opacity); |
|||
} |
|||
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static Vector4 In(Vector4 backdrop, Vector4 source, float opacity) |
|||
{ |
|||
opacity = opacity.Clamp(0, 1); |
|||
Vector4 xform = source; |
|||
|
|||
// calculate weights
|
|||
float xw = Vector4.Zero.W * Vector4.Zero.W; |
|||
float bw = Vector4.Zero.W - xw; |
|||
float sw = Vector4.Zero.W - xw; |
|||
|
|||
// calculate final alpha
|
|||
float a = xw + bw + sw; |
|||
|
|||
// calculate final value
|
|||
xform = ((xform * xw) + (Vector4.Zero * bw) + (Vector4.Zero * sw)) / MathF.Max(a, Constants.Epsilon); |
|||
|
|||
return Vector4.Lerp(backdrop, xform, opacity); |
|||
} |
|||
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static Vector4 Out(Vector4 backdrop, Vector4 source, float opacity) |
|||
{ |
|||
opacity = opacity.Clamp(0, 1); |
|||
source.W *= opacity; |
|||
Vector4 xform = Vector4.Zero; |
|||
|
|||
// calculate weights
|
|||
float xw = Vector4.Zero.W * source.W; |
|||
float bw = Vector4.Zero.W - xw; |
|||
float sw = source.W - xw; |
|||
|
|||
// calculate final alpha
|
|||
float a = xw + bw + sw; |
|||
|
|||
// calculate final value
|
|||
xform = ((xform * xw) + (Vector4.Zero * bw) + (source * sw)) / MathF.Max(a, Constants.Epsilon); |
|||
|
|||
return Vector4.Lerp(backdrop, xform, opacity); |
|||
} |
|||
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static Vector4 Dest(Vector4 backdrop, Vector4 source, float opacity) |
|||
{ |
|||
opacity = opacity.Clamp(0, 1); |
|||
Vector4 xform = backdrop; |
|||
|
|||
// calculate weights
|
|||
float xw = backdrop.W * Vector4.Zero.W; |
|||
float bw = backdrop.W - xw; |
|||
float sw = Vector4.Zero.W - xw; |
|||
|
|||
// calculate final alpha
|
|||
float a = xw + bw + sw; |
|||
|
|||
// calculate final value
|
|||
xform = ((xform * xw) + (backdrop * bw) + (Vector4.Zero * sw)) / MathF.Max(a, Constants.Epsilon); |
|||
|
|||
return Vector4.Lerp(backdrop, xform, opacity); |
|||
} |
|||
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static Vector4 DestAtop(Vector4 backdrop, Vector4 source, float opacity) |
|||
{ |
|||
opacity = opacity.Clamp(0, 1); |
|||
source.W *= opacity; |
|||
Vector4 xform = backdrop; |
|||
|
|||
// calculate weights
|
|||
float xw = Vector4.Zero.W * source.W; |
|||
float bw = Vector4.Zero.W - xw; |
|||
float sw = source.W - xw; |
|||
|
|||
// calculate final alpha
|
|||
float a = xw + bw + sw; |
|||
|
|||
// calculate final value
|
|||
xform = ((xform * xw) + (Vector4.Zero * bw) + (source * sw)) / MathF.Max(a, Constants.Epsilon); |
|||
|
|||
return Vector4.Lerp(backdrop, xform, opacity); |
|||
} |
|||
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static Vector4 DestOver(Vector4 backdrop, Vector4 source, float opacity) |
|||
{ |
|||
opacity = opacity.Clamp(0, 1); |
|||
source.W *= opacity; |
|||
Vector4 xform = backdrop; |
|||
|
|||
// calculate weights
|
|||
float xw = backdrop.W * source.W; |
|||
float bw = backdrop.W - xw; |
|||
float sw = source.W - xw; |
|||
|
|||
// calculate final alpha
|
|||
float a = xw + bw + sw; |
|||
|
|||
// calculate final value
|
|||
xform = ((xform * xw) + (backdrop * bw) + (source * sw)) / MathF.Max(a, Constants.Epsilon); |
|||
|
|||
return Vector4.Lerp(backdrop, xform, opacity); |
|||
} |
|||
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static Vector4 DestIn(Vector4 backdrop, Vector4 source, float opacity) |
|||
{ |
|||
opacity = opacity.Clamp(0, 1); |
|||
Vector4 xform = backdrop; |
|||
|
|||
// calculate weights
|
|||
float xw = Vector4.Zero.W * Vector4.Zero.W; |
|||
float bw = Vector4.Zero.W - xw; |
|||
float sw = Vector4.Zero.W - xw; |
|||
|
|||
// calculate final alpha
|
|||
float a = xw + bw + sw; |
|||
|
|||
// calculate final value
|
|||
xform = ((xform * xw) + (Vector4.Zero * bw) + (Vector4.Zero * sw)) / MathF.Max(a, Constants.Epsilon); |
|||
|
|||
return Vector4.Lerp(backdrop, xform, opacity); |
|||
} |
|||
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static Vector4 DestOut(Vector4 backdrop, Vector4 source, float opacity) |
|||
{ |
|||
opacity = opacity.Clamp(0, 1); |
|||
Vector4 xform = Vector4.Zero; |
|||
|
|||
// calculate weights
|
|||
float xw = backdrop.W * Vector4.Zero.W; |
|||
float bw = backdrop.W - xw; |
|||
float sw = Vector4.Zero.W - xw; |
|||
|
|||
// calculate final alpha
|
|||
float a = xw + bw + sw; |
|||
|
|||
// calculate final value
|
|||
xform = ((xform * xw) + (backdrop * bw) + (Vector4.Zero * sw)) / MathF.Max(a, Constants.Epsilon); |
|||
|
|||
return Vector4.Lerp(backdrop, xform, opacity); |
|||
} |
|||
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static Vector4 Clear(Vector4 backdrop, Vector4 source, float opacity) |
|||
{ |
|||
opacity = opacity.Clamp(0, 1); |
|||
Vector4 xform = Vector4.Zero; |
|||
|
|||
// calculate weights
|
|||
float xw = Vector4.Zero.W * Vector4.Zero.W; |
|||
float bw = Vector4.Zero.W - xw; |
|||
float sw = Vector4.Zero.W - xw; |
|||
|
|||
// calculate final alpha
|
|||
float a = xw + bw + sw; |
|||
|
|||
// calculate final value
|
|||
xform = ((xform * xw) + (Vector4.Zero * bw) + (Vector4.Zero * sw)) / MathF.Max(a, Constants.Epsilon); |
|||
|
|||
return Vector4.Lerp(backdrop, xform, opacity); |
|||
} |
|||
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static Vector4 Xor(Vector4 backdrop, Vector4 source, float opacity) |
|||
{ |
|||
opacity = opacity.Clamp(0, 1); |
|||
source.W *= opacity; |
|||
Vector4 xform = Vector4.Zero; |
|||
|
|||
// calculate weights
|
|||
float xw = backdrop.W * source.W; |
|||
float bw = backdrop.W - xw; |
|||
float sw = source.W - xw; |
|||
|
|||
// calculate final alpha
|
|||
float a = xw + bw + sw; |
|||
|
|||
// calculate final value
|
|||
xform = ((xform * xw) + (backdrop * bw) + (source * sw)) / MathF.Max(a, Constants.Epsilon); |
|||
|
|||
return Vector4.Lerp(backdrop, xform, opacity); |
|||
} |
|||
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static TPixel Normal<TPixel>(TPixel backdrop, TPixel source, float amount) |
|||
where TPixel : struct, IPixel<TPixel> |
|||
{ |
|||
TPixel dest = default(TPixel); |
|||
dest.PackFromVector4(Normal(backdrop.ToVector4(), source.ToVector4(), amount)); |
|||
return dest; |
|||
} |
|||
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static TPixel Multiply<TPixel>(TPixel backdrop, TPixel source, float amount) |
|||
where TPixel : struct, IPixel<TPixel> |
|||
{ |
|||
TPixel dest = default(TPixel); |
|||
dest.PackFromVector4(Multiply(backdrop.ToVector4(), source.ToVector4(), amount)); |
|||
return dest; |
|||
} |
|||
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static TPixel Add<TPixel>(TPixel backdrop, TPixel source, float amount) |
|||
where TPixel : struct, IPixel<TPixel> |
|||
{ |
|||
TPixel dest = default(TPixel); |
|||
dest.PackFromVector4(Add(backdrop.ToVector4(), source.ToVector4(), amount)); |
|||
return dest; |
|||
} |
|||
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static TPixel Substract<TPixel>(TPixel backdrop, TPixel source, float amount) |
|||
where TPixel : struct, IPixel<TPixel> |
|||
{ |
|||
TPixel dest = default(TPixel); |
|||
dest.PackFromVector4(Substract(backdrop.ToVector4(), source.ToVector4(), amount)); |
|||
return dest; |
|||
} |
|||
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static TPixel Screen<TPixel>(TPixel backdrop, TPixel source, float amount) |
|||
where TPixel : struct, IPixel<TPixel> |
|||
{ |
|||
TPixel dest = default(TPixel); |
|||
dest.PackFromVector4(Screen(backdrop.ToVector4(), source.ToVector4(), amount)); |
|||
return dest; |
|||
} |
|||
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static TPixel Darken<TPixel>(TPixel backdrop, TPixel source, float amount) |
|||
where TPixel : struct, IPixel<TPixel> |
|||
{ |
|||
TPixel dest = default(TPixel); |
|||
dest.PackFromVector4(Darken(backdrop.ToVector4(), source.ToVector4(), amount)); |
|||
return dest; |
|||
} |
|||
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static TPixel Lighten<TPixel>(TPixel backdrop, TPixel source, float amount) |
|||
where TPixel : struct, IPixel<TPixel> |
|||
{ |
|||
TPixel dest = default(TPixel); |
|||
dest.PackFromVector4(Lighten(backdrop.ToVector4(), source.ToVector4(), amount)); |
|||
return dest; |
|||
} |
|||
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static TPixel Overlay<TPixel>(TPixel backdrop, TPixel source, float amount) |
|||
where TPixel : struct, IPixel<TPixel> |
|||
{ |
|||
TPixel dest = default(TPixel); |
|||
dest.PackFromVector4(Overlay(backdrop.ToVector4(), source.ToVector4(), amount)); |
|||
return dest; |
|||
} |
|||
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static TPixel HardLight<TPixel>(TPixel backdrop, TPixel source, float amount) |
|||
where TPixel : struct, IPixel<TPixel> |
|||
{ |
|||
TPixel dest = default(TPixel); |
|||
dest.PackFromVector4(HardLight(backdrop.ToVector4(), source.ToVector4(), amount)); |
|||
return dest; |
|||
} |
|||
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static TPixel Src<TPixel>(TPixel backdrop, TPixel source, float amount) |
|||
where TPixel : struct, IPixel<TPixel> |
|||
{ |
|||
TPixel dest = default(TPixel); |
|||
dest.PackFromVector4(Src(backdrop.ToVector4(), source.ToVector4(), amount)); |
|||
return dest; |
|||
} |
|||
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static TPixel Atop<TPixel>(TPixel backdrop, TPixel source, float amount) |
|||
where TPixel : struct, IPixel<TPixel> |
|||
{ |
|||
TPixel dest = default(TPixel); |
|||
dest.PackFromVector4(Atop(backdrop.ToVector4(), source.ToVector4(), amount)); |
|||
return dest; |
|||
} |
|||
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static TPixel Over<TPixel>(TPixel backdrop, TPixel source, float amount) |
|||
where TPixel : struct, IPixel<TPixel> |
|||
{ |
|||
TPixel dest = default(TPixel); |
|||
dest.PackFromVector4(Over(backdrop.ToVector4(), source.ToVector4(), amount)); |
|||
return dest; |
|||
} |
|||
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static TPixel In<TPixel>(TPixel backdrop, TPixel source, float amount) |
|||
where TPixel : struct, IPixel<TPixel> |
|||
{ |
|||
TPixel dest = default(TPixel); |
|||
dest.PackFromVector4(In(backdrop.ToVector4(), source.ToVector4(), amount)); |
|||
return dest; |
|||
} |
|||
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static TPixel Out<TPixel>(TPixel backdrop, TPixel source, float amount) |
|||
where TPixel : struct, IPixel<TPixel> |
|||
{ |
|||
TPixel dest = default(TPixel); |
|||
dest.PackFromVector4(Out(backdrop.ToVector4(), source.ToVector4(), amount)); |
|||
return dest; |
|||
} |
|||
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static TPixel Dest<TPixel>(TPixel backdrop, TPixel source, float amount) |
|||
where TPixel : struct, IPixel<TPixel> |
|||
{ |
|||
TPixel dest = default(TPixel); |
|||
dest.PackFromVector4(Dest(backdrop.ToVector4(), source.ToVector4(), amount)); |
|||
return dest; |
|||
} |
|||
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static TPixel DestAtop<TPixel>(TPixel backdrop, TPixel source, float amount) |
|||
where TPixel : struct, IPixel<TPixel> |
|||
{ |
|||
TPixel dest = default(TPixel); |
|||
dest.PackFromVector4(DestAtop(backdrop.ToVector4(), source.ToVector4(), amount)); |
|||
return dest; |
|||
} |
|||
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static TPixel DestOver<TPixel>(TPixel backdrop, TPixel source, float amount) |
|||
where TPixel : struct, IPixel<TPixel> |
|||
{ |
|||
TPixel dest = default(TPixel); |
|||
dest.PackFromVector4(DestOver(backdrop.ToVector4(), source.ToVector4(), amount)); |
|||
return dest; |
|||
} |
|||
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static TPixel DestIn<TPixel>(TPixel backdrop, TPixel source, float amount) |
|||
where TPixel : struct, IPixel<TPixel> |
|||
{ |
|||
TPixel dest = default(TPixel); |
|||
dest.PackFromVector4(DestIn(backdrop.ToVector4(), source.ToVector4(), amount)); |
|||
return dest; |
|||
} |
|||
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static TPixel DestOut<TPixel>(TPixel backdrop, TPixel source, float amount) |
|||
where TPixel : struct, IPixel<TPixel> |
|||
{ |
|||
TPixel dest = default(TPixel); |
|||
dest.PackFromVector4(DestOut(backdrop.ToVector4(), source.ToVector4(), amount)); |
|||
return dest; |
|||
} |
|||
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static TPixel Clear<TPixel>(TPixel backdrop, TPixel source, float amount) |
|||
where TPixel : struct, IPixel<TPixel> |
|||
{ |
|||
TPixel dest = default(TPixel); |
|||
dest.PackFromVector4(Clear(backdrop.ToVector4(), source.ToVector4(), amount)); |
|||
return dest; |
|||
} |
|||
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static TPixel Xor<TPixel>(TPixel backdrop, TPixel source, float amount) |
|||
where TPixel : struct, IPixel<TPixel> |
|||
{ |
|||
TPixel dest = default(TPixel); |
|||
dest.PackFromVector4(Xor(backdrop.ToVector4(), source.ToVector4(), amount)); |
|||
return dest; |
|||
} |
|||
|
|||
} |
|||
} |
|||
@ -0,0 +1,112 @@ |
|||
<# |
|||
// <copyright file="PorterDuffFunctions.Generated.tt" company="James Jackson-South"> |
|||
// Copyright (c) James Jackson-South and contributors. |
|||
// Licensed under the Apache License, Version 2.0. |
|||
// </copyright> |
|||
#> |
|||
<#@ template debug="false" hostspecific="false" language="C#" #> |
|||
<#@ assembly name="System.Core" #> |
|||
<#@ import namespace="System.Linq" #> |
|||
<#@ import namespace="System.Text" #> |
|||
<#@ import namespace="System.Collections.Generic" #> |
|||
<#@ output extension=".cs" #> |
|||
// <autogenerated /> |
|||
// <copyright file="PorterDuffFunctions.Generated.cs" company="James Jackson-South"> |
|||
// Copyright (c) James Jackson-South and contributors. |
|||
// Licensed under the Apache License, Version 2.0. |
|||
// </copyright> |
|||
|
|||
namespace ImageSharp.PixelFormats.PixelBlenders |
|||
{ |
|||
using System.Numerics; |
|||
using System.Runtime.CompilerServices; |
|||
|
|||
|
|||
internal static partial class PorterDuffFunctions |
|||
{ |
|||
<# |
|||
|
|||
void GeneratePixelBlender (string blender) |
|||
{ |
|||
#> |
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static TPixel <#=blender#><TPixel>(TPixel backdrop, TPixel source, float amount) |
|||
where TPixel : struct, IPixel<TPixel> |
|||
{ |
|||
TPixel dest = default(TPixel); |
|||
dest.PackFromVector4(<#=blender#>(backdrop.ToVector4(), source.ToVector4(), amount)); |
|||
return dest; |
|||
} |
|||
|
|||
<# |
|||
} |
|||
|
|||
void GenerateVectorCompositor(string name, string sourceVar, string destVar, string blendVar) |
|||
{ |
|||
#> |
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static Vector4 <#=name#>(Vector4 backdrop, Vector4 source, float opacity) |
|||
{ |
|||
opacity = opacity.Clamp(0, 1); |
|||
<# if(sourceVar != "Vector4.Zero" ) { #> |
|||
source.W *= opacity; |
|||
<# } #> |
|||
Vector4 xform = <#=blendVar#>; |
|||
|
|||
// calculate weights |
|||
float xw = <#=destVar#>.W * <#=sourceVar#>.W; |
|||
float bw = <#=destVar#>.W - xw; |
|||
float sw = <#=sourceVar#>.W - xw; |
|||
|
|||
// calculate final alpha |
|||
float a = xw + bw + sw; |
|||
|
|||
// calculate final value |
|||
xform = ((xform * xw) + (<#=destVar#> * bw) + (<#=sourceVar#> * sw)) / MathF.Max(a, Constants.Epsilon); |
|||
|
|||
return Vector4.Lerp(backdrop, xform, opacity); |
|||
} |
|||
|
|||
<# |
|||
} |
|||
GenerateVectorCompositor("Src", "source", "Vector4.Zero", "source"); |
|||
GenerateVectorCompositor("Atop", "Vector4.Zero", "backdrop", "source"); |
|||
GenerateVectorCompositor("Over", "source", "backdrop", "source"); |
|||
GenerateVectorCompositor("In", "Vector4.Zero", "Vector4.Zero", "source"); |
|||
GenerateVectorCompositor("Out", "source", "Vector4.Zero", "Vector4.Zero"); |
|||
GenerateVectorCompositor("Dest", "Vector4.Zero", "backdrop", "backdrop"); |
|||
GenerateVectorCompositor("DestAtop", "source", "Vector4.Zero", "backdrop"); |
|||
GenerateVectorCompositor("DestOver", "source", "backdrop", "backdrop"); |
|||
GenerateVectorCompositor("DestIn", "Vector4.Zero", "Vector4.Zero", "backdrop"); |
|||
GenerateVectorCompositor("DestOut", "Vector4.Zero", "backdrop", "Vector4.Zero"); |
|||
GenerateVectorCompositor("Clear", "Vector4.Zero", "Vector4.Zero", "Vector4.Zero"); |
|||
GenerateVectorCompositor("Xor", "source", "backdrop", "Vector4.Zero"); |
|||
|
|||
|
|||
GeneratePixelBlender("Normal"); |
|||
GeneratePixelBlender("Multiply"); |
|||
GeneratePixelBlender("Add"); |
|||
GeneratePixelBlender("Substract"); |
|||
GeneratePixelBlender("Screen"); |
|||
GeneratePixelBlender("Darken"); |
|||
GeneratePixelBlender("Lighten"); |
|||
GeneratePixelBlender("Overlay"); |
|||
GeneratePixelBlender("HardLight"); |
|||
|
|||
GeneratePixelBlender("Src"); |
|||
GeneratePixelBlender("Atop"); |
|||
GeneratePixelBlender("Over"); |
|||
GeneratePixelBlender("In"); |
|||
GeneratePixelBlender("Out"); |
|||
GeneratePixelBlender("Dest"); |
|||
GeneratePixelBlender("DestAtop"); |
|||
GeneratePixelBlender("DestOver"); |
|||
GeneratePixelBlender("DestIn"); |
|||
GeneratePixelBlender("DestOut"); |
|||
GeneratePixelBlender("Clear"); |
|||
GeneratePixelBlender("Xor"); |
|||
|
|||
|
|||
#> |
|||
} |
|||
} |
|||
@ -1,151 +0,0 @@ |
|||
// <copyright file="PorterDuffFunctions.cs" company="James Jackson-South">
|
|||
// Copyright (c) James Jackson-South and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
|
|||
namespace ImageSharp.PixelFormats.PixelBlenders |
|||
{ |
|||
using System.Numerics; |
|||
using System.Runtime.CompilerServices; |
|||
|
|||
/// <summary>
|
|||
/// Collection of Porter Duff alpha blending functions
|
|||
/// </summary>
|
|||
/// <typeparam name="TPixel">Pixel Format</typeparam>
|
|||
/// <remarks>
|
|||
/// These functions are designed to be a general solution for all color cases,
|
|||
/// that is, they take in account the alpha value of both the backdrop
|
|||
/// and source, and there's no need to alpha-premultiply neither the backdrop
|
|||
/// nor the source.
|
|||
/// Note there are faster functions for when the backdrop color is known
|
|||
/// to be opaque
|
|||
/// </remarks>
|
|||
internal static class PorterDuffFunctions<TPixel> |
|||
where TPixel : IPixel |
|||
{ |
|||
/// <summary>
|
|||
/// Source over backdrop
|
|||
/// </summary>
|
|||
/// <param name="backdrop">Backgrop color</param>
|
|||
/// <param name="source">Source color</param>
|
|||
/// <param name="opacity">Opacity applied to Source Alpha</param>
|
|||
/// <returns>Output color</returns>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static TPixel NormalBlendFunction(TPixel backdrop, TPixel source, float opacity) |
|||
{ |
|||
return ToPixel(PorterDuffFunctions.NormalBlendFunction(backdrop.ToVector4(), source.ToVector4(), opacity)); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Source multiplied by backdrop
|
|||
/// </summary>
|
|||
/// <param name="backdrop">Backgrop color</param>
|
|||
/// <param name="source">Source color</param>
|
|||
/// <param name="opacity">Opacity applied to Source Alpha</param>
|
|||
/// <returns>Output color</returns>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static TPixel MultiplyFunction(TPixel backdrop, TPixel source, float opacity) |
|||
{ |
|||
return ToPixel(PorterDuffFunctions.MultiplyFunction(backdrop.ToVector4(), source.ToVector4(), opacity)); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Source added to backdrop
|
|||
/// </summary>
|
|||
/// <param name="backdrop">Backgrop color</param>
|
|||
/// <param name="source">Source color</param>
|
|||
/// <param name="opacity">Opacity applied to Source Alpha</param>
|
|||
/// <returns>Output color</returns>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static TPixel AddFunction(TPixel backdrop, TPixel source, float opacity) |
|||
{ |
|||
return ToPixel(PorterDuffFunctions.AddFunction(backdrop.ToVector4(), source.ToVector4(), opacity)); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Source substracted from backdrop
|
|||
/// </summary>
|
|||
/// <param name="backdrop">Backgrop color</param>
|
|||
/// <param name="source">Source color</param>
|
|||
/// <param name="opacity">Opacity applied to Source Alpha</param>
|
|||
/// <returns>Output color</returns>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static TPixel SubstractFunction(TPixel backdrop, TPixel source, float opacity) |
|||
{ |
|||
return ToPixel(PorterDuffFunctions.SubstractFunction(backdrop.ToVector4(), source.ToVector4(), opacity)); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Complement of source multiplied by the complement of backdrop
|
|||
/// </summary>
|
|||
/// <param name="backdrop">Backgrop color</param>
|
|||
/// <param name="source">Source color</param>
|
|||
/// <param name="opacity">Opacity applied to Source Alpha</param>
|
|||
/// <returns>Output color</returns>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static TPixel ScreenFunction(TPixel backdrop, TPixel source, float opacity) |
|||
{ |
|||
return ToPixel(PorterDuffFunctions.ScreenFunction(backdrop.ToVector4(), source.ToVector4(), opacity)); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Per element, chooses the smallest value of source and backdrop
|
|||
/// </summary>
|
|||
/// <param name="backdrop">Backgrop color</param>
|
|||
/// <param name="source">Source color</param>
|
|||
/// <param name="opacity">Opacity applied to Source Alpha</param>
|
|||
/// <returns>Output color</returns>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static TPixel DarkenFunction(TPixel backdrop, TPixel source, float opacity) |
|||
{ |
|||
return ToPixel(PorterDuffFunctions.DarkenFunction(backdrop.ToVector4(), source.ToVector4(), opacity)); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Per element, chooses the largest value of source and backdrop
|
|||
/// </summary>
|
|||
/// <param name="backdrop">Backgrop color</param>
|
|||
/// <param name="source">Source color</param>
|
|||
/// <param name="opacity">Opacity applied to Source Alpha</param>
|
|||
/// <returns>Output color</returns>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static TPixel LightenFunction(TPixel backdrop, TPixel source, float opacity) |
|||
{ |
|||
return ToPixel(PorterDuffFunctions.LightenFunction(backdrop.ToVector4(), source.ToVector4(), opacity)); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Overlays source over backdrop
|
|||
/// </summary>
|
|||
/// <param name="backdrop">Backgrop color</param>
|
|||
/// <param name="source">Source color</param>
|
|||
/// <param name="opacity">Opacity applied to Source Alpha</param>
|
|||
/// <returns>Output color</returns>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static TPixel OverlayFunction(TPixel backdrop, TPixel source, float opacity) |
|||
{ |
|||
return ToPixel(PorterDuffFunctions.OverlayFunction(backdrop.ToVector4(), source.ToVector4(), opacity)); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Hard light effect
|
|||
/// </summary>
|
|||
/// <param name="backdrop">Backgrop color</param>
|
|||
/// <param name="source">Source color</param>
|
|||
/// <param name="opacity">Opacity applied to Source Alpha</param>
|
|||
/// <returns>Output color</returns>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static TPixel HardLightFunction(TPixel backdrop, TPixel source, float opacity) |
|||
{ |
|||
return ToPixel(PorterDuffFunctions.HardLightFunction(backdrop.ToVector4(), source.ToVector4(), opacity)); |
|||
} |
|||
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
private static TPixel ToPixel(Vector4 vector) |
|||
{ |
|||
TPixel p = default(TPixel); |
|||
p.PackFromVector4(vector); |
|||
return p; |
|||
} |
|||
} |
|||
} |
|||
@ -1,50 +0,0 @@ |
|||
// <copyright file="PixelOperations.cs" company="James Jackson-South">
|
|||
// Copyright (c) James Jackson-South and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
|
|||
namespace ImageSharp.Tests.PixelFormats |
|||
{ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Text; |
|||
using ImageSharp.PixelFormats; |
|||
using ImageSharp.PixelFormats.PixelBlenders; |
|||
using ImageSharp.Tests.TestUtilities; |
|||
using Xunit; |
|||
|
|||
public class PixelOperations |
|||
{ |
|||
public static TheoryData<object, Type, PixelBlenderMode> BlenderMappings = new TheoryData<object, Type, PixelBlenderMode>() |
|||
{ |
|||
{ new TestPixel<Rgba32>(), typeof(DefaultNormalPixelBlender<Rgba32>), PixelBlenderMode.Normal }, |
|||
{ new TestPixel<Rgba32>(), typeof(DefaultScreenPixelBlender<Rgba32>), PixelBlenderMode.Screen }, |
|||
{ new TestPixel<Rgba32>(), typeof(DefaultHardLightPixelBlender<Rgba32>), PixelBlenderMode.HardLight }, |
|||
{ new TestPixel<Rgba32>(), typeof(DefaultOverlayPixelBlender<Rgba32>), PixelBlenderMode.Overlay }, |
|||
{ new TestPixel<Rgba32>(), typeof(DefaultDarkenPixelBlender<Rgba32>), PixelBlenderMode.Darken }, |
|||
{ new TestPixel<Rgba32>(), typeof(DefaultLightenPixelBlender<Rgba32>), PixelBlenderMode.Lighten }, |
|||
{ new TestPixel<Rgba32>(), typeof(DefaultAddPixelBlender<Rgba32>), PixelBlenderMode.Add }, |
|||
{ new TestPixel<Rgba32>(), typeof(DefaultSubstractPixelBlender<Rgba32>), PixelBlenderMode.Substract }, |
|||
{ new TestPixel<Rgba32>(), typeof(DefaultMultiplyPixelBlender<Rgba32>), PixelBlenderMode.Multiply }, |
|||
|
|||
{ new TestPixel<RgbaVector>(), typeof(DefaultNormalPixelBlender<RgbaVector>), PixelBlenderMode.Normal }, |
|||
{ new TestPixel<RgbaVector>(), typeof(DefaultScreenPixelBlender<RgbaVector>), PixelBlenderMode.Screen }, |
|||
{ new TestPixel<RgbaVector>(), typeof(DefaultHardLightPixelBlender<RgbaVector>), PixelBlenderMode.HardLight }, |
|||
{ new TestPixel<RgbaVector>(), typeof(DefaultOverlayPixelBlender<RgbaVector>), PixelBlenderMode.Overlay }, |
|||
{ new TestPixel<RgbaVector>(), typeof(DefaultDarkenPixelBlender<RgbaVector>), PixelBlenderMode.Darken }, |
|||
{ new TestPixel<RgbaVector>(), typeof(DefaultLightenPixelBlender<RgbaVector>), PixelBlenderMode.Lighten }, |
|||
{ new TestPixel<RgbaVector>(), typeof(DefaultAddPixelBlender<RgbaVector>), PixelBlenderMode.Add }, |
|||
{ new TestPixel<RgbaVector>(), typeof(DefaultSubstractPixelBlender<RgbaVector>), PixelBlenderMode.Substract }, |
|||
{ new TestPixel<RgbaVector>(), typeof(DefaultMultiplyPixelBlender<RgbaVector>), PixelBlenderMode.Multiply }, |
|||
}; |
|||
|
|||
[Theory] |
|||
[MemberData(nameof(BlenderMappings))] |
|||
public void ReturnsCorrectBlender<TPixel>(TestPixel<TPixel> pixel, Type type, PixelBlenderMode mode) |
|||
where TPixel : struct, IPixel<TPixel> |
|||
{ |
|||
PixelBlender<TPixel> blender = PixelOperations<TPixel>.Instance.GetPixelBlender(mode); |
|||
Assert.IsType(type, blender); |
|||
} |
|||
} |
|||
} |
|||
Loading…
Reference in new issue