mirror of https://github.com/SixLabors/ImageSharp
36 changed files with 2051 additions and 895 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; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
Loading…
Reference in new issue