diff --git a/src/ImageSharp.Drawing/Processing/GradientBrushBase{TPixel}.cs b/src/ImageSharp.Drawing/Processing/GradientBrushBase{TPixel}.cs index a844457ac..897b3f384 100644 --- a/src/ImageSharp.Drawing/Processing/GradientBrushBase{TPixel}.cs +++ b/src/ImageSharp.Drawing/Processing/GradientBrushBase{TPixel}.cs @@ -111,7 +111,7 @@ namespace SixLabors.ImageSharp.Processing throw new ArgumentOutOfRangeException(); } - var (from, to) = this.GetGradientSegment(positionOnCompleteGradient); + (ColorStop from, ColorStop to) = this.GetGradientSegment(positionOnCompleteGradient); if (from.Color.Equals(to.Color)) { @@ -124,7 +124,7 @@ namespace SixLabors.ImageSharp.Processing float onLocalGradient = (positionOnCompleteGradient - from.Ratio) / to.Ratio; // TODO: this should be changeble for different gradienting functions - Vector4 result = PorterDuffFunctions.Normal( + Vector4 result = PorterDuffFunctions.NormalSrcOver( fromAsVector, toAsVector, onLocalGradient); @@ -153,11 +153,11 @@ namespace SixLabors.ImageSharp.Processing private (ColorStop from, ColorStop to) GetGradientSegment( float positionOnCompleteGradient) { - var localGradientFrom = this.colorStops[0]; + ColorStop localGradientFrom = this.colorStops[0]; ColorStop localGradientTo = default; // TODO: ensure colorStops has at least 2 items (technically 1 would be okay, but that's no gradient) - foreach (var colorStop in this.colorStops) + foreach (ColorStop colorStop in this.colorStops) { localGradientTo = colorStop; diff --git a/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs b/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs index 128ae0854..d67beb036 100644 --- a/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs +++ b/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs @@ -373,11 +373,9 @@ namespace SixLabors.ImageSharp.Formats.Bmp for (int x = 0; x < arrayWidth; x++) { int colOffset = x * ppb; - - for (int shift = 0; shift < ppb && (x + shift) < width; shift++) + for (int shift = 0, newX = colOffset; shift < ppb && newX < width; shift++, newX++) { int colorIndex = ((rowSpan[offset] >> (8 - bits - (shift * bits))) & mask) * 4; - int newX = colOffset + shift; // Stored in b-> g-> r order. rgba.Bgr = Unsafe.As(ref colors[colorIndex]); diff --git a/src/ImageSharp/Image.FromBytes.cs b/src/ImageSharp/Image.FromBytes.cs index 98a39193d..12abf720b 100644 --- a/src/ImageSharp/Image.FromBytes.cs +++ b/src/ImageSharp/Image.FromBytes.cs @@ -3,6 +3,7 @@ using System; using System.IO; +using System.Linq; using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.PixelFormats; @@ -193,13 +194,24 @@ namespace SixLabors.ImageSharp /// The mime type or null if none found. public static unsafe IImageFormat DetectFormat(Configuration config, ReadOnlySpan data) { - fixed (byte* ptr = &data.GetPinnableReference()) + int maxHeaderSize = config.MaxHeaderSize; + if (maxHeaderSize <= 0) { - using (var stream = new UnmanagedMemoryStream(ptr, data.Length)) + return null; + } + + IImageFormat format = default; + foreach (IImageFormatDetector detector in config.ImageFormatsManager.FormatDetectors) + { + IImageFormat f = detector.DetectFormat(data); + + if (f != null) { - return DetectFormat(config, stream); + format = f; } } + + return format; } /// diff --git a/src/ImageSharp/PixelFormats/Alpha8.cs b/src/ImageSharp/PixelFormats/Alpha8.cs index 0b16fed0a..a8d97d31a 100644 --- a/src/ImageSharp/PixelFormats/Alpha8.cs +++ b/src/ImageSharp/PixelFormats/Alpha8.cs @@ -208,10 +208,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public override int GetHashCode() - { - return this.PackedValue.GetHashCode(); - } + public override int GetHashCode() => this.PackedValue.GetHashCode(); /// /// Packs a into a byte. diff --git a/src/ImageSharp/PixelFormats/Argb32.cs b/src/ImageSharp/PixelFormats/Argb32.cs index ccb17a2a5..51d3964ef 100644 --- a/src/ImageSharp/PixelFormats/Argb32.cs +++ b/src/ImageSharp/PixelFormats/Argb32.cs @@ -362,12 +362,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public override int GetHashCode() - { - int hash = HashHelpers.Combine(this.R.GetHashCode(), this.G.GetHashCode()); - hash = HashHelpers.Combine(hash, this.B.GetHashCode()); - return HashHelpers.Combine(hash, this.A.GetHashCode()); - } + public override int GetHashCode() => this.Argb.GetHashCode(); /// /// Gets the representation without normalizing to [0, 1] diff --git a/src/ImageSharp/PixelFormats/Bgr565.cs b/src/ImageSharp/PixelFormats/Bgr565.cs index f9a0ce9dc..570b975db 100644 --- a/src/ImageSharp/PixelFormats/Bgr565.cs +++ b/src/ImageSharp/PixelFormats/Bgr565.cs @@ -224,10 +224,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public override int GetHashCode() - { - return this.PackedValue.GetHashCode(); - } + public override int GetHashCode() => this.PackedValue.GetHashCode(); /// /// Packs the components into a . diff --git a/src/ImageSharp/PixelFormats/Bgra32.cs b/src/ImageSharp/PixelFormats/Bgra32.cs index 14b2da07c..233df2f29 100644 --- a/src/ImageSharp/PixelFormats/Bgra32.cs +++ b/src/ImageSharp/PixelFormats/Bgra32.cs @@ -1,7 +1,6 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. -using System; using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; @@ -105,19 +104,14 @@ namespace SixLabors.ImageSharp.PixelFormats /// public bool Equals(Bgra32 other) { - return this.R == other.R && this.G == other.G && this.B == other.B && this.A == other.A; + return this.Bgra == other.Bgra; } /// public override bool Equals(object obj) => obj is Bgra32 other && this.Equals(other); /// - public override int GetHashCode() - { - int hash = HashHelpers.Combine(this.R.GetHashCode(), this.G.GetHashCode()); - hash = HashHelpers.Combine(hash, this.B.GetHashCode()); - return HashHelpers.Combine(hash, this.A.GetHashCode()); - } + public override int GetHashCode() => this.Bgra.GetHashCode(); /// /// Gets the representation without normalizing to [0, 1] diff --git a/src/ImageSharp/PixelFormats/Bgra4444.cs b/src/ImageSharp/PixelFormats/Bgra4444.cs index b006aa5d2..90f967f89 100644 --- a/src/ImageSharp/PixelFormats/Bgra4444.cs +++ b/src/ImageSharp/PixelFormats/Bgra4444.cs @@ -215,10 +215,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public override int GetHashCode() - { - return this.PackedValue.GetHashCode(); - } + public override int GetHashCode() => this.PackedValue.GetHashCode(); /// /// Packs the components into a . diff --git a/src/ImageSharp/PixelFormats/Bgra5551.cs b/src/ImageSharp/PixelFormats/Bgra5551.cs index 90a625142..3a18c03e8 100644 --- a/src/ImageSharp/PixelFormats/Bgra5551.cs +++ b/src/ImageSharp/PixelFormats/Bgra5551.cs @@ -221,10 +221,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// The hash code for the packed vector. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public override int GetHashCode() - { - return this.PackedValue.GetHashCode(); - } + public override int GetHashCode() => this.PackedValue.GetHashCode(); /// /// Packs the components into a . diff --git a/src/ImageSharp/PixelFormats/Byte4.cs b/src/ImageSharp/PixelFormats/Byte4.cs index 426955727..bb1b350f0 100644 --- a/src/ImageSharp/PixelFormats/Byte4.cs +++ b/src/ImageSharp/PixelFormats/Byte4.cs @@ -210,10 +210,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public override int GetHashCode() - { - return this.PackedValue.GetHashCode(); - } + public override int GetHashCode() => this.PackedValue.GetHashCode(); /// /// Returns a string representation of the current instance. diff --git a/src/ImageSharp/PixelFormats/HalfSingle.cs b/src/ImageSharp/PixelFormats/HalfSingle.cs index 54c615f9b..09b463649 100644 --- a/src/ImageSharp/PixelFormats/HalfSingle.cs +++ b/src/ImageSharp/PixelFormats/HalfSingle.cs @@ -229,10 +229,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public override int GetHashCode() - { - return this.PackedValue.GetHashCode(); - } + public override int GetHashCode() => this.PackedValue.GetHashCode(); [MethodImpl(MethodImplOptions.AggressiveInlining)] private Vector4 ToByteScaledVector4() diff --git a/src/ImageSharp/PixelFormats/HalfVector2.cs b/src/ImageSharp/PixelFormats/HalfVector2.cs index 4a135a77c..befa49736 100644 --- a/src/ImageSharp/PixelFormats/HalfVector2.cs +++ b/src/ImageSharp/PixelFormats/HalfVector2.cs @@ -231,10 +231,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public override int GetHashCode() - { - return this.PackedValue.GetHashCode(); - } + public override int GetHashCode() => this.PackedValue.GetHashCode(); /// public override bool Equals(object obj) diff --git a/src/ImageSharp/PixelFormats/HalfVector4.cs b/src/ImageSharp/PixelFormats/HalfVector4.cs index 62a25bc2b..885e02292 100644 --- a/src/ImageSharp/PixelFormats/HalfVector4.cs +++ b/src/ImageSharp/PixelFormats/HalfVector4.cs @@ -224,10 +224,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public override int GetHashCode() - { - return this.PackedValue.GetHashCode(); - } + public override int GetHashCode() => this.PackedValue.GetHashCode(); /// public override bool Equals(object obj) diff --git a/src/ImageSharp/PixelFormats/NormalizedByte2.cs b/src/ImageSharp/PixelFormats/NormalizedByte2.cs index 75a907594..8592fdd6a 100644 --- a/src/ImageSharp/PixelFormats/NormalizedByte2.cs +++ b/src/ImageSharp/PixelFormats/NormalizedByte2.cs @@ -257,10 +257,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public override int GetHashCode() - { - return this.PackedValue.GetHashCode(); - } + public override int GetHashCode() => this.PackedValue.GetHashCode(); /// public override string ToString() diff --git a/src/ImageSharp/PixelFormats/NormalizedByte4.cs b/src/ImageSharp/PixelFormats/NormalizedByte4.cs index fc3845eb2..293d536e5 100644 --- a/src/ImageSharp/PixelFormats/NormalizedByte4.cs +++ b/src/ImageSharp/PixelFormats/NormalizedByte4.cs @@ -250,10 +250,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public override int GetHashCode() - { - return this.PackedValue.GetHashCode(); - } + public override int GetHashCode() => this.PackedValue.GetHashCode(); /// public override string ToString() diff --git a/src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.cs b/src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.cs index 0d8db637d..9b1e29db8 100644 --- a/src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.cs @@ -26,17 +26,17 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders where TPixel : struct, IPixel { - internal class Normal : PixelBlender + internal class NormalSrc : PixelBlender { /// /// Gets the static instance of this blender. /// - public static Normal Instance { get; } = new Normal(); + public static NormalSrc Instance { get; } = new NormalSrc(); /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.Normal(background, source, amount); + return PorterDuffFunctions.NormalSrc(background, source, amount); } /// @@ -57,7 +57,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders for (int i = 0; i < destination.Length; i++) { - destinationSpan[i] = PorterDuffFunctions.Normal(backgroundSpan[i], sourceSpan[i], amount[i]); + destinationSpan[i] = PorterDuffFunctions.NormalSrc(backgroundSpan[i], sourceSpan[i], amount[i]); } PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); @@ -65,17 +65,17 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class Multiply : PixelBlender + internal class MultiplySrc : PixelBlender { /// /// Gets the static instance of this blender. /// - public static Multiply Instance { get; } = new Multiply(); + public static MultiplySrc Instance { get; } = new MultiplySrc(); /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.Multiply(background, source, amount); + return PorterDuffFunctions.MultiplySrc(background, source, amount); } /// @@ -96,7 +96,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders for (int i = 0; i < destination.Length; i++) { - destinationSpan[i] = PorterDuffFunctions.Multiply(backgroundSpan[i], sourceSpan[i], amount[i]); + destinationSpan[i] = PorterDuffFunctions.MultiplySrc(backgroundSpan[i], sourceSpan[i], amount[i]); } PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); @@ -104,17 +104,17 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class Add : PixelBlender + internal class AddSrc : PixelBlender { /// /// Gets the static instance of this blender. /// - public static Add Instance { get; } = new Add(); + public static AddSrc Instance { get; } = new AddSrc(); /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.Add(background, source, amount); + return PorterDuffFunctions.AddSrc(background, source, amount); } /// @@ -135,7 +135,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders for (int i = 0; i < destination.Length; i++) { - destinationSpan[i] = PorterDuffFunctions.Add(backgroundSpan[i], sourceSpan[i], amount[i]); + destinationSpan[i] = PorterDuffFunctions.AddSrc(backgroundSpan[i], sourceSpan[i], amount[i]); } PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); @@ -143,17 +143,17 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class Subtract : PixelBlender + internal class SubtractSrc : PixelBlender { /// /// Gets the static instance of this blender. /// - public static Subtract Instance { get; } = new Subtract(); + public static SubtractSrc Instance { get; } = new SubtractSrc(); /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.Subtract(background, source, amount); + return PorterDuffFunctions.SubtractSrc(background, source, amount); } /// @@ -174,7 +174,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders for (int i = 0; i < destination.Length; i++) { - destinationSpan[i] = PorterDuffFunctions.Subtract(backgroundSpan[i], sourceSpan[i], amount[i]); + destinationSpan[i] = PorterDuffFunctions.SubtractSrc(backgroundSpan[i], sourceSpan[i], amount[i]); } PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); @@ -182,17 +182,17 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class Screen : PixelBlender + internal class ScreenSrc : PixelBlender { /// /// Gets the static instance of this blender. /// - public static Screen Instance { get; } = new Screen(); + public static ScreenSrc Instance { get; } = new ScreenSrc(); /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.Screen(background, source, amount); + return PorterDuffFunctions.ScreenSrc(background, source, amount); } /// @@ -213,7 +213,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders for (int i = 0; i < destination.Length; i++) { - destinationSpan[i] = PorterDuffFunctions.Screen(backgroundSpan[i], sourceSpan[i], amount[i]); + destinationSpan[i] = PorterDuffFunctions.ScreenSrc(backgroundSpan[i], sourceSpan[i], amount[i]); } PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); @@ -221,17 +221,17 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class Darken : PixelBlender + internal class DarkenSrc : PixelBlender { /// /// Gets the static instance of this blender. /// - public static Darken Instance { get; } = new Darken(); + public static DarkenSrc Instance { get; } = new DarkenSrc(); /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.Darken(background, source, amount); + return PorterDuffFunctions.DarkenSrc(background, source, amount); } /// @@ -252,7 +252,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders for (int i = 0; i < destination.Length; i++) { - destinationSpan[i] = PorterDuffFunctions.Darken(backgroundSpan[i], sourceSpan[i], amount[i]); + destinationSpan[i] = PorterDuffFunctions.DarkenSrc(backgroundSpan[i], sourceSpan[i], amount[i]); } PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); @@ -260,17 +260,17 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class Lighten : PixelBlender + internal class LightenSrc : PixelBlender { /// /// Gets the static instance of this blender. /// - public static Lighten Instance { get; } = new Lighten(); + public static LightenSrc Instance { get; } = new LightenSrc(); /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.Lighten(background, source, amount); + return PorterDuffFunctions.LightenSrc(background, source, amount); } /// @@ -291,7 +291,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders for (int i = 0; i < destination.Length; i++) { - destinationSpan[i] = PorterDuffFunctions.Lighten(backgroundSpan[i], sourceSpan[i], amount[i]); + destinationSpan[i] = PorterDuffFunctions.LightenSrc(backgroundSpan[i], sourceSpan[i], amount[i]); } PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); @@ -299,17 +299,17 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class Overlay : PixelBlender + internal class OverlaySrc : PixelBlender { /// /// Gets the static instance of this blender. /// - public static Overlay Instance { get; } = new Overlay(); + public static OverlaySrc Instance { get; } = new OverlaySrc(); /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.Overlay(background, source, amount); + return PorterDuffFunctions.OverlaySrc(background, source, amount); } /// @@ -330,7 +330,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders for (int i = 0; i < destination.Length; i++) { - destinationSpan[i] = PorterDuffFunctions.Overlay(backgroundSpan[i], sourceSpan[i], amount[i]); + destinationSpan[i] = PorterDuffFunctions.OverlaySrc(backgroundSpan[i], sourceSpan[i], amount[i]); } PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); @@ -338,17 +338,17 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class HardLight : PixelBlender + internal class HardLightSrc : PixelBlender { /// /// Gets the static instance of this blender. /// - public static HardLight Instance { get; } = new HardLight(); + public static HardLightSrc Instance { get; } = new HardLightSrc(); /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.HardLight(background, source, amount); + return PorterDuffFunctions.HardLightSrc(background, source, amount); } /// @@ -369,7 +369,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders for (int i = 0; i < destination.Length; i++) { - destinationSpan[i] = PorterDuffFunctions.HardLight(backgroundSpan[i], sourceSpan[i], amount[i]); + destinationSpan[i] = PorterDuffFunctions.HardLightSrc(backgroundSpan[i], sourceSpan[i], amount[i]); } PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); @@ -377,17 +377,17 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class Src : PixelBlender + internal class NormalSrcAtop : PixelBlender { /// /// Gets the static instance of this blender. /// - public static Src Instance { get; } = new Src(); + public static NormalSrcAtop Instance { get; } = new NormalSrcAtop(); /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.Src(background, source, amount); + return PorterDuffFunctions.NormalSrcAtop(background, source, amount); } /// @@ -408,7 +408,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders for (int i = 0; i < destination.Length; i++) { - destinationSpan[i] = PorterDuffFunctions.Src(backgroundSpan[i], sourceSpan[i], amount[i]); + destinationSpan[i] = PorterDuffFunctions.NormalSrcAtop(backgroundSpan[i], sourceSpan[i], amount[i]); } PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); @@ -416,17 +416,17 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class Atop : PixelBlender + internal class MultiplySrcAtop : PixelBlender { /// /// Gets the static instance of this blender. /// - public static Atop Instance { get; } = new Atop(); + public static MultiplySrcAtop Instance { get; } = new MultiplySrcAtop(); /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.Atop(background, source, amount); + return PorterDuffFunctions.MultiplySrcAtop(background, source, amount); } /// @@ -447,7 +447,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders for (int i = 0; i < destination.Length; i++) { - destinationSpan[i] = PorterDuffFunctions.Atop(backgroundSpan[i], sourceSpan[i], amount[i]); + destinationSpan[i] = PorterDuffFunctions.MultiplySrcAtop(backgroundSpan[i], sourceSpan[i], amount[i]); } PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); @@ -455,17 +455,17 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class Over : PixelBlender + internal class AddSrcAtop : PixelBlender { /// /// Gets the static instance of this blender. /// - public static Over Instance { get; } = new Over(); + public static AddSrcAtop Instance { get; } = new AddSrcAtop(); /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.Over(background, source, amount); + return PorterDuffFunctions.AddSrcAtop(background, source, amount); } /// @@ -486,7 +486,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders for (int i = 0; i < destination.Length; i++) { - destinationSpan[i] = PorterDuffFunctions.Over(backgroundSpan[i], sourceSpan[i], amount[i]); + destinationSpan[i] = PorterDuffFunctions.AddSrcAtop(backgroundSpan[i], sourceSpan[i], amount[i]); } PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); @@ -494,17 +494,17 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class In : PixelBlender + internal class SubtractSrcAtop : PixelBlender { /// /// Gets the static instance of this blender. /// - public static In Instance { get; } = new In(); + public static SubtractSrcAtop Instance { get; } = new SubtractSrcAtop(); /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.In(background, source, amount); + return PorterDuffFunctions.SubtractSrcAtop(background, source, amount); } /// @@ -525,7 +525,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders for (int i = 0; i < destination.Length; i++) { - destinationSpan[i] = PorterDuffFunctions.In(backgroundSpan[i], sourceSpan[i], amount[i]); + destinationSpan[i] = PorterDuffFunctions.SubtractSrcAtop(backgroundSpan[i], sourceSpan[i], amount[i]); } PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); @@ -533,17 +533,17 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class Out : PixelBlender + internal class ScreenSrcAtop : PixelBlender { /// /// Gets the static instance of this blender. /// - public static Out Instance { get; } = new Out(); + public static ScreenSrcAtop Instance { get; } = new ScreenSrcAtop(); /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.Out(background, source, amount); + return PorterDuffFunctions.ScreenSrcAtop(background, source, amount); } /// @@ -564,7 +564,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders for (int i = 0; i < destination.Length; i++) { - destinationSpan[i] = PorterDuffFunctions.Out(backgroundSpan[i], sourceSpan[i], amount[i]); + destinationSpan[i] = PorterDuffFunctions.ScreenSrcAtop(backgroundSpan[i], sourceSpan[i], amount[i]); } PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); @@ -572,17 +572,17 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class Dest : PixelBlender + internal class DarkenSrcAtop : PixelBlender { /// /// Gets the static instance of this blender. /// - public static Dest Instance { get; } = new Dest(); + public static DarkenSrcAtop Instance { get; } = new DarkenSrcAtop(); /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.Dest(background, source, amount); + return PorterDuffFunctions.DarkenSrcAtop(background, source, amount); } /// @@ -603,7 +603,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders for (int i = 0; i < destination.Length; i++) { - destinationSpan[i] = PorterDuffFunctions.Dest(backgroundSpan[i], sourceSpan[i], amount[i]); + destinationSpan[i] = PorterDuffFunctions.DarkenSrcAtop(backgroundSpan[i], sourceSpan[i], amount[i]); } PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); @@ -611,17 +611,17 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class DestAtop : PixelBlender + internal class LightenSrcAtop : PixelBlender { /// /// Gets the static instance of this blender. /// - public static DestAtop Instance { get; } = new DestAtop(); + public static LightenSrcAtop Instance { get; } = new LightenSrcAtop(); /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.DestAtop(background, source, amount); + return PorterDuffFunctions.LightenSrcAtop(background, source, amount); } /// @@ -642,7 +642,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders for (int i = 0; i < destination.Length; i++) { - destinationSpan[i] = PorterDuffFunctions.DestAtop(backgroundSpan[i], sourceSpan[i], amount[i]); + destinationSpan[i] = PorterDuffFunctions.LightenSrcAtop(backgroundSpan[i], sourceSpan[i], amount[i]); } PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); @@ -650,17 +650,17 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class DestOver : PixelBlender + internal class OverlaySrcAtop : PixelBlender { /// /// Gets the static instance of this blender. /// - public static DestOver Instance { get; } = new DestOver(); + public static OverlaySrcAtop Instance { get; } = new OverlaySrcAtop(); /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.DestOver(background, source, amount); + return PorterDuffFunctions.OverlaySrcAtop(background, source, amount); } /// @@ -681,7 +681,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders for (int i = 0; i < destination.Length; i++) { - destinationSpan[i] = PorterDuffFunctions.DestOver(backgroundSpan[i], sourceSpan[i], amount[i]); + destinationSpan[i] = PorterDuffFunctions.OverlaySrcAtop(backgroundSpan[i], sourceSpan[i], amount[i]); } PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); @@ -689,17 +689,17 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class DestIn : PixelBlender + internal class HardLightSrcAtop : PixelBlender { /// /// Gets the static instance of this blender. /// - public static DestIn Instance { get; } = new DestIn(); + public static HardLightSrcAtop Instance { get; } = new HardLightSrcAtop(); /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.DestIn(background, source, amount); + return PorterDuffFunctions.HardLightSrcAtop(background, source, amount); } /// @@ -720,7 +720,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders for (int i = 0; i < destination.Length; i++) { - destinationSpan[i] = PorterDuffFunctions.DestIn(backgroundSpan[i], sourceSpan[i], amount[i]); + destinationSpan[i] = PorterDuffFunctions.HardLightSrcAtop(backgroundSpan[i], sourceSpan[i], amount[i]); } PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); @@ -728,17 +728,17 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class DestOut : PixelBlender + internal class NormalSrcOver : PixelBlender { /// /// Gets the static instance of this blender. /// - public static DestOut Instance { get; } = new DestOut(); + public static NormalSrcOver Instance { get; } = new NormalSrcOver(); /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.DestOut(background, source, amount); + return PorterDuffFunctions.NormalSrcOver(background, source, amount); } /// @@ -759,7 +759,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders for (int i = 0; i < destination.Length; i++) { - destinationSpan[i] = PorterDuffFunctions.DestOut(backgroundSpan[i], sourceSpan[i], amount[i]); + destinationSpan[i] = PorterDuffFunctions.NormalSrcOver(backgroundSpan[i], sourceSpan[i], amount[i]); } PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); @@ -767,17 +767,17 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class Clear : PixelBlender + internal class MultiplySrcOver : PixelBlender { /// /// Gets the static instance of this blender. /// - public static Clear Instance { get; } = new Clear(); + public static MultiplySrcOver Instance { get; } = new MultiplySrcOver(); /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.Clear(background, source, amount); + return PorterDuffFunctions.MultiplySrcOver(background, source, amount); } /// @@ -798,7 +798,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders for (int i = 0; i < destination.Length; i++) { - destinationSpan[i] = PorterDuffFunctions.Clear(backgroundSpan[i], sourceSpan[i], amount[i]); + destinationSpan[i] = PorterDuffFunctions.MultiplySrcOver(backgroundSpan[i], sourceSpan[i], amount[i]); } PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); @@ -806,17 +806,17 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class Xor : PixelBlender + internal class AddSrcOver : PixelBlender { /// /// Gets the static instance of this blender. /// - public static Xor Instance { get; } = new Xor(); + public static AddSrcOver Instance { get; } = new AddSrcOver(); /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.Xor(background, source, amount); + return PorterDuffFunctions.AddSrcOver(background, source, amount); } /// @@ -837,7 +837,3400 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders for (int i = 0; i < destination.Length; i++) { - destinationSpan[i] = PorterDuffFunctions.Xor(backgroundSpan[i], sourceSpan[i], amount[i]); + destinationSpan[i] = PorterDuffFunctions.AddSrcOver(backgroundSpan[i], sourceSpan[i], amount[i]); + } + + PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); + } + } + } + + internal class SubtractSrcOver : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static SubtractSrcOver Instance { get; } = new SubtractSrcOver(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + return PorterDuffFunctions.SubtractSrcOver(background, source, amount); + } + + /// + public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + { + Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); + Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); + Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); + + using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + { + Span destinationSpan = buffer.Slice(0, destination.Length); + Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); + Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); + + PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); + PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); + + for (int i = 0; i < destination.Length; i++) + { + destinationSpan[i] = PorterDuffFunctions.SubtractSrcOver(backgroundSpan[i], sourceSpan[i], amount[i]); + } + + PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); + } + } + } + + internal class ScreenSrcOver : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static ScreenSrcOver Instance { get; } = new ScreenSrcOver(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + return PorterDuffFunctions.ScreenSrcOver(background, source, amount); + } + + /// + public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + { + Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); + Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); + Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); + + using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + { + Span destinationSpan = buffer.Slice(0, destination.Length); + Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); + Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); + + PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); + PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); + + for (int i = 0; i < destination.Length; i++) + { + destinationSpan[i] = PorterDuffFunctions.ScreenSrcOver(backgroundSpan[i], sourceSpan[i], amount[i]); + } + + PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); + } + } + } + + internal class DarkenSrcOver : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static DarkenSrcOver Instance { get; } = new DarkenSrcOver(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + return PorterDuffFunctions.DarkenSrcOver(background, source, amount); + } + + /// + public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + { + Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); + Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); + Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); + + using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + { + Span destinationSpan = buffer.Slice(0, destination.Length); + Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); + Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); + + PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); + PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); + + for (int i = 0; i < destination.Length; i++) + { + destinationSpan[i] = PorterDuffFunctions.DarkenSrcOver(backgroundSpan[i], sourceSpan[i], amount[i]); + } + + PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); + } + } + } + + internal class LightenSrcOver : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static LightenSrcOver Instance { get; } = new LightenSrcOver(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + return PorterDuffFunctions.LightenSrcOver(background, source, amount); + } + + /// + public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + { + Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); + Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); + Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); + + using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + { + Span destinationSpan = buffer.Slice(0, destination.Length); + Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); + Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); + + PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); + PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); + + for (int i = 0; i < destination.Length; i++) + { + destinationSpan[i] = PorterDuffFunctions.LightenSrcOver(backgroundSpan[i], sourceSpan[i], amount[i]); + } + + PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); + } + } + } + + internal class OverlaySrcOver : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static OverlaySrcOver Instance { get; } = new OverlaySrcOver(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + return PorterDuffFunctions.OverlaySrcOver(background, source, amount); + } + + /// + public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + { + Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); + Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); + Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); + + using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + { + Span destinationSpan = buffer.Slice(0, destination.Length); + Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); + Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); + + PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); + PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); + + for (int i = 0; i < destination.Length; i++) + { + destinationSpan[i] = PorterDuffFunctions.OverlaySrcOver(backgroundSpan[i], sourceSpan[i], amount[i]); + } + + PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); + } + } + } + + internal class HardLightSrcOver : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static HardLightSrcOver Instance { get; } = new HardLightSrcOver(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + return PorterDuffFunctions.HardLightSrcOver(background, source, amount); + } + + /// + public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + { + Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); + Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); + Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); + + using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + { + Span destinationSpan = buffer.Slice(0, destination.Length); + Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); + Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); + + PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); + PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); + + for (int i = 0; i < destination.Length; i++) + { + destinationSpan[i] = PorterDuffFunctions.HardLightSrcOver(backgroundSpan[i], sourceSpan[i], amount[i]); + } + + PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); + } + } + } + + internal class NormalSrcIn : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static NormalSrcIn Instance { get; } = new NormalSrcIn(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + return PorterDuffFunctions.NormalSrcIn(background, source, amount); + } + + /// + public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + { + Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); + Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); + Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); + + using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + { + Span destinationSpan = buffer.Slice(0, destination.Length); + Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); + Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); + + PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); + PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); + + for (int i = 0; i < destination.Length; i++) + { + destinationSpan[i] = PorterDuffFunctions.NormalSrcIn(backgroundSpan[i], sourceSpan[i], amount[i]); + } + + PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); + } + } + } + + internal class MultiplySrcIn : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static MultiplySrcIn Instance { get; } = new MultiplySrcIn(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + return PorterDuffFunctions.MultiplySrcIn(background, source, amount); + } + + /// + public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + { + Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); + Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); + Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); + + using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + { + Span destinationSpan = buffer.Slice(0, destination.Length); + Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); + Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); + + PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); + PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); + + for (int i = 0; i < destination.Length; i++) + { + destinationSpan[i] = PorterDuffFunctions.MultiplySrcIn(backgroundSpan[i], sourceSpan[i], amount[i]); + } + + PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); + } + } + } + + internal class AddSrcIn : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static AddSrcIn Instance { get; } = new AddSrcIn(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + return PorterDuffFunctions.AddSrcIn(background, source, amount); + } + + /// + public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + { + Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); + Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); + Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); + + using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + { + Span destinationSpan = buffer.Slice(0, destination.Length); + Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); + Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); + + PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); + PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); + + for (int i = 0; i < destination.Length; i++) + { + destinationSpan[i] = PorterDuffFunctions.AddSrcIn(backgroundSpan[i], sourceSpan[i], amount[i]); + } + + PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); + } + } + } + + internal class SubtractSrcIn : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static SubtractSrcIn Instance { get; } = new SubtractSrcIn(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + return PorterDuffFunctions.SubtractSrcIn(background, source, amount); + } + + /// + public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + { + Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); + Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); + Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); + + using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + { + Span destinationSpan = buffer.Slice(0, destination.Length); + Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); + Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); + + PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); + PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); + + for (int i = 0; i < destination.Length; i++) + { + destinationSpan[i] = PorterDuffFunctions.SubtractSrcIn(backgroundSpan[i], sourceSpan[i], amount[i]); + } + + PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); + } + } + } + + internal class ScreenSrcIn : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static ScreenSrcIn Instance { get; } = new ScreenSrcIn(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + return PorterDuffFunctions.ScreenSrcIn(background, source, amount); + } + + /// + public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + { + Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); + Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); + Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); + + using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + { + Span destinationSpan = buffer.Slice(0, destination.Length); + Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); + Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); + + PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); + PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); + + for (int i = 0; i < destination.Length; i++) + { + destinationSpan[i] = PorterDuffFunctions.ScreenSrcIn(backgroundSpan[i], sourceSpan[i], amount[i]); + } + + PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); + } + } + } + + internal class DarkenSrcIn : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static DarkenSrcIn Instance { get; } = new DarkenSrcIn(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + return PorterDuffFunctions.DarkenSrcIn(background, source, amount); + } + + /// + public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + { + Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); + Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); + Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); + + using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + { + Span destinationSpan = buffer.Slice(0, destination.Length); + Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); + Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); + + PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); + PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); + + for (int i = 0; i < destination.Length; i++) + { + destinationSpan[i] = PorterDuffFunctions.DarkenSrcIn(backgroundSpan[i], sourceSpan[i], amount[i]); + } + + PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); + } + } + } + + internal class LightenSrcIn : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static LightenSrcIn Instance { get; } = new LightenSrcIn(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + return PorterDuffFunctions.LightenSrcIn(background, source, amount); + } + + /// + public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + { + Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); + Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); + Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); + + using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + { + Span destinationSpan = buffer.Slice(0, destination.Length); + Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); + Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); + + PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); + PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); + + for (int i = 0; i < destination.Length; i++) + { + destinationSpan[i] = PorterDuffFunctions.LightenSrcIn(backgroundSpan[i], sourceSpan[i], amount[i]); + } + + PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); + } + } + } + + internal class OverlaySrcIn : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static OverlaySrcIn Instance { get; } = new OverlaySrcIn(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + return PorterDuffFunctions.OverlaySrcIn(background, source, amount); + } + + /// + public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + { + Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); + Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); + Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); + + using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + { + Span destinationSpan = buffer.Slice(0, destination.Length); + Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); + Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); + + PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); + PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); + + for (int i = 0; i < destination.Length; i++) + { + destinationSpan[i] = PorterDuffFunctions.OverlaySrcIn(backgroundSpan[i], sourceSpan[i], amount[i]); + } + + PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); + } + } + } + + internal class HardLightSrcIn : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static HardLightSrcIn Instance { get; } = new HardLightSrcIn(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + return PorterDuffFunctions.HardLightSrcIn(background, source, amount); + } + + /// + public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + { + Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); + Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); + Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); + + using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + { + Span destinationSpan = buffer.Slice(0, destination.Length); + Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); + Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); + + PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); + PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); + + for (int i = 0; i < destination.Length; i++) + { + destinationSpan[i] = PorterDuffFunctions.HardLightSrcIn(backgroundSpan[i], sourceSpan[i], amount[i]); + } + + PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); + } + } + } + + internal class NormalSrcOut : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static NormalSrcOut Instance { get; } = new NormalSrcOut(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + return PorterDuffFunctions.NormalSrcOut(background, source, amount); + } + + /// + public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + { + Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); + Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); + Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); + + using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + { + Span destinationSpan = buffer.Slice(0, destination.Length); + Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); + Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); + + PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); + PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); + + for (int i = 0; i < destination.Length; i++) + { + destinationSpan[i] = PorterDuffFunctions.NormalSrcOut(backgroundSpan[i], sourceSpan[i], amount[i]); + } + + PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); + } + } + } + + internal class MultiplySrcOut : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static MultiplySrcOut Instance { get; } = new MultiplySrcOut(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + return PorterDuffFunctions.MultiplySrcOut(background, source, amount); + } + + /// + public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + { + Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); + Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); + Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); + + using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + { + Span destinationSpan = buffer.Slice(0, destination.Length); + Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); + Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); + + PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); + PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); + + for (int i = 0; i < destination.Length; i++) + { + destinationSpan[i] = PorterDuffFunctions.MultiplySrcOut(backgroundSpan[i], sourceSpan[i], amount[i]); + } + + PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); + } + } + } + + internal class AddSrcOut : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static AddSrcOut Instance { get; } = new AddSrcOut(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + return PorterDuffFunctions.AddSrcOut(background, source, amount); + } + + /// + public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + { + Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); + Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); + Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); + + using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + { + Span destinationSpan = buffer.Slice(0, destination.Length); + Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); + Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); + + PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); + PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); + + for (int i = 0; i < destination.Length; i++) + { + destinationSpan[i] = PorterDuffFunctions.AddSrcOut(backgroundSpan[i], sourceSpan[i], amount[i]); + } + + PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); + } + } + } + + internal class SubtractSrcOut : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static SubtractSrcOut Instance { get; } = new SubtractSrcOut(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + return PorterDuffFunctions.SubtractSrcOut(background, source, amount); + } + + /// + public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + { + Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); + Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); + Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); + + using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + { + Span destinationSpan = buffer.Slice(0, destination.Length); + Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); + Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); + + PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); + PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); + + for (int i = 0; i < destination.Length; i++) + { + destinationSpan[i] = PorterDuffFunctions.SubtractSrcOut(backgroundSpan[i], sourceSpan[i], amount[i]); + } + + PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); + } + } + } + + internal class ScreenSrcOut : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static ScreenSrcOut Instance { get; } = new ScreenSrcOut(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + return PorterDuffFunctions.ScreenSrcOut(background, source, amount); + } + + /// + public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + { + Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); + Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); + Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); + + using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + { + Span destinationSpan = buffer.Slice(0, destination.Length); + Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); + Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); + + PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); + PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); + + for (int i = 0; i < destination.Length; i++) + { + destinationSpan[i] = PorterDuffFunctions.ScreenSrcOut(backgroundSpan[i], sourceSpan[i], amount[i]); + } + + PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); + } + } + } + + internal class DarkenSrcOut : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static DarkenSrcOut Instance { get; } = new DarkenSrcOut(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + return PorterDuffFunctions.DarkenSrcOut(background, source, amount); + } + + /// + public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + { + Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); + Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); + Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); + + using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + { + Span destinationSpan = buffer.Slice(0, destination.Length); + Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); + Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); + + PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); + PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); + + for (int i = 0; i < destination.Length; i++) + { + destinationSpan[i] = PorterDuffFunctions.DarkenSrcOut(backgroundSpan[i], sourceSpan[i], amount[i]); + } + + PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); + } + } + } + + internal class LightenSrcOut : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static LightenSrcOut Instance { get; } = new LightenSrcOut(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + return PorterDuffFunctions.LightenSrcOut(background, source, amount); + } + + /// + public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + { + Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); + Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); + Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); + + using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + { + Span destinationSpan = buffer.Slice(0, destination.Length); + Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); + Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); + + PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); + PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); + + for (int i = 0; i < destination.Length; i++) + { + destinationSpan[i] = PorterDuffFunctions.LightenSrcOut(backgroundSpan[i], sourceSpan[i], amount[i]); + } + + PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); + } + } + } + + internal class OverlaySrcOut : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static OverlaySrcOut Instance { get; } = new OverlaySrcOut(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + return PorterDuffFunctions.OverlaySrcOut(background, source, amount); + } + + /// + public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + { + Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); + Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); + Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); + + using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + { + Span destinationSpan = buffer.Slice(0, destination.Length); + Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); + Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); + + PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); + PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); + + for (int i = 0; i < destination.Length; i++) + { + destinationSpan[i] = PorterDuffFunctions.OverlaySrcOut(backgroundSpan[i], sourceSpan[i], amount[i]); + } + + PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); + } + } + } + + internal class HardLightSrcOut : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static HardLightSrcOut Instance { get; } = new HardLightSrcOut(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + return PorterDuffFunctions.HardLightSrcOut(background, source, amount); + } + + /// + public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + { + Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); + Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); + Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); + + using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + { + Span destinationSpan = buffer.Slice(0, destination.Length); + Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); + Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); + + PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); + PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); + + for (int i = 0; i < destination.Length; i++) + { + destinationSpan[i] = PorterDuffFunctions.HardLightSrcOut(backgroundSpan[i], sourceSpan[i], amount[i]); + } + + PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); + } + } + } + + internal class NormalDest : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static NormalDest Instance { get; } = new NormalDest(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + return PorterDuffFunctions.NormalDest(background, source, amount); + } + + /// + public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + { + Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); + Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); + Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); + + using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + { + Span destinationSpan = buffer.Slice(0, destination.Length); + Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); + Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); + + PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); + PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); + + for (int i = 0; i < destination.Length; i++) + { + destinationSpan[i] = PorterDuffFunctions.NormalDest(backgroundSpan[i], sourceSpan[i], amount[i]); + } + + PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); + } + } + } + + internal class MultiplyDest : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static MultiplyDest Instance { get; } = new MultiplyDest(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + return PorterDuffFunctions.MultiplyDest(background, source, amount); + } + + /// + public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + { + Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); + Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); + Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); + + using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + { + Span destinationSpan = buffer.Slice(0, destination.Length); + Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); + Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); + + PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); + PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); + + for (int i = 0; i < destination.Length; i++) + { + destinationSpan[i] = PorterDuffFunctions.MultiplyDest(backgroundSpan[i], sourceSpan[i], amount[i]); + } + + PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); + } + } + } + + internal class AddDest : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static AddDest Instance { get; } = new AddDest(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + return PorterDuffFunctions.AddDest(background, source, amount); + } + + /// + public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + { + Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); + Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); + Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); + + using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + { + Span destinationSpan = buffer.Slice(0, destination.Length); + Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); + Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); + + PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); + PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); + + for (int i = 0; i < destination.Length; i++) + { + destinationSpan[i] = PorterDuffFunctions.AddDest(backgroundSpan[i], sourceSpan[i], amount[i]); + } + + PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); + } + } + } + + internal class SubtractDest : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static SubtractDest Instance { get; } = new SubtractDest(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + return PorterDuffFunctions.SubtractDest(background, source, amount); + } + + /// + public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + { + Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); + Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); + Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); + + using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + { + Span destinationSpan = buffer.Slice(0, destination.Length); + Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); + Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); + + PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); + PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); + + for (int i = 0; i < destination.Length; i++) + { + destinationSpan[i] = PorterDuffFunctions.SubtractDest(backgroundSpan[i], sourceSpan[i], amount[i]); + } + + PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); + } + } + } + + internal class ScreenDest : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static ScreenDest Instance { get; } = new ScreenDest(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + return PorterDuffFunctions.ScreenDest(background, source, amount); + } + + /// + public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + { + Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); + Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); + Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); + + using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + { + Span destinationSpan = buffer.Slice(0, destination.Length); + Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); + Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); + + PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); + PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); + + for (int i = 0; i < destination.Length; i++) + { + destinationSpan[i] = PorterDuffFunctions.ScreenDest(backgroundSpan[i], sourceSpan[i], amount[i]); + } + + PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); + } + } + } + + internal class DarkenDest : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static DarkenDest Instance { get; } = new DarkenDest(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + return PorterDuffFunctions.DarkenDest(background, source, amount); + } + + /// + public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + { + Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); + Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); + Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); + + using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + { + Span destinationSpan = buffer.Slice(0, destination.Length); + Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); + Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); + + PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); + PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); + + for (int i = 0; i < destination.Length; i++) + { + destinationSpan[i] = PorterDuffFunctions.DarkenDest(backgroundSpan[i], sourceSpan[i], amount[i]); + } + + PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); + } + } + } + + internal class LightenDest : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static LightenDest Instance { get; } = new LightenDest(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + return PorterDuffFunctions.LightenDest(background, source, amount); + } + + /// + public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + { + Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); + Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); + Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); + + using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + { + Span destinationSpan = buffer.Slice(0, destination.Length); + Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); + Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); + + PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); + PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); + + for (int i = 0; i < destination.Length; i++) + { + destinationSpan[i] = PorterDuffFunctions.LightenDest(backgroundSpan[i], sourceSpan[i], amount[i]); + } + + PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); + } + } + } + + internal class OverlayDest : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static OverlayDest Instance { get; } = new OverlayDest(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + return PorterDuffFunctions.OverlayDest(background, source, amount); + } + + /// + public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + { + Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); + Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); + Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); + + using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + { + Span destinationSpan = buffer.Slice(0, destination.Length); + Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); + Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); + + PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); + PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); + + for (int i = 0; i < destination.Length; i++) + { + destinationSpan[i] = PorterDuffFunctions.OverlayDest(backgroundSpan[i], sourceSpan[i], amount[i]); + } + + PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); + } + } + } + + internal class HardLightDest : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static HardLightDest Instance { get; } = new HardLightDest(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + return PorterDuffFunctions.HardLightDest(background, source, amount); + } + + /// + public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + { + Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); + Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); + Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); + + using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + { + Span destinationSpan = buffer.Slice(0, destination.Length); + Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); + Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); + + PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); + PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); + + for (int i = 0; i < destination.Length; i++) + { + destinationSpan[i] = PorterDuffFunctions.HardLightDest(backgroundSpan[i], sourceSpan[i], amount[i]); + } + + PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); + } + } + } + + internal class NormalDestAtop : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static NormalDestAtop Instance { get; } = new NormalDestAtop(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + return PorterDuffFunctions.NormalDestAtop(background, source, amount); + } + + /// + public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + { + Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); + Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); + Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); + + using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + { + Span destinationSpan = buffer.Slice(0, destination.Length); + Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); + Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); + + PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); + PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); + + for (int i = 0; i < destination.Length; i++) + { + destinationSpan[i] = PorterDuffFunctions.NormalDestAtop(backgroundSpan[i], sourceSpan[i], amount[i]); + } + + PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); + } + } + } + + internal class MultiplyDestAtop : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static MultiplyDestAtop Instance { get; } = new MultiplyDestAtop(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + return PorterDuffFunctions.MultiplyDestAtop(background, source, amount); + } + + /// + public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + { + Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); + Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); + Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); + + using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + { + Span destinationSpan = buffer.Slice(0, destination.Length); + Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); + Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); + + PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); + PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); + + for (int i = 0; i < destination.Length; i++) + { + destinationSpan[i] = PorterDuffFunctions.MultiplyDestAtop(backgroundSpan[i], sourceSpan[i], amount[i]); + } + + PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); + } + } + } + + internal class AddDestAtop : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static AddDestAtop Instance { get; } = new AddDestAtop(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + return PorterDuffFunctions.AddDestAtop(background, source, amount); + } + + /// + public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + { + Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); + Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); + Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); + + using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + { + Span destinationSpan = buffer.Slice(0, destination.Length); + Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); + Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); + + PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); + PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); + + for (int i = 0; i < destination.Length; i++) + { + destinationSpan[i] = PorterDuffFunctions.AddDestAtop(backgroundSpan[i], sourceSpan[i], amount[i]); + } + + PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); + } + } + } + + internal class SubtractDestAtop : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static SubtractDestAtop Instance { get; } = new SubtractDestAtop(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + return PorterDuffFunctions.SubtractDestAtop(background, source, amount); + } + + /// + public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + { + Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); + Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); + Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); + + using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + { + Span destinationSpan = buffer.Slice(0, destination.Length); + Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); + Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); + + PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); + PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); + + for (int i = 0; i < destination.Length; i++) + { + destinationSpan[i] = PorterDuffFunctions.SubtractDestAtop(backgroundSpan[i], sourceSpan[i], amount[i]); + } + + PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); + } + } + } + + internal class ScreenDestAtop : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static ScreenDestAtop Instance { get; } = new ScreenDestAtop(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + return PorterDuffFunctions.ScreenDestAtop(background, source, amount); + } + + /// + public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + { + Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); + Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); + Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); + + using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + { + Span destinationSpan = buffer.Slice(0, destination.Length); + Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); + Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); + + PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); + PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); + + for (int i = 0; i < destination.Length; i++) + { + destinationSpan[i] = PorterDuffFunctions.ScreenDestAtop(backgroundSpan[i], sourceSpan[i], amount[i]); + } + + PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); + } + } + } + + internal class DarkenDestAtop : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static DarkenDestAtop Instance { get; } = new DarkenDestAtop(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + return PorterDuffFunctions.DarkenDestAtop(background, source, amount); + } + + /// + public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + { + Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); + Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); + Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); + + using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + { + Span destinationSpan = buffer.Slice(0, destination.Length); + Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); + Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); + + PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); + PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); + + for (int i = 0; i < destination.Length; i++) + { + destinationSpan[i] = PorterDuffFunctions.DarkenDestAtop(backgroundSpan[i], sourceSpan[i], amount[i]); + } + + PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); + } + } + } + + internal class LightenDestAtop : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static LightenDestAtop Instance { get; } = new LightenDestAtop(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + return PorterDuffFunctions.LightenDestAtop(background, source, amount); + } + + /// + public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + { + Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); + Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); + Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); + + using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + { + Span destinationSpan = buffer.Slice(0, destination.Length); + Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); + Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); + + PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); + PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); + + for (int i = 0; i < destination.Length; i++) + { + destinationSpan[i] = PorterDuffFunctions.LightenDestAtop(backgroundSpan[i], sourceSpan[i], amount[i]); + } + + PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); + } + } + } + + internal class OverlayDestAtop : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static OverlayDestAtop Instance { get; } = new OverlayDestAtop(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + return PorterDuffFunctions.OverlayDestAtop(background, source, amount); + } + + /// + public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + { + Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); + Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); + Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); + + using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + { + Span destinationSpan = buffer.Slice(0, destination.Length); + Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); + Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); + + PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); + PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); + + for (int i = 0; i < destination.Length; i++) + { + destinationSpan[i] = PorterDuffFunctions.OverlayDestAtop(backgroundSpan[i], sourceSpan[i], amount[i]); + } + + PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); + } + } + } + + internal class HardLightDestAtop : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static HardLightDestAtop Instance { get; } = new HardLightDestAtop(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + return PorterDuffFunctions.HardLightDestAtop(background, source, amount); + } + + /// + public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + { + Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); + Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); + Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); + + using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + { + Span destinationSpan = buffer.Slice(0, destination.Length); + Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); + Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); + + PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); + PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); + + for (int i = 0; i < destination.Length; i++) + { + destinationSpan[i] = PorterDuffFunctions.HardLightDestAtop(backgroundSpan[i], sourceSpan[i], amount[i]); + } + + PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); + } + } + } + + internal class NormalDestOver : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static NormalDestOver Instance { get; } = new NormalDestOver(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + return PorterDuffFunctions.NormalDestOver(background, source, amount); + } + + /// + public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + { + Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); + Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); + Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); + + using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + { + Span destinationSpan = buffer.Slice(0, destination.Length); + Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); + Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); + + PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); + PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); + + for (int i = 0; i < destination.Length; i++) + { + destinationSpan[i] = PorterDuffFunctions.NormalDestOver(backgroundSpan[i], sourceSpan[i], amount[i]); + } + + PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); + } + } + } + + internal class MultiplyDestOver : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static MultiplyDestOver Instance { get; } = new MultiplyDestOver(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + return PorterDuffFunctions.MultiplyDestOver(background, source, amount); + } + + /// + public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + { + Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); + Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); + Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); + + using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + { + Span destinationSpan = buffer.Slice(0, destination.Length); + Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); + Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); + + PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); + PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); + + for (int i = 0; i < destination.Length; i++) + { + destinationSpan[i] = PorterDuffFunctions.MultiplyDestOver(backgroundSpan[i], sourceSpan[i], amount[i]); + } + + PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); + } + } + } + + internal class AddDestOver : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static AddDestOver Instance { get; } = new AddDestOver(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + return PorterDuffFunctions.AddDestOver(background, source, amount); + } + + /// + public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + { + Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); + Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); + Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); + + using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + { + Span destinationSpan = buffer.Slice(0, destination.Length); + Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); + Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); + + PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); + PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); + + for (int i = 0; i < destination.Length; i++) + { + destinationSpan[i] = PorterDuffFunctions.AddDestOver(backgroundSpan[i], sourceSpan[i], amount[i]); + } + + PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); + } + } + } + + internal class SubtractDestOver : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static SubtractDestOver Instance { get; } = new SubtractDestOver(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + return PorterDuffFunctions.SubtractDestOver(background, source, amount); + } + + /// + public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + { + Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); + Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); + Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); + + using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + { + Span destinationSpan = buffer.Slice(0, destination.Length); + Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); + Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); + + PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); + PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); + + for (int i = 0; i < destination.Length; i++) + { + destinationSpan[i] = PorterDuffFunctions.SubtractDestOver(backgroundSpan[i], sourceSpan[i], amount[i]); + } + + PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); + } + } + } + + internal class ScreenDestOver : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static ScreenDestOver Instance { get; } = new ScreenDestOver(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + return PorterDuffFunctions.ScreenDestOver(background, source, amount); + } + + /// + public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + { + Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); + Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); + Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); + + using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + { + Span destinationSpan = buffer.Slice(0, destination.Length); + Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); + Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); + + PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); + PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); + + for (int i = 0; i < destination.Length; i++) + { + destinationSpan[i] = PorterDuffFunctions.ScreenDestOver(backgroundSpan[i], sourceSpan[i], amount[i]); + } + + PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); + } + } + } + + internal class DarkenDestOver : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static DarkenDestOver Instance { get; } = new DarkenDestOver(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + return PorterDuffFunctions.DarkenDestOver(background, source, amount); + } + + /// + public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + { + Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); + Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); + Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); + + using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + { + Span destinationSpan = buffer.Slice(0, destination.Length); + Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); + Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); + + PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); + PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); + + for (int i = 0; i < destination.Length; i++) + { + destinationSpan[i] = PorterDuffFunctions.DarkenDestOver(backgroundSpan[i], sourceSpan[i], amount[i]); + } + + PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); + } + } + } + + internal class LightenDestOver : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static LightenDestOver Instance { get; } = new LightenDestOver(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + return PorterDuffFunctions.LightenDestOver(background, source, amount); + } + + /// + public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + { + Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); + Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); + Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); + + using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + { + Span destinationSpan = buffer.Slice(0, destination.Length); + Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); + Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); + + PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); + PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); + + for (int i = 0; i < destination.Length; i++) + { + destinationSpan[i] = PorterDuffFunctions.LightenDestOver(backgroundSpan[i], sourceSpan[i], amount[i]); + } + + PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); + } + } + } + + internal class OverlayDestOver : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static OverlayDestOver Instance { get; } = new OverlayDestOver(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + return PorterDuffFunctions.OverlayDestOver(background, source, amount); + } + + /// + public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + { + Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); + Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); + Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); + + using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + { + Span destinationSpan = buffer.Slice(0, destination.Length); + Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); + Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); + + PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); + PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); + + for (int i = 0; i < destination.Length; i++) + { + destinationSpan[i] = PorterDuffFunctions.OverlayDestOver(backgroundSpan[i], sourceSpan[i], amount[i]); + } + + PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); + } + } + } + + internal class HardLightDestOver : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static HardLightDestOver Instance { get; } = new HardLightDestOver(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + return PorterDuffFunctions.HardLightDestOver(background, source, amount); + } + + /// + public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + { + Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); + Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); + Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); + + using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + { + Span destinationSpan = buffer.Slice(0, destination.Length); + Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); + Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); + + PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); + PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); + + for (int i = 0; i < destination.Length; i++) + { + destinationSpan[i] = PorterDuffFunctions.HardLightDestOver(backgroundSpan[i], sourceSpan[i], amount[i]); + } + + PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); + } + } + } + + internal class NormalDestIn : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static NormalDestIn Instance { get; } = new NormalDestIn(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + return PorterDuffFunctions.NormalDestIn(background, source, amount); + } + + /// + public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + { + Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); + Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); + Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); + + using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + { + Span destinationSpan = buffer.Slice(0, destination.Length); + Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); + Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); + + PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); + PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); + + for (int i = 0; i < destination.Length; i++) + { + destinationSpan[i] = PorterDuffFunctions.NormalDestIn(backgroundSpan[i], sourceSpan[i], amount[i]); + } + + PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); + } + } + } + + internal class MultiplyDestIn : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static MultiplyDestIn Instance { get; } = new MultiplyDestIn(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + return PorterDuffFunctions.MultiplyDestIn(background, source, amount); + } + + /// + public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + { + Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); + Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); + Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); + + using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + { + Span destinationSpan = buffer.Slice(0, destination.Length); + Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); + Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); + + PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); + PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); + + for (int i = 0; i < destination.Length; i++) + { + destinationSpan[i] = PorterDuffFunctions.MultiplyDestIn(backgroundSpan[i], sourceSpan[i], amount[i]); + } + + PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); + } + } + } + + internal class AddDestIn : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static AddDestIn Instance { get; } = new AddDestIn(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + return PorterDuffFunctions.AddDestIn(background, source, amount); + } + + /// + public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + { + Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); + Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); + Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); + + using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + { + Span destinationSpan = buffer.Slice(0, destination.Length); + Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); + Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); + + PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); + PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); + + for (int i = 0; i < destination.Length; i++) + { + destinationSpan[i] = PorterDuffFunctions.AddDestIn(backgroundSpan[i], sourceSpan[i], amount[i]); + } + + PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); + } + } + } + + internal class SubtractDestIn : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static SubtractDestIn Instance { get; } = new SubtractDestIn(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + return PorterDuffFunctions.SubtractDestIn(background, source, amount); + } + + /// + public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + { + Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); + Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); + Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); + + using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + { + Span destinationSpan = buffer.Slice(0, destination.Length); + Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); + Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); + + PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); + PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); + + for (int i = 0; i < destination.Length; i++) + { + destinationSpan[i] = PorterDuffFunctions.SubtractDestIn(backgroundSpan[i], sourceSpan[i], amount[i]); + } + + PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); + } + } + } + + internal class ScreenDestIn : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static ScreenDestIn Instance { get; } = new ScreenDestIn(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + return PorterDuffFunctions.ScreenDestIn(background, source, amount); + } + + /// + public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + { + Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); + Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); + Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); + + using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + { + Span destinationSpan = buffer.Slice(0, destination.Length); + Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); + Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); + + PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); + PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); + + for (int i = 0; i < destination.Length; i++) + { + destinationSpan[i] = PorterDuffFunctions.ScreenDestIn(backgroundSpan[i], sourceSpan[i], amount[i]); + } + + PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); + } + } + } + + internal class DarkenDestIn : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static DarkenDestIn Instance { get; } = new DarkenDestIn(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + return PorterDuffFunctions.DarkenDestIn(background, source, amount); + } + + /// + public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + { + Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); + Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); + Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); + + using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + { + Span destinationSpan = buffer.Slice(0, destination.Length); + Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); + Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); + + PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); + PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); + + for (int i = 0; i < destination.Length; i++) + { + destinationSpan[i] = PorterDuffFunctions.DarkenDestIn(backgroundSpan[i], sourceSpan[i], amount[i]); + } + + PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); + } + } + } + + internal class LightenDestIn : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static LightenDestIn Instance { get; } = new LightenDestIn(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + return PorterDuffFunctions.LightenDestIn(background, source, amount); + } + + /// + public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + { + Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); + Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); + Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); + + using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + { + Span destinationSpan = buffer.Slice(0, destination.Length); + Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); + Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); + + PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); + PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); + + for (int i = 0; i < destination.Length; i++) + { + destinationSpan[i] = PorterDuffFunctions.LightenDestIn(backgroundSpan[i], sourceSpan[i], amount[i]); + } + + PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); + } + } + } + + internal class OverlayDestIn : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static OverlayDestIn Instance { get; } = new OverlayDestIn(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + return PorterDuffFunctions.OverlayDestIn(background, source, amount); + } + + /// + public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + { + Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); + Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); + Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); + + using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + { + Span destinationSpan = buffer.Slice(0, destination.Length); + Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); + Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); + + PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); + PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); + + for (int i = 0; i < destination.Length; i++) + { + destinationSpan[i] = PorterDuffFunctions.OverlayDestIn(backgroundSpan[i], sourceSpan[i], amount[i]); + } + + PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); + } + } + } + + internal class HardLightDestIn : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static HardLightDestIn Instance { get; } = new HardLightDestIn(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + return PorterDuffFunctions.HardLightDestIn(background, source, amount); + } + + /// + public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + { + Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); + Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); + Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); + + using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + { + Span destinationSpan = buffer.Slice(0, destination.Length); + Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); + Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); + + PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); + PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); + + for (int i = 0; i < destination.Length; i++) + { + destinationSpan[i] = PorterDuffFunctions.HardLightDestIn(backgroundSpan[i], sourceSpan[i], amount[i]); + } + + PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); + } + } + } + + internal class NormalDestOut : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static NormalDestOut Instance { get; } = new NormalDestOut(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + return PorterDuffFunctions.NormalDestOut(background, source, amount); + } + + /// + public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + { + Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); + Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); + Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); + + using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + { + Span destinationSpan = buffer.Slice(0, destination.Length); + Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); + Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); + + PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); + PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); + + for (int i = 0; i < destination.Length; i++) + { + destinationSpan[i] = PorterDuffFunctions.NormalDestOut(backgroundSpan[i], sourceSpan[i], amount[i]); + } + + PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); + } + } + } + + internal class MultiplyDestOut : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static MultiplyDestOut Instance { get; } = new MultiplyDestOut(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + return PorterDuffFunctions.MultiplyDestOut(background, source, amount); + } + + /// + public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + { + Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); + Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); + Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); + + using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + { + Span destinationSpan = buffer.Slice(0, destination.Length); + Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); + Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); + + PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); + PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); + + for (int i = 0; i < destination.Length; i++) + { + destinationSpan[i] = PorterDuffFunctions.MultiplyDestOut(backgroundSpan[i], sourceSpan[i], amount[i]); + } + + PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); + } + } + } + + internal class AddDestOut : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static AddDestOut Instance { get; } = new AddDestOut(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + return PorterDuffFunctions.AddDestOut(background, source, amount); + } + + /// + public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + { + Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); + Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); + Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); + + using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + { + Span destinationSpan = buffer.Slice(0, destination.Length); + Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); + Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); + + PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); + PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); + + for (int i = 0; i < destination.Length; i++) + { + destinationSpan[i] = PorterDuffFunctions.AddDestOut(backgroundSpan[i], sourceSpan[i], amount[i]); + } + + PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); + } + } + } + + internal class SubtractDestOut : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static SubtractDestOut Instance { get; } = new SubtractDestOut(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + return PorterDuffFunctions.SubtractDestOut(background, source, amount); + } + + /// + public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + { + Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); + Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); + Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); + + using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + { + Span destinationSpan = buffer.Slice(0, destination.Length); + Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); + Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); + + PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); + PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); + + for (int i = 0; i < destination.Length; i++) + { + destinationSpan[i] = PorterDuffFunctions.SubtractDestOut(backgroundSpan[i], sourceSpan[i], amount[i]); + } + + PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); + } + } + } + + internal class ScreenDestOut : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static ScreenDestOut Instance { get; } = new ScreenDestOut(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + return PorterDuffFunctions.ScreenDestOut(background, source, amount); + } + + /// + public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + { + Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); + Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); + Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); + + using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + { + Span destinationSpan = buffer.Slice(0, destination.Length); + Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); + Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); + + PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); + PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); + + for (int i = 0; i < destination.Length; i++) + { + destinationSpan[i] = PorterDuffFunctions.ScreenDestOut(backgroundSpan[i], sourceSpan[i], amount[i]); + } + + PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); + } + } + } + + internal class DarkenDestOut : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static DarkenDestOut Instance { get; } = new DarkenDestOut(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + return PorterDuffFunctions.DarkenDestOut(background, source, amount); + } + + /// + public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + { + Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); + Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); + Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); + + using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + { + Span destinationSpan = buffer.Slice(0, destination.Length); + Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); + Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); + + PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); + PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); + + for (int i = 0; i < destination.Length; i++) + { + destinationSpan[i] = PorterDuffFunctions.DarkenDestOut(backgroundSpan[i], sourceSpan[i], amount[i]); + } + + PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); + } + } + } + + internal class LightenDestOut : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static LightenDestOut Instance { get; } = new LightenDestOut(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + return PorterDuffFunctions.LightenDestOut(background, source, amount); + } + + /// + public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + { + Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); + Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); + Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); + + using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + { + Span destinationSpan = buffer.Slice(0, destination.Length); + Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); + Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); + + PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); + PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); + + for (int i = 0; i < destination.Length; i++) + { + destinationSpan[i] = PorterDuffFunctions.LightenDestOut(backgroundSpan[i], sourceSpan[i], amount[i]); + } + + PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); + } + } + } + + internal class OverlayDestOut : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static OverlayDestOut Instance { get; } = new OverlayDestOut(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + return PorterDuffFunctions.OverlayDestOut(background, source, amount); + } + + /// + public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + { + Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); + Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); + Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); + + using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + { + Span destinationSpan = buffer.Slice(0, destination.Length); + Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); + Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); + + PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); + PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); + + for (int i = 0; i < destination.Length; i++) + { + destinationSpan[i] = PorterDuffFunctions.OverlayDestOut(backgroundSpan[i], sourceSpan[i], amount[i]); + } + + PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); + } + } + } + + internal class HardLightDestOut : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static HardLightDestOut Instance { get; } = new HardLightDestOut(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + return PorterDuffFunctions.HardLightDestOut(background, source, amount); + } + + /// + public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + { + Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); + Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); + Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); + + using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + { + Span destinationSpan = buffer.Slice(0, destination.Length); + Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); + Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); + + PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); + PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); + + for (int i = 0; i < destination.Length; i++) + { + destinationSpan[i] = PorterDuffFunctions.HardLightDestOut(backgroundSpan[i], sourceSpan[i], amount[i]); + } + + PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); + } + } + } + + internal class NormalClear : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static NormalClear Instance { get; } = new NormalClear(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + return PorterDuffFunctions.NormalClear(background, source, amount); + } + + /// + public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + { + Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); + Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); + Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); + + using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + { + Span destinationSpan = buffer.Slice(0, destination.Length); + Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); + Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); + + PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); + PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); + + for (int i = 0; i < destination.Length; i++) + { + destinationSpan[i] = PorterDuffFunctions.NormalClear(backgroundSpan[i], sourceSpan[i], amount[i]); + } + + PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); + } + } + } + + internal class MultiplyClear : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static MultiplyClear Instance { get; } = new MultiplyClear(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + return PorterDuffFunctions.MultiplyClear(background, source, amount); + } + + /// + public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + { + Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); + Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); + Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); + + using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + { + Span destinationSpan = buffer.Slice(0, destination.Length); + Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); + Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); + + PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); + PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); + + for (int i = 0; i < destination.Length; i++) + { + destinationSpan[i] = PorterDuffFunctions.MultiplyClear(backgroundSpan[i], sourceSpan[i], amount[i]); + } + + PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); + } + } + } + + internal class AddClear : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static AddClear Instance { get; } = new AddClear(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + return PorterDuffFunctions.AddClear(background, source, amount); + } + + /// + public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + { + Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); + Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); + Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); + + using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + { + Span destinationSpan = buffer.Slice(0, destination.Length); + Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); + Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); + + PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); + PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); + + for (int i = 0; i < destination.Length; i++) + { + destinationSpan[i] = PorterDuffFunctions.AddClear(backgroundSpan[i], sourceSpan[i], amount[i]); + } + + PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); + } + } + } + + internal class SubtractClear : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static SubtractClear Instance { get; } = new SubtractClear(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + return PorterDuffFunctions.SubtractClear(background, source, amount); + } + + /// + public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + { + Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); + Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); + Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); + + using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + { + Span destinationSpan = buffer.Slice(0, destination.Length); + Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); + Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); + + PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); + PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); + + for (int i = 0; i < destination.Length; i++) + { + destinationSpan[i] = PorterDuffFunctions.SubtractClear(backgroundSpan[i], sourceSpan[i], amount[i]); + } + + PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); + } + } + } + + internal class ScreenClear : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static ScreenClear Instance { get; } = new ScreenClear(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + return PorterDuffFunctions.ScreenClear(background, source, amount); + } + + /// + public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + { + Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); + Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); + Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); + + using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + { + Span destinationSpan = buffer.Slice(0, destination.Length); + Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); + Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); + + PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); + PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); + + for (int i = 0; i < destination.Length; i++) + { + destinationSpan[i] = PorterDuffFunctions.ScreenClear(backgroundSpan[i], sourceSpan[i], amount[i]); + } + + PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); + } + } + } + + internal class DarkenClear : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static DarkenClear Instance { get; } = new DarkenClear(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + return PorterDuffFunctions.DarkenClear(background, source, amount); + } + + /// + public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + { + Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); + Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); + Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); + + using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + { + Span destinationSpan = buffer.Slice(0, destination.Length); + Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); + Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); + + PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); + PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); + + for (int i = 0; i < destination.Length; i++) + { + destinationSpan[i] = PorterDuffFunctions.DarkenClear(backgroundSpan[i], sourceSpan[i], amount[i]); + } + + PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); + } + } + } + + internal class LightenClear : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static LightenClear Instance { get; } = new LightenClear(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + return PorterDuffFunctions.LightenClear(background, source, amount); + } + + /// + public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + { + Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); + Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); + Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); + + using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + { + Span destinationSpan = buffer.Slice(0, destination.Length); + Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); + Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); + + PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); + PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); + + for (int i = 0; i < destination.Length; i++) + { + destinationSpan[i] = PorterDuffFunctions.LightenClear(backgroundSpan[i], sourceSpan[i], amount[i]); + } + + PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); + } + } + } + + internal class OverlayClear : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static OverlayClear Instance { get; } = new OverlayClear(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + return PorterDuffFunctions.OverlayClear(background, source, amount); + } + + /// + public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + { + Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); + Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); + Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); + + using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + { + Span destinationSpan = buffer.Slice(0, destination.Length); + Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); + Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); + + PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); + PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); + + for (int i = 0; i < destination.Length; i++) + { + destinationSpan[i] = PorterDuffFunctions.OverlayClear(backgroundSpan[i], sourceSpan[i], amount[i]); + } + + PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); + } + } + } + + internal class HardLightClear : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static HardLightClear Instance { get; } = new HardLightClear(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + return PorterDuffFunctions.HardLightClear(background, source, amount); + } + + /// + public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + { + Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); + Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); + Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); + + using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + { + Span destinationSpan = buffer.Slice(0, destination.Length); + Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); + Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); + + PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); + PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); + + for (int i = 0; i < destination.Length; i++) + { + destinationSpan[i] = PorterDuffFunctions.HardLightClear(backgroundSpan[i], sourceSpan[i], amount[i]); + } + + PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); + } + } + } + + internal class NormalXor : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static NormalXor Instance { get; } = new NormalXor(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + return PorterDuffFunctions.NormalXor(background, source, amount); + } + + /// + public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + { + Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); + Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); + Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); + + using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + { + Span destinationSpan = buffer.Slice(0, destination.Length); + Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); + Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); + + PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); + PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); + + for (int i = 0; i < destination.Length; i++) + { + destinationSpan[i] = PorterDuffFunctions.NormalXor(backgroundSpan[i], sourceSpan[i], amount[i]); + } + + PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); + } + } + } + + internal class MultiplyXor : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static MultiplyXor Instance { get; } = new MultiplyXor(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + return PorterDuffFunctions.MultiplyXor(background, source, amount); + } + + /// + public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + { + Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); + Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); + Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); + + using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + { + Span destinationSpan = buffer.Slice(0, destination.Length); + Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); + Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); + + PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); + PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); + + for (int i = 0; i < destination.Length; i++) + { + destinationSpan[i] = PorterDuffFunctions.MultiplyXor(backgroundSpan[i], sourceSpan[i], amount[i]); + } + + PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); + } + } + } + + internal class AddXor : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static AddXor Instance { get; } = new AddXor(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + return PorterDuffFunctions.AddXor(background, source, amount); + } + + /// + public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + { + Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); + Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); + Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); + + using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + { + Span destinationSpan = buffer.Slice(0, destination.Length); + Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); + Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); + + PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); + PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); + + for (int i = 0; i < destination.Length; i++) + { + destinationSpan[i] = PorterDuffFunctions.AddXor(backgroundSpan[i], sourceSpan[i], amount[i]); + } + + PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); + } + } + } + + internal class SubtractXor : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static SubtractXor Instance { get; } = new SubtractXor(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + return PorterDuffFunctions.SubtractXor(background, source, amount); + } + + /// + public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + { + Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); + Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); + Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); + + using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + { + Span destinationSpan = buffer.Slice(0, destination.Length); + Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); + Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); + + PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); + PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); + + for (int i = 0; i < destination.Length; i++) + { + destinationSpan[i] = PorterDuffFunctions.SubtractXor(backgroundSpan[i], sourceSpan[i], amount[i]); + } + + PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); + } + } + } + + internal class ScreenXor : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static ScreenXor Instance { get; } = new ScreenXor(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + return PorterDuffFunctions.ScreenXor(background, source, amount); + } + + /// + public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + { + Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); + Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); + Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); + + using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + { + Span destinationSpan = buffer.Slice(0, destination.Length); + Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); + Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); + + PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); + PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); + + for (int i = 0; i < destination.Length; i++) + { + destinationSpan[i] = PorterDuffFunctions.ScreenXor(backgroundSpan[i], sourceSpan[i], amount[i]); + } + + PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); + } + } + } + + internal class DarkenXor : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static DarkenXor Instance { get; } = new DarkenXor(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + return PorterDuffFunctions.DarkenXor(background, source, amount); + } + + /// + public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + { + Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); + Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); + Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); + + using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + { + Span destinationSpan = buffer.Slice(0, destination.Length); + Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); + Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); + + PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); + PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); + + for (int i = 0; i < destination.Length; i++) + { + destinationSpan[i] = PorterDuffFunctions.DarkenXor(backgroundSpan[i], sourceSpan[i], amount[i]); + } + + PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); + } + } + } + + internal class LightenXor : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static LightenXor Instance { get; } = new LightenXor(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + return PorterDuffFunctions.LightenXor(background, source, amount); + } + + /// + public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + { + Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); + Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); + Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); + + using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + { + Span destinationSpan = buffer.Slice(0, destination.Length); + Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); + Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); + + PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); + PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); + + for (int i = 0; i < destination.Length; i++) + { + destinationSpan[i] = PorterDuffFunctions.LightenXor(backgroundSpan[i], sourceSpan[i], amount[i]); + } + + PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); + } + } + } + + internal class OverlayXor : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static OverlayXor Instance { get; } = new OverlayXor(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + return PorterDuffFunctions.OverlayXor(background, source, amount); + } + + /// + public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + { + Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); + Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); + Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); + + using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + { + Span destinationSpan = buffer.Slice(0, destination.Length); + Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); + Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); + + PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); + PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); + + for (int i = 0; i < destination.Length; i++) + { + destinationSpan[i] = PorterDuffFunctions.OverlayXor(backgroundSpan[i], sourceSpan[i], amount[i]); + } + + PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); + } + } + } + + internal class HardLightXor : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static HardLightXor Instance { get; } = new HardLightXor(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + return PorterDuffFunctions.HardLightXor(background, source, amount); + } + + /// + public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + { + Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); + Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); + Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); + + using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + { + Span destinationSpan = buffer.Slice(0, destination.Length); + Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); + Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); + + PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); + PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); + + for (int i = 0; i < destination.Length; i++) + { + destinationSpan[i] = PorterDuffFunctions.HardLightXor(backgroundSpan[i], sourceSpan[i], amount[i]); } PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); diff --git a/src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.tt b/src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.tt index 4f627764f..34fe4d4cd 100644 --- a/src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.tt +++ b/src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.tt @@ -35,10 +35,22 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { <# - - + string[] composers = new []{ + "Src", + "SrcAtop", + "SrcOver", + "SrcIn", + "SrcOut", + "Dest", + "DestAtop", + "DestOver", + "DestIn", + "DestOut", + "Clear", + "Xor", + }; - string[] blenders = new []{ + string[] blenders = new []{ "Normal", "Multiply", "Add", @@ -47,36 +59,26 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders "Darken", "Lighten", "Overlay", - "HardLight", - "Src" , - "Atop" , - "Over" , - "In" , - "Out" , - "Dest" , - "DestAtop" , - "DestOver" , - "DestIn" , - "DestOut" , - "Clear" , - "Xor" , + "HardLight" }; - - + foreach(var composer in composers) { foreach(var blender in blenders) { + + string blender_composer= $"{blender}{composer}"; + #> - internal class <#=blender#> : PixelBlender + internal class <#= blender_composer#> : PixelBlender { /// /// Gets the static instance of this blender. /// - public static <#=blender#> Instance { get; } = new <#=blender#>(); + public static <#=blender_composer#> Instance { get; } = new <#=blender_composer#>(); /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.<#=blender#>(background, source, amount); + return PorterDuffFunctions.<#=blender_composer#>(background, source, amount); } /// @@ -97,7 +99,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders for (int i = 0; i < destination.Length; i++) { - destinationSpan[i] = PorterDuffFunctions.<#=blender#>(backgroundSpan[i], sourceSpan[i], amount[i]); + destinationSpan[i] = PorterDuffFunctions.<#=blender_composer#>(backgroundSpan[i], sourceSpan[i], amount[i]); } PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); @@ -106,7 +108,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } <# - + } } #> diff --git a/src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.Generated.cs b/src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.Generated.cs index 66cc427de..4b0ffdd48 100644 --- a/src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.Generated.cs @@ -1,450 +1,2152 @@ -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -// - -using System; -using System.Numerics; -using System.Runtime.CompilerServices; - -namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders -{ - 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; - - // calculate weights - float xw = backdrop.W * source.W; - float bw = backdrop.W - xw; - float sw = source.W - xw; - - // calculate final alpha - float fw = (sw * 1) + (bw * 0) + (xw * 1); - - // calculate final value - Vector4 xform = ((source * xw) + (Vector4.Zero * bw) + (source * sw)) / MathF.Max(fw, Constants.Epsilon); - xform.W = fw; - - return Vector4.Lerp(backdrop, xform, opacity); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Vector4 Atop(Vector4 backdrop, Vector4 source, float opacity) - { - opacity = opacity.Clamp(0, 1); - - // calculate weights - float xw = backdrop.W * source.W; - float bw = backdrop.W - xw; - float sw = source.W - xw; - - // calculate final alpha - float fw = (sw * 0) + (bw * 1) + (xw * 1); - - // calculate final value - Vector4 xform = ((source * xw) + (backdrop * bw) + (Vector4.Zero * sw)) / MathF.Max(fw, Constants.Epsilon); - xform.W = fw; - - 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; - - // calculate weights - float xw = backdrop.W * source.W; - float bw = backdrop.W - xw; - float sw = source.W - xw; - - // calculate final alpha - float fw = (sw * 1) + (bw * 1) + (xw * 1); - - // calculate final value - Vector4 xform = ((source * xw) + (backdrop * bw) + (source * sw)) / MathF.Max(fw, Constants.Epsilon); - xform.W = fw; - - return Vector4.Lerp(backdrop, xform, opacity); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Vector4 In(Vector4 backdrop, Vector4 source, float opacity) - { - opacity = opacity.Clamp(0, 1); - - // calculate weights - float xw = backdrop.W * source.W; - float bw = backdrop.W - xw; - float sw = source.W - xw; - - // calculate final alpha - float fw = (sw * 0) + (bw * 0) + (xw * 1); - - // calculate final value - Vector4 xform = ((source * xw) + (Vector4.Zero * bw) + (Vector4.Zero * sw)) / MathF.Max(fw, Constants.Epsilon); - xform.W = fw; - - 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; - - // calculate weights - float xw = backdrop.W * source.W; - float bw = backdrop.W - xw; - float sw = source.W - xw; - - // calculate final alpha - float fw = (sw * 1) + (bw * 0) + (xw * 0); - - // calculate final value - Vector4 xform = ((Vector4.Zero * xw) + (Vector4.Zero * bw) + (source * sw)) / MathF.Max(fw, Constants.Epsilon); - xform.W = fw; - - return Vector4.Lerp(backdrop, xform, opacity); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Vector4 Dest(Vector4 backdrop, Vector4 source, float opacity) - { - opacity = opacity.Clamp(0, 1); - - // calculate weights - float xw = backdrop.W * source.W; - float bw = backdrop.W - xw; - float sw = source.W - xw; - - // calculate final alpha - float fw = (sw * 0) + (bw * 1) + (xw * 1); - - // calculate final value - Vector4 xform = ((backdrop * xw) + (backdrop * bw) + (Vector4.Zero * sw)) / MathF.Max(fw, Constants.Epsilon); - xform.W = fw; - - 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; - - // calculate weights - float xw = backdrop.W * source.W; - float bw = backdrop.W - xw; - float sw = source.W - xw; - - // calculate final alpha - float fw = (sw * 1) + (bw * 0) + (xw * 1); - - // calculate final value - Vector4 xform = ((backdrop * xw) + (Vector4.Zero * bw) + (source * sw)) / MathF.Max(fw, Constants.Epsilon); - xform.W = fw; - - 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; - - // calculate weights - float xw = backdrop.W * source.W; - float bw = backdrop.W - xw; - float sw = source.W - xw; - - // calculate final alpha - float fw = (sw * 1) + (bw * 1) + (xw * 1); - - // calculate final value - Vector4 xform = ((backdrop * xw) + (backdrop * bw) + (source * sw)) / MathF.Max(fw, Constants.Epsilon); - xform.W = fw; - - return Vector4.Lerp(backdrop, xform, opacity); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Vector4 DestIn(Vector4 backdrop, Vector4 source, float opacity) - { - opacity = opacity.Clamp(0, 1); - - // calculate weights - float xw = backdrop.W * source.W; - float bw = backdrop.W - xw; - float sw = source.W - xw; - - // calculate final alpha - float fw = (sw * 0) + (bw * 0) + (xw * 1); - - // calculate final value - Vector4 xform = ((backdrop * xw) + (Vector4.Zero * bw) + (Vector4.Zero * sw)) / MathF.Max(fw, Constants.Epsilon); - xform.W = fw; - - return Vector4.Lerp(backdrop, xform, opacity); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Vector4 DestOut(Vector4 backdrop, Vector4 source, float opacity) - { - opacity = opacity.Clamp(0, 1); - - // calculate weights - float xw = backdrop.W * source.W; - float bw = backdrop.W - xw; - float sw = source.W - xw; - - // calculate final alpha - float fw = (sw * 0) + (bw * 1) + (xw * 0); - - // calculate final value - Vector4 xform = ((Vector4.Zero * xw) + (backdrop * bw) + (Vector4.Zero * sw)) / MathF.Max(fw, Constants.Epsilon); - xform.W = fw; - - return Vector4.Lerp(backdrop, xform, opacity); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Vector4 Clear(Vector4 backdrop, Vector4 source, float opacity) - { - opacity = opacity.Clamp(0, 1); - - // calculate weights - float xw = backdrop.W * source.W; - float bw = backdrop.W - xw; - float sw = source.W - xw; - - // calculate final alpha - float fw = (sw * 0) + (bw * 0) + (xw * 0); - - // calculate final value - Vector4 xform = ((Vector4.Zero * xw) + (Vector4.Zero * bw) + (Vector4.Zero * sw)) / MathF.Max(fw, Constants.Epsilon); - xform.W = fw; - - 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; - - // calculate weights - float xw = backdrop.W * source.W; - float bw = backdrop.W - xw; - float sw = source.W - xw; - - // calculate final alpha - float fw = (sw * 1) + (bw * 1) + (xw * 0); - - // calculate final value - Vector4 xform = ((Vector4.Zero * xw) + (backdrop * bw) + (source * sw)) / MathF.Max(fw, Constants.Epsilon); - xform.W = fw; - - return Vector4.Lerp(backdrop, xform, opacity); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static TPixel Normal(TPixel backdrop, TPixel source, float amount) - where TPixel : struct, IPixel - { - TPixel dest = default; - dest.PackFromVector4(Normal(backdrop.ToVector4(), source.ToVector4(), amount)); - return dest; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static TPixel Multiply(TPixel backdrop, TPixel source, float amount) - where TPixel : struct, IPixel - { - TPixel dest = default; - dest.PackFromVector4(Multiply(backdrop.ToVector4(), source.ToVector4(), amount)); - return dest; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static TPixel Add(TPixel backdrop, TPixel source, float amount) - where TPixel : struct, IPixel - { - TPixel dest = default; - dest.PackFromVector4(Add(backdrop.ToVector4(), source.ToVector4(), amount)); - return dest; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static TPixel Subtract(TPixel backdrop, TPixel source, float amount) - where TPixel : struct, IPixel - { - TPixel dest = default; - dest.PackFromVector4(Subtract(backdrop.ToVector4(), source.ToVector4(), amount)); - return dest; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static TPixel Screen(TPixel backdrop, TPixel source, float amount) - where TPixel : struct, IPixel - { - TPixel dest = default; - dest.PackFromVector4(Screen(backdrop.ToVector4(), source.ToVector4(), amount)); - return dest; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static TPixel Darken(TPixel backdrop, TPixel source, float amount) - where TPixel : struct, IPixel - { - TPixel dest = default; - dest.PackFromVector4(Darken(backdrop.ToVector4(), source.ToVector4(), amount)); - return dest; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static TPixel Lighten(TPixel backdrop, TPixel source, float amount) - where TPixel : struct, IPixel - { - TPixel dest = default; - dest.PackFromVector4(Lighten(backdrop.ToVector4(), source.ToVector4(), amount)); - return dest; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static TPixel Overlay(TPixel backdrop, TPixel source, float amount) - where TPixel : struct, IPixel - { - TPixel dest = default; - dest.PackFromVector4(Overlay(backdrop.ToVector4(), source.ToVector4(), amount)); - return dest; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static TPixel HardLight(TPixel backdrop, TPixel source, float amount) - where TPixel : struct, IPixel - { - TPixel dest = default; - dest.PackFromVector4(HardLight(backdrop.ToVector4(), source.ToVector4(), amount)); - return dest; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static TPixel Src(TPixel backdrop, TPixel source, float amount) - where TPixel : struct, IPixel - { - TPixel dest = default; - dest.PackFromVector4(Src(backdrop.ToVector4(), source.ToVector4(), amount)); - return dest; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static TPixel Atop(TPixel backdrop, TPixel source, float amount) - where TPixel : struct, IPixel - { - TPixel dest = default; - dest.PackFromVector4(Atop(backdrop.ToVector4(), source.ToVector4(), amount)); - return dest; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static TPixel Over(TPixel backdrop, TPixel source, float amount) - where TPixel : struct, IPixel - { - TPixel dest = default; - dest.PackFromVector4(Over(backdrop.ToVector4(), source.ToVector4(), amount)); - return dest; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static TPixel In(TPixel backdrop, TPixel source, float amount) - where TPixel : struct, IPixel - { - TPixel dest = default; - dest.PackFromVector4(In(backdrop.ToVector4(), source.ToVector4(), amount)); - return dest; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static TPixel Out(TPixel backdrop, TPixel source, float amount) - where TPixel : struct, IPixel - { - TPixel dest = default; - dest.PackFromVector4(Out(backdrop.ToVector4(), source.ToVector4(), amount)); - return dest; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static TPixel Dest(TPixel backdrop, TPixel source, float amount) - where TPixel : struct, IPixel - { - TPixel dest = default; - dest.PackFromVector4(Dest(backdrop.ToVector4(), source.ToVector4(), amount)); - return dest; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static TPixel DestAtop(TPixel backdrop, TPixel source, float amount) - where TPixel : struct, IPixel - { - TPixel dest = default; - dest.PackFromVector4(DestAtop(backdrop.ToVector4(), source.ToVector4(), amount)); - return dest; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static TPixel DestOver(TPixel backdrop, TPixel source, float amount) - where TPixel : struct, IPixel - { - TPixel dest = default; - dest.PackFromVector4(DestOver(backdrop.ToVector4(), source.ToVector4(), amount)); - return dest; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static TPixel DestIn(TPixel backdrop, TPixel source, float amount) - where TPixel : struct, IPixel - { - TPixel dest = default; - dest.PackFromVector4(DestIn(backdrop.ToVector4(), source.ToVector4(), amount)); - return dest; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static TPixel DestOut(TPixel backdrop, TPixel source, float amount) - where TPixel : struct, IPixel - { - TPixel dest = default; - dest.PackFromVector4(DestOut(backdrop.ToVector4(), source.ToVector4(), amount)); - return dest; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static TPixel Clear(TPixel backdrop, TPixel source, float amount) - where TPixel : struct, IPixel - { - TPixel dest = default; - dest.PackFromVector4(Clear(backdrop.ToVector4(), source.ToVector4(), amount)); - return dest; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static TPixel Xor(TPixel backdrop, TPixel source, float amount) - where TPixel : struct, IPixel - { - TPixel dest = default; - dest.PackFromVector4(Xor(backdrop.ToVector4(), source.ToVector4(), amount)); - return dest; - } - - } +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +// + +using System; +using System.Numerics; +using System.Runtime.CompilerServices; + +namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders +{ + internal static partial class PorterDuffFunctions + { + + + + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 NormalSrc(Vector4 backdrop, Vector4 source, float opacity) + { + opacity = opacity.Clamp(0, 1); + source.W *= opacity; + + return source; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 NormalSrcAtop(Vector4 backdrop, Vector4 source, float opacity) + { + opacity = opacity.Clamp(0, 1); + source.W *= opacity; + + return Atop(backdrop, source, Normal(backdrop, source)); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 NormalSrcOver(Vector4 backdrop, Vector4 source, float opacity) + { + opacity = opacity.Clamp(0, 1); + source.W *= opacity; + + return Over(backdrop, source, Normal(backdrop, source)); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 NormalSrcIn(Vector4 backdrop, Vector4 source, float opacity) + { + opacity = opacity.Clamp(0, 1); + source.W *= opacity; + + return In(backdrop, source, Normal(backdrop, source)); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 NormalSrcOut(Vector4 backdrop, Vector4 source, float opacity) + { + opacity = opacity.Clamp(0, 1); + source.W *= opacity; + + return Out(backdrop, source); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 NormalDest(Vector4 backdrop, Vector4 source, float opacity) + { + return backdrop; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 NormalDestAtop(Vector4 backdrop, Vector4 source, float opacity) + { + opacity = opacity.Clamp(0, 1); + source.W *= opacity; + + return Atop(source, backdrop, Normal(source, backdrop)); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 NormalDestOver(Vector4 backdrop, Vector4 source, float opacity) + { + opacity = opacity.Clamp(0, 1); + source.W *= opacity; + + return Over(source, backdrop, Normal(source, backdrop)); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 NormalDestIn(Vector4 backdrop, Vector4 source, float opacity) + { + opacity = opacity.Clamp(0, 1); + source.W *= opacity; + + return In(source, backdrop, Normal(source, backdrop)); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 NormalDestOut(Vector4 backdrop, Vector4 source, float opacity) + { + opacity = opacity.Clamp(0, 1); + source.W *= opacity; + + return Out(source, backdrop); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 NormalXor(Vector4 backdrop, Vector4 source, float opacity) + { + opacity = opacity.Clamp(0, 1); + source.W *= opacity; + + return Xor(backdrop, source); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 NormalClear(Vector4 backdrop, Vector4 source, float opacity) + { + opacity = opacity.Clamp(0, 1); + source.W *= opacity; + + return Clear(backdrop, source); + } + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TPixel NormalSrc(TPixel backdrop, TPixel source, float opacity) + where TPixel : struct, IPixel + { + TPixel dest = default; + dest.PackFromVector4(NormalSrc(backdrop.ToVector4(),source.ToVector4(),opacity)); + return dest; + } + + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TPixel NormalSrcAtop(TPixel backdrop, TPixel source, float opacity) + where TPixel : struct, IPixel + { + TPixel dest = default; + dest.PackFromVector4(NormalSrcAtop(backdrop.ToVector4(),source.ToVector4(),opacity)); + return dest; + } + + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TPixel NormalSrcOver(TPixel backdrop, TPixel source, float opacity) + where TPixel : struct, IPixel + { + TPixel dest = default; + dest.PackFromVector4(NormalSrcOver(backdrop.ToVector4(),source.ToVector4(),opacity)); + return dest; + } + + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TPixel NormalSrcIn(TPixel backdrop, TPixel source, float opacity) + where TPixel : struct, IPixel + { + TPixel dest = default; + dest.PackFromVector4(NormalSrcIn(backdrop.ToVector4(),source.ToVector4(),opacity)); + return dest; + } + + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TPixel NormalSrcOut(TPixel backdrop, TPixel source, float opacity) + where TPixel : struct, IPixel + { + TPixel dest = default; + dest.PackFromVector4(NormalSrcOut(backdrop.ToVector4(),source.ToVector4(),opacity)); + return dest; + } + + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TPixel NormalDest(TPixel backdrop, TPixel source, float opacity) + where TPixel : struct, IPixel + { + TPixel dest = default; + dest.PackFromVector4(NormalDest(backdrop.ToVector4(),source.ToVector4(),opacity)); + return dest; + } + + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TPixel NormalDestAtop(TPixel backdrop, TPixel source, float opacity) + where TPixel : struct, IPixel + { + TPixel dest = default; + dest.PackFromVector4(NormalDestAtop(backdrop.ToVector4(),source.ToVector4(),opacity)); + return dest; + } + + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TPixel NormalDestOver(TPixel backdrop, TPixel source, float opacity) + where TPixel : struct, IPixel + { + TPixel dest = default; + dest.PackFromVector4(NormalDestOver(backdrop.ToVector4(),source.ToVector4(),opacity)); + return dest; + } + + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TPixel NormalDestIn(TPixel backdrop, TPixel source, float opacity) + where TPixel : struct, IPixel + { + TPixel dest = default; + dest.PackFromVector4(NormalDestIn(backdrop.ToVector4(),source.ToVector4(),opacity)); + return dest; + } + + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TPixel NormalDestOut(TPixel backdrop, TPixel source, float opacity) + where TPixel : struct, IPixel + { + TPixel dest = default; + dest.PackFromVector4(NormalDestOut(backdrop.ToVector4(),source.ToVector4(),opacity)); + return dest; + } + + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TPixel NormalClear(TPixel backdrop, TPixel source, float opacity) + where TPixel : struct, IPixel + { + TPixel dest = default; + dest.PackFromVector4(NormalClear(backdrop.ToVector4(),source.ToVector4(),opacity)); + return dest; + } + + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TPixel NormalXor(TPixel backdrop, TPixel source, float opacity) + where TPixel : struct, IPixel + { + TPixel dest = default; + dest.PackFromVector4(NormalXor(backdrop.ToVector4(),source.ToVector4(),opacity)); + return dest; + } + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 MultiplySrc(Vector4 backdrop, Vector4 source, float opacity) + { + opacity = opacity.Clamp(0, 1); + source.W *= opacity; + + return source; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 MultiplySrcAtop(Vector4 backdrop, Vector4 source, float opacity) + { + opacity = opacity.Clamp(0, 1); + source.W *= opacity; + + return Atop(backdrop, source, Multiply(backdrop, source)); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 MultiplySrcOver(Vector4 backdrop, Vector4 source, float opacity) + { + opacity = opacity.Clamp(0, 1); + source.W *= opacity; + + return Over(backdrop, source, Multiply(backdrop, source)); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 MultiplySrcIn(Vector4 backdrop, Vector4 source, float opacity) + { + opacity = opacity.Clamp(0, 1); + source.W *= opacity; + + return In(backdrop, source, Multiply(backdrop, source)); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 MultiplySrcOut(Vector4 backdrop, Vector4 source, float opacity) + { + opacity = opacity.Clamp(0, 1); + source.W *= opacity; + + return Out(backdrop, source); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 MultiplyDest(Vector4 backdrop, Vector4 source, float opacity) + { + return backdrop; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 MultiplyDestAtop(Vector4 backdrop, Vector4 source, float opacity) + { + opacity = opacity.Clamp(0, 1); + source.W *= opacity; + + return Atop(source, backdrop, Multiply(source, backdrop)); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 MultiplyDestOver(Vector4 backdrop, Vector4 source, float opacity) + { + opacity = opacity.Clamp(0, 1); + source.W *= opacity; + + return Over(source, backdrop, Multiply(source, backdrop)); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 MultiplyDestIn(Vector4 backdrop, Vector4 source, float opacity) + { + opacity = opacity.Clamp(0, 1); + source.W *= opacity; + + return In(source, backdrop, Multiply(source, backdrop)); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 MultiplyDestOut(Vector4 backdrop, Vector4 source, float opacity) + { + opacity = opacity.Clamp(0, 1); + source.W *= opacity; + + return Out(source, backdrop); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 MultiplyXor(Vector4 backdrop, Vector4 source, float opacity) + { + opacity = opacity.Clamp(0, 1); + source.W *= opacity; + + return Xor(backdrop, source); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 MultiplyClear(Vector4 backdrop, Vector4 source, float opacity) + { + opacity = opacity.Clamp(0, 1); + source.W *= opacity; + + return Clear(backdrop, source); + } + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TPixel MultiplySrc(TPixel backdrop, TPixel source, float opacity) + where TPixel : struct, IPixel + { + TPixel dest = default; + dest.PackFromVector4(MultiplySrc(backdrop.ToVector4(),source.ToVector4(),opacity)); + return dest; + } + + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TPixel MultiplySrcAtop(TPixel backdrop, TPixel source, float opacity) + where TPixel : struct, IPixel + { + TPixel dest = default; + dest.PackFromVector4(MultiplySrcAtop(backdrop.ToVector4(),source.ToVector4(),opacity)); + return dest; + } + + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TPixel MultiplySrcOver(TPixel backdrop, TPixel source, float opacity) + where TPixel : struct, IPixel + { + TPixel dest = default; + dest.PackFromVector4(MultiplySrcOver(backdrop.ToVector4(),source.ToVector4(),opacity)); + return dest; + } + + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TPixel MultiplySrcIn(TPixel backdrop, TPixel source, float opacity) + where TPixel : struct, IPixel + { + TPixel dest = default; + dest.PackFromVector4(MultiplySrcIn(backdrop.ToVector4(),source.ToVector4(),opacity)); + return dest; + } + + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TPixel MultiplySrcOut(TPixel backdrop, TPixel source, float opacity) + where TPixel : struct, IPixel + { + TPixel dest = default; + dest.PackFromVector4(MultiplySrcOut(backdrop.ToVector4(),source.ToVector4(),opacity)); + return dest; + } + + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TPixel MultiplyDest(TPixel backdrop, TPixel source, float opacity) + where TPixel : struct, IPixel + { + TPixel dest = default; + dest.PackFromVector4(MultiplyDest(backdrop.ToVector4(),source.ToVector4(),opacity)); + return dest; + } + + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TPixel MultiplyDestAtop(TPixel backdrop, TPixel source, float opacity) + where TPixel : struct, IPixel + { + TPixel dest = default; + dest.PackFromVector4(MultiplyDestAtop(backdrop.ToVector4(),source.ToVector4(),opacity)); + return dest; + } + + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TPixel MultiplyDestOver(TPixel backdrop, TPixel source, float opacity) + where TPixel : struct, IPixel + { + TPixel dest = default; + dest.PackFromVector4(MultiplyDestOver(backdrop.ToVector4(),source.ToVector4(),opacity)); + return dest; + } + + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TPixel MultiplyDestIn(TPixel backdrop, TPixel source, float opacity) + where TPixel : struct, IPixel + { + TPixel dest = default; + dest.PackFromVector4(MultiplyDestIn(backdrop.ToVector4(),source.ToVector4(),opacity)); + return dest; + } + + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TPixel MultiplyDestOut(TPixel backdrop, TPixel source, float opacity) + where TPixel : struct, IPixel + { + TPixel dest = default; + dest.PackFromVector4(MultiplyDestOut(backdrop.ToVector4(),source.ToVector4(),opacity)); + return dest; + } + + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TPixel MultiplyClear(TPixel backdrop, TPixel source, float opacity) + where TPixel : struct, IPixel + { + TPixel dest = default; + dest.PackFromVector4(MultiplyClear(backdrop.ToVector4(),source.ToVector4(),opacity)); + return dest; + } + + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TPixel MultiplyXor(TPixel backdrop, TPixel source, float opacity) + where TPixel : struct, IPixel + { + TPixel dest = default; + dest.PackFromVector4(MultiplyXor(backdrop.ToVector4(),source.ToVector4(),opacity)); + return dest; + } + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 AddSrc(Vector4 backdrop, Vector4 source, float opacity) + { + opacity = opacity.Clamp(0, 1); + source.W *= opacity; + + return source; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 AddSrcAtop(Vector4 backdrop, Vector4 source, float opacity) + { + opacity = opacity.Clamp(0, 1); + source.W *= opacity; + + return Atop(backdrop, source, Add(backdrop, source)); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 AddSrcOver(Vector4 backdrop, Vector4 source, float opacity) + { + opacity = opacity.Clamp(0, 1); + source.W *= opacity; + + return Over(backdrop, source, Add(backdrop, source)); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 AddSrcIn(Vector4 backdrop, Vector4 source, float opacity) + { + opacity = opacity.Clamp(0, 1); + source.W *= opacity; + + return In(backdrop, source, Add(backdrop, source)); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 AddSrcOut(Vector4 backdrop, Vector4 source, float opacity) + { + opacity = opacity.Clamp(0, 1); + source.W *= opacity; + + return Out(backdrop, source); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 AddDest(Vector4 backdrop, Vector4 source, float opacity) + { + return backdrop; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 AddDestAtop(Vector4 backdrop, Vector4 source, float opacity) + { + opacity = opacity.Clamp(0, 1); + source.W *= opacity; + + return Atop(source, backdrop, Add(source, backdrop)); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 AddDestOver(Vector4 backdrop, Vector4 source, float opacity) + { + opacity = opacity.Clamp(0, 1); + source.W *= opacity; + + return Over(source, backdrop, Add(source, backdrop)); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 AddDestIn(Vector4 backdrop, Vector4 source, float opacity) + { + opacity = opacity.Clamp(0, 1); + source.W *= opacity; + + return In(source, backdrop, Add(source, backdrop)); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 AddDestOut(Vector4 backdrop, Vector4 source, float opacity) + { + opacity = opacity.Clamp(0, 1); + source.W *= opacity; + + return Out(source, backdrop); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 AddXor(Vector4 backdrop, Vector4 source, float opacity) + { + opacity = opacity.Clamp(0, 1); + source.W *= opacity; + + return Xor(backdrop, source); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 AddClear(Vector4 backdrop, Vector4 source, float opacity) + { + opacity = opacity.Clamp(0, 1); + source.W *= opacity; + + return Clear(backdrop, source); + } + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TPixel AddSrc(TPixel backdrop, TPixel source, float opacity) + where TPixel : struct, IPixel + { + TPixel dest = default; + dest.PackFromVector4(AddSrc(backdrop.ToVector4(),source.ToVector4(),opacity)); + return dest; + } + + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TPixel AddSrcAtop(TPixel backdrop, TPixel source, float opacity) + where TPixel : struct, IPixel + { + TPixel dest = default; + dest.PackFromVector4(AddSrcAtop(backdrop.ToVector4(),source.ToVector4(),opacity)); + return dest; + } + + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TPixel AddSrcOver(TPixel backdrop, TPixel source, float opacity) + where TPixel : struct, IPixel + { + TPixel dest = default; + dest.PackFromVector4(AddSrcOver(backdrop.ToVector4(),source.ToVector4(),opacity)); + return dest; + } + + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TPixel AddSrcIn(TPixel backdrop, TPixel source, float opacity) + where TPixel : struct, IPixel + { + TPixel dest = default; + dest.PackFromVector4(AddSrcIn(backdrop.ToVector4(),source.ToVector4(),opacity)); + return dest; + } + + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TPixel AddSrcOut(TPixel backdrop, TPixel source, float opacity) + where TPixel : struct, IPixel + { + TPixel dest = default; + dest.PackFromVector4(AddSrcOut(backdrop.ToVector4(),source.ToVector4(),opacity)); + return dest; + } + + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TPixel AddDest(TPixel backdrop, TPixel source, float opacity) + where TPixel : struct, IPixel + { + TPixel dest = default; + dest.PackFromVector4(AddDest(backdrop.ToVector4(),source.ToVector4(),opacity)); + return dest; + } + + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TPixel AddDestAtop(TPixel backdrop, TPixel source, float opacity) + where TPixel : struct, IPixel + { + TPixel dest = default; + dest.PackFromVector4(AddDestAtop(backdrop.ToVector4(),source.ToVector4(),opacity)); + return dest; + } + + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TPixel AddDestOver(TPixel backdrop, TPixel source, float opacity) + where TPixel : struct, IPixel + { + TPixel dest = default; + dest.PackFromVector4(AddDestOver(backdrop.ToVector4(),source.ToVector4(),opacity)); + return dest; + } + + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TPixel AddDestIn(TPixel backdrop, TPixel source, float opacity) + where TPixel : struct, IPixel + { + TPixel dest = default; + dest.PackFromVector4(AddDestIn(backdrop.ToVector4(),source.ToVector4(),opacity)); + return dest; + } + + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TPixel AddDestOut(TPixel backdrop, TPixel source, float opacity) + where TPixel : struct, IPixel + { + TPixel dest = default; + dest.PackFromVector4(AddDestOut(backdrop.ToVector4(),source.ToVector4(),opacity)); + return dest; + } + + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TPixel AddClear(TPixel backdrop, TPixel source, float opacity) + where TPixel : struct, IPixel + { + TPixel dest = default; + dest.PackFromVector4(AddClear(backdrop.ToVector4(),source.ToVector4(),opacity)); + return dest; + } + + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TPixel AddXor(TPixel backdrop, TPixel source, float opacity) + where TPixel : struct, IPixel + { + TPixel dest = default; + dest.PackFromVector4(AddXor(backdrop.ToVector4(),source.ToVector4(),opacity)); + return dest; + } + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 SubtractSrc(Vector4 backdrop, Vector4 source, float opacity) + { + opacity = opacity.Clamp(0, 1); + source.W *= opacity; + + return source; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 SubtractSrcAtop(Vector4 backdrop, Vector4 source, float opacity) + { + opacity = opacity.Clamp(0, 1); + source.W *= opacity; + + return Atop(backdrop, source, Subtract(backdrop, source)); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 SubtractSrcOver(Vector4 backdrop, Vector4 source, float opacity) + { + opacity = opacity.Clamp(0, 1); + source.W *= opacity; + + return Over(backdrop, source, Subtract(backdrop, source)); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 SubtractSrcIn(Vector4 backdrop, Vector4 source, float opacity) + { + opacity = opacity.Clamp(0, 1); + source.W *= opacity; + + return In(backdrop, source, Subtract(backdrop, source)); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 SubtractSrcOut(Vector4 backdrop, Vector4 source, float opacity) + { + opacity = opacity.Clamp(0, 1); + source.W *= opacity; + + return Out(backdrop, source); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 SubtractDest(Vector4 backdrop, Vector4 source, float opacity) + { + return backdrop; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 SubtractDestAtop(Vector4 backdrop, Vector4 source, float opacity) + { + opacity = opacity.Clamp(0, 1); + source.W *= opacity; + + return Atop(source, backdrop, Subtract(source, backdrop)); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 SubtractDestOver(Vector4 backdrop, Vector4 source, float opacity) + { + opacity = opacity.Clamp(0, 1); + source.W *= opacity; + + return Over(source, backdrop, Subtract(source, backdrop)); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 SubtractDestIn(Vector4 backdrop, Vector4 source, float opacity) + { + opacity = opacity.Clamp(0, 1); + source.W *= opacity; + + return In(source, backdrop, Subtract(source, backdrop)); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 SubtractDestOut(Vector4 backdrop, Vector4 source, float opacity) + { + opacity = opacity.Clamp(0, 1); + source.W *= opacity; + + return Out(source, backdrop); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 SubtractXor(Vector4 backdrop, Vector4 source, float opacity) + { + opacity = opacity.Clamp(0, 1); + source.W *= opacity; + + return Xor(backdrop, source); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 SubtractClear(Vector4 backdrop, Vector4 source, float opacity) + { + opacity = opacity.Clamp(0, 1); + source.W *= opacity; + + return Clear(backdrop, source); + } + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TPixel SubtractSrc(TPixel backdrop, TPixel source, float opacity) + where TPixel : struct, IPixel + { + TPixel dest = default; + dest.PackFromVector4(SubtractSrc(backdrop.ToVector4(),source.ToVector4(),opacity)); + return dest; + } + + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TPixel SubtractSrcAtop(TPixel backdrop, TPixel source, float opacity) + where TPixel : struct, IPixel + { + TPixel dest = default; + dest.PackFromVector4(SubtractSrcAtop(backdrop.ToVector4(),source.ToVector4(),opacity)); + return dest; + } + + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TPixel SubtractSrcOver(TPixel backdrop, TPixel source, float opacity) + where TPixel : struct, IPixel + { + TPixel dest = default; + dest.PackFromVector4(SubtractSrcOver(backdrop.ToVector4(),source.ToVector4(),opacity)); + return dest; + } + + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TPixel SubtractSrcIn(TPixel backdrop, TPixel source, float opacity) + where TPixel : struct, IPixel + { + TPixel dest = default; + dest.PackFromVector4(SubtractSrcIn(backdrop.ToVector4(),source.ToVector4(),opacity)); + return dest; + } + + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TPixel SubtractSrcOut(TPixel backdrop, TPixel source, float opacity) + where TPixel : struct, IPixel + { + TPixel dest = default; + dest.PackFromVector4(SubtractSrcOut(backdrop.ToVector4(),source.ToVector4(),opacity)); + return dest; + } + + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TPixel SubtractDest(TPixel backdrop, TPixel source, float opacity) + where TPixel : struct, IPixel + { + TPixel dest = default; + dest.PackFromVector4(SubtractDest(backdrop.ToVector4(),source.ToVector4(),opacity)); + return dest; + } + + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TPixel SubtractDestAtop(TPixel backdrop, TPixel source, float opacity) + where TPixel : struct, IPixel + { + TPixel dest = default; + dest.PackFromVector4(SubtractDestAtop(backdrop.ToVector4(),source.ToVector4(),opacity)); + return dest; + } + + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TPixel SubtractDestOver(TPixel backdrop, TPixel source, float opacity) + where TPixel : struct, IPixel + { + TPixel dest = default; + dest.PackFromVector4(SubtractDestOver(backdrop.ToVector4(),source.ToVector4(),opacity)); + return dest; + } + + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TPixel SubtractDestIn(TPixel backdrop, TPixel source, float opacity) + where TPixel : struct, IPixel + { + TPixel dest = default; + dest.PackFromVector4(SubtractDestIn(backdrop.ToVector4(),source.ToVector4(),opacity)); + return dest; + } + + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TPixel SubtractDestOut(TPixel backdrop, TPixel source, float opacity) + where TPixel : struct, IPixel + { + TPixel dest = default; + dest.PackFromVector4(SubtractDestOut(backdrop.ToVector4(),source.ToVector4(),opacity)); + return dest; + } + + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TPixel SubtractClear(TPixel backdrop, TPixel source, float opacity) + where TPixel : struct, IPixel + { + TPixel dest = default; + dest.PackFromVector4(SubtractClear(backdrop.ToVector4(),source.ToVector4(),opacity)); + return dest; + } + + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TPixel SubtractXor(TPixel backdrop, TPixel source, float opacity) + where TPixel : struct, IPixel + { + TPixel dest = default; + dest.PackFromVector4(SubtractXor(backdrop.ToVector4(),source.ToVector4(),opacity)); + return dest; + } + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 ScreenSrc(Vector4 backdrop, Vector4 source, float opacity) + { + opacity = opacity.Clamp(0, 1); + source.W *= opacity; + + return source; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 ScreenSrcAtop(Vector4 backdrop, Vector4 source, float opacity) + { + opacity = opacity.Clamp(0, 1); + source.W *= opacity; + + return Atop(backdrop, source, Screen(backdrop, source)); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 ScreenSrcOver(Vector4 backdrop, Vector4 source, float opacity) + { + opacity = opacity.Clamp(0, 1); + source.W *= opacity; + + return Over(backdrop, source, Screen(backdrop, source)); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 ScreenSrcIn(Vector4 backdrop, Vector4 source, float opacity) + { + opacity = opacity.Clamp(0, 1); + source.W *= opacity; + + return In(backdrop, source, Screen(backdrop, source)); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 ScreenSrcOut(Vector4 backdrop, Vector4 source, float opacity) + { + opacity = opacity.Clamp(0, 1); + source.W *= opacity; + + return Out(backdrop, source); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 ScreenDest(Vector4 backdrop, Vector4 source, float opacity) + { + return backdrop; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 ScreenDestAtop(Vector4 backdrop, Vector4 source, float opacity) + { + opacity = opacity.Clamp(0, 1); + source.W *= opacity; + + return Atop(source, backdrop, Screen(source, backdrop)); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 ScreenDestOver(Vector4 backdrop, Vector4 source, float opacity) + { + opacity = opacity.Clamp(0, 1); + source.W *= opacity; + + return Over(source, backdrop, Screen(source, backdrop)); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 ScreenDestIn(Vector4 backdrop, Vector4 source, float opacity) + { + opacity = opacity.Clamp(0, 1); + source.W *= opacity; + + return In(source, backdrop, Screen(source, backdrop)); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 ScreenDestOut(Vector4 backdrop, Vector4 source, float opacity) + { + opacity = opacity.Clamp(0, 1); + source.W *= opacity; + + return Out(source, backdrop); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 ScreenXor(Vector4 backdrop, Vector4 source, float opacity) + { + opacity = opacity.Clamp(0, 1); + source.W *= opacity; + + return Xor(backdrop, source); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 ScreenClear(Vector4 backdrop, Vector4 source, float opacity) + { + opacity = opacity.Clamp(0, 1); + source.W *= opacity; + + return Clear(backdrop, source); + } + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TPixel ScreenSrc(TPixel backdrop, TPixel source, float opacity) + where TPixel : struct, IPixel + { + TPixel dest = default; + dest.PackFromVector4(ScreenSrc(backdrop.ToVector4(),source.ToVector4(),opacity)); + return dest; + } + + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TPixel ScreenSrcAtop(TPixel backdrop, TPixel source, float opacity) + where TPixel : struct, IPixel + { + TPixel dest = default; + dest.PackFromVector4(ScreenSrcAtop(backdrop.ToVector4(),source.ToVector4(),opacity)); + return dest; + } + + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TPixel ScreenSrcOver(TPixel backdrop, TPixel source, float opacity) + where TPixel : struct, IPixel + { + TPixel dest = default; + dest.PackFromVector4(ScreenSrcOver(backdrop.ToVector4(),source.ToVector4(),opacity)); + return dest; + } + + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TPixel ScreenSrcIn(TPixel backdrop, TPixel source, float opacity) + where TPixel : struct, IPixel + { + TPixel dest = default; + dest.PackFromVector4(ScreenSrcIn(backdrop.ToVector4(),source.ToVector4(),opacity)); + return dest; + } + + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TPixel ScreenSrcOut(TPixel backdrop, TPixel source, float opacity) + where TPixel : struct, IPixel + { + TPixel dest = default; + dest.PackFromVector4(ScreenSrcOut(backdrop.ToVector4(),source.ToVector4(),opacity)); + return dest; + } + + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TPixel ScreenDest(TPixel backdrop, TPixel source, float opacity) + where TPixel : struct, IPixel + { + TPixel dest = default; + dest.PackFromVector4(ScreenDest(backdrop.ToVector4(),source.ToVector4(),opacity)); + return dest; + } + + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TPixel ScreenDestAtop(TPixel backdrop, TPixel source, float opacity) + where TPixel : struct, IPixel + { + TPixel dest = default; + dest.PackFromVector4(ScreenDestAtop(backdrop.ToVector4(),source.ToVector4(),opacity)); + return dest; + } + + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TPixel ScreenDestOver(TPixel backdrop, TPixel source, float opacity) + where TPixel : struct, IPixel + { + TPixel dest = default; + dest.PackFromVector4(ScreenDestOver(backdrop.ToVector4(),source.ToVector4(),opacity)); + return dest; + } + + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TPixel ScreenDestIn(TPixel backdrop, TPixel source, float opacity) + where TPixel : struct, IPixel + { + TPixel dest = default; + dest.PackFromVector4(ScreenDestIn(backdrop.ToVector4(),source.ToVector4(),opacity)); + return dest; + } + + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TPixel ScreenDestOut(TPixel backdrop, TPixel source, float opacity) + where TPixel : struct, IPixel + { + TPixel dest = default; + dest.PackFromVector4(ScreenDestOut(backdrop.ToVector4(),source.ToVector4(),opacity)); + return dest; + } + + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TPixel ScreenClear(TPixel backdrop, TPixel source, float opacity) + where TPixel : struct, IPixel + { + TPixel dest = default; + dest.PackFromVector4(ScreenClear(backdrop.ToVector4(),source.ToVector4(),opacity)); + return dest; + } + + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TPixel ScreenXor(TPixel backdrop, TPixel source, float opacity) + where TPixel : struct, IPixel + { + TPixel dest = default; + dest.PackFromVector4(ScreenXor(backdrop.ToVector4(),source.ToVector4(),opacity)); + return dest; + } + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 DarkenSrc(Vector4 backdrop, Vector4 source, float opacity) + { + opacity = opacity.Clamp(0, 1); + source.W *= opacity; + + return source; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 DarkenSrcAtop(Vector4 backdrop, Vector4 source, float opacity) + { + opacity = opacity.Clamp(0, 1); + source.W *= opacity; + + return Atop(backdrop, source, Darken(backdrop, source)); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 DarkenSrcOver(Vector4 backdrop, Vector4 source, float opacity) + { + opacity = opacity.Clamp(0, 1); + source.W *= opacity; + + return Over(backdrop, source, Darken(backdrop, source)); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 DarkenSrcIn(Vector4 backdrop, Vector4 source, float opacity) + { + opacity = opacity.Clamp(0, 1); + source.W *= opacity; + + return In(backdrop, source, Darken(backdrop, source)); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 DarkenSrcOut(Vector4 backdrop, Vector4 source, float opacity) + { + opacity = opacity.Clamp(0, 1); + source.W *= opacity; + + return Out(backdrop, source); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 DarkenDest(Vector4 backdrop, Vector4 source, float opacity) + { + return backdrop; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 DarkenDestAtop(Vector4 backdrop, Vector4 source, float opacity) + { + opacity = opacity.Clamp(0, 1); + source.W *= opacity; + + return Atop(source, backdrop, Darken(source, backdrop)); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 DarkenDestOver(Vector4 backdrop, Vector4 source, float opacity) + { + opacity = opacity.Clamp(0, 1); + source.W *= opacity; + + return Over(source, backdrop, Darken(source, backdrop)); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 DarkenDestIn(Vector4 backdrop, Vector4 source, float opacity) + { + opacity = opacity.Clamp(0, 1); + source.W *= opacity; + + return In(source, backdrop, Darken(source, backdrop)); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 DarkenDestOut(Vector4 backdrop, Vector4 source, float opacity) + { + opacity = opacity.Clamp(0, 1); + source.W *= opacity; + + return Out(source, backdrop); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 DarkenXor(Vector4 backdrop, Vector4 source, float opacity) + { + opacity = opacity.Clamp(0, 1); + source.W *= opacity; + + return Xor(backdrop, source); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 DarkenClear(Vector4 backdrop, Vector4 source, float opacity) + { + opacity = opacity.Clamp(0, 1); + source.W *= opacity; + + return Clear(backdrop, source); + } + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TPixel DarkenSrc(TPixel backdrop, TPixel source, float opacity) + where TPixel : struct, IPixel + { + TPixel dest = default; + dest.PackFromVector4(DarkenSrc(backdrop.ToVector4(),source.ToVector4(),opacity)); + return dest; + } + + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TPixel DarkenSrcAtop(TPixel backdrop, TPixel source, float opacity) + where TPixel : struct, IPixel + { + TPixel dest = default; + dest.PackFromVector4(DarkenSrcAtop(backdrop.ToVector4(),source.ToVector4(),opacity)); + return dest; + } + + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TPixel DarkenSrcOver(TPixel backdrop, TPixel source, float opacity) + where TPixel : struct, IPixel + { + TPixel dest = default; + dest.PackFromVector4(DarkenSrcOver(backdrop.ToVector4(),source.ToVector4(),opacity)); + return dest; + } + + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TPixel DarkenSrcIn(TPixel backdrop, TPixel source, float opacity) + where TPixel : struct, IPixel + { + TPixel dest = default; + dest.PackFromVector4(DarkenSrcIn(backdrop.ToVector4(),source.ToVector4(),opacity)); + return dest; + } + + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TPixel DarkenSrcOut(TPixel backdrop, TPixel source, float opacity) + where TPixel : struct, IPixel + { + TPixel dest = default; + dest.PackFromVector4(DarkenSrcOut(backdrop.ToVector4(),source.ToVector4(),opacity)); + return dest; + } + + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TPixel DarkenDest(TPixel backdrop, TPixel source, float opacity) + where TPixel : struct, IPixel + { + TPixel dest = default; + dest.PackFromVector4(DarkenDest(backdrop.ToVector4(),source.ToVector4(),opacity)); + return dest; + } + + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TPixel DarkenDestAtop(TPixel backdrop, TPixel source, float opacity) + where TPixel : struct, IPixel + { + TPixel dest = default; + dest.PackFromVector4(DarkenDestAtop(backdrop.ToVector4(),source.ToVector4(),opacity)); + return dest; + } + + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TPixel DarkenDestOver(TPixel backdrop, TPixel source, float opacity) + where TPixel : struct, IPixel + { + TPixel dest = default; + dest.PackFromVector4(DarkenDestOver(backdrop.ToVector4(),source.ToVector4(),opacity)); + return dest; + } + + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TPixel DarkenDestIn(TPixel backdrop, TPixel source, float opacity) + where TPixel : struct, IPixel + { + TPixel dest = default; + dest.PackFromVector4(DarkenDestIn(backdrop.ToVector4(),source.ToVector4(),opacity)); + return dest; + } + + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TPixel DarkenDestOut(TPixel backdrop, TPixel source, float opacity) + where TPixel : struct, IPixel + { + TPixel dest = default; + dest.PackFromVector4(DarkenDestOut(backdrop.ToVector4(),source.ToVector4(),opacity)); + return dest; + } + + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TPixel DarkenClear(TPixel backdrop, TPixel source, float opacity) + where TPixel : struct, IPixel + { + TPixel dest = default; + dest.PackFromVector4(DarkenClear(backdrop.ToVector4(),source.ToVector4(),opacity)); + return dest; + } + + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TPixel DarkenXor(TPixel backdrop, TPixel source, float opacity) + where TPixel : struct, IPixel + { + TPixel dest = default; + dest.PackFromVector4(DarkenXor(backdrop.ToVector4(),source.ToVector4(),opacity)); + return dest; + } + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 LightenSrc(Vector4 backdrop, Vector4 source, float opacity) + { + opacity = opacity.Clamp(0, 1); + source.W *= opacity; + + return source; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 LightenSrcAtop(Vector4 backdrop, Vector4 source, float opacity) + { + opacity = opacity.Clamp(0, 1); + source.W *= opacity; + + return Atop(backdrop, source, Lighten(backdrop, source)); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 LightenSrcOver(Vector4 backdrop, Vector4 source, float opacity) + { + opacity = opacity.Clamp(0, 1); + source.W *= opacity; + + return Over(backdrop, source, Lighten(backdrop, source)); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 LightenSrcIn(Vector4 backdrop, Vector4 source, float opacity) + { + opacity = opacity.Clamp(0, 1); + source.W *= opacity; + + return In(backdrop, source, Lighten(backdrop, source)); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 LightenSrcOut(Vector4 backdrop, Vector4 source, float opacity) + { + opacity = opacity.Clamp(0, 1); + source.W *= opacity; + + return Out(backdrop, source); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 LightenDest(Vector4 backdrop, Vector4 source, float opacity) + { + return backdrop; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 LightenDestAtop(Vector4 backdrop, Vector4 source, float opacity) + { + opacity = opacity.Clamp(0, 1); + source.W *= opacity; + + return Atop(source, backdrop, Lighten(source, backdrop)); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 LightenDestOver(Vector4 backdrop, Vector4 source, float opacity) + { + opacity = opacity.Clamp(0, 1); + source.W *= opacity; + + return Over(source, backdrop, Lighten(source, backdrop)); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 LightenDestIn(Vector4 backdrop, Vector4 source, float opacity) + { + opacity = opacity.Clamp(0, 1); + source.W *= opacity; + + return In(source, backdrop, Lighten(source, backdrop)); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 LightenDestOut(Vector4 backdrop, Vector4 source, float opacity) + { + opacity = opacity.Clamp(0, 1); + source.W *= opacity; + + return Out(source, backdrop); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 LightenXor(Vector4 backdrop, Vector4 source, float opacity) + { + opacity = opacity.Clamp(0, 1); + source.W *= opacity; + + return Xor(backdrop, source); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 LightenClear(Vector4 backdrop, Vector4 source, float opacity) + { + opacity = opacity.Clamp(0, 1); + source.W *= opacity; + + return Clear(backdrop, source); + } + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TPixel LightenSrc(TPixel backdrop, TPixel source, float opacity) + where TPixel : struct, IPixel + { + TPixel dest = default; + dest.PackFromVector4(LightenSrc(backdrop.ToVector4(),source.ToVector4(),opacity)); + return dest; + } + + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TPixel LightenSrcAtop(TPixel backdrop, TPixel source, float opacity) + where TPixel : struct, IPixel + { + TPixel dest = default; + dest.PackFromVector4(LightenSrcAtop(backdrop.ToVector4(),source.ToVector4(),opacity)); + return dest; + } + + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TPixel LightenSrcOver(TPixel backdrop, TPixel source, float opacity) + where TPixel : struct, IPixel + { + TPixel dest = default; + dest.PackFromVector4(LightenSrcOver(backdrop.ToVector4(),source.ToVector4(),opacity)); + return dest; + } + + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TPixel LightenSrcIn(TPixel backdrop, TPixel source, float opacity) + where TPixel : struct, IPixel + { + TPixel dest = default; + dest.PackFromVector4(LightenSrcIn(backdrop.ToVector4(),source.ToVector4(),opacity)); + return dest; + } + + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TPixel LightenSrcOut(TPixel backdrop, TPixel source, float opacity) + where TPixel : struct, IPixel + { + TPixel dest = default; + dest.PackFromVector4(LightenSrcOut(backdrop.ToVector4(),source.ToVector4(),opacity)); + return dest; + } + + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TPixel LightenDest(TPixel backdrop, TPixel source, float opacity) + where TPixel : struct, IPixel + { + TPixel dest = default; + dest.PackFromVector4(LightenDest(backdrop.ToVector4(),source.ToVector4(),opacity)); + return dest; + } + + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TPixel LightenDestAtop(TPixel backdrop, TPixel source, float opacity) + where TPixel : struct, IPixel + { + TPixel dest = default; + dest.PackFromVector4(LightenDestAtop(backdrop.ToVector4(),source.ToVector4(),opacity)); + return dest; + } + + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TPixel LightenDestOver(TPixel backdrop, TPixel source, float opacity) + where TPixel : struct, IPixel + { + TPixel dest = default; + dest.PackFromVector4(LightenDestOver(backdrop.ToVector4(),source.ToVector4(),opacity)); + return dest; + } + + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TPixel LightenDestIn(TPixel backdrop, TPixel source, float opacity) + where TPixel : struct, IPixel + { + TPixel dest = default; + dest.PackFromVector4(LightenDestIn(backdrop.ToVector4(),source.ToVector4(),opacity)); + return dest; + } + + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TPixel LightenDestOut(TPixel backdrop, TPixel source, float opacity) + where TPixel : struct, IPixel + { + TPixel dest = default; + dest.PackFromVector4(LightenDestOut(backdrop.ToVector4(),source.ToVector4(),opacity)); + return dest; + } + + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TPixel LightenClear(TPixel backdrop, TPixel source, float opacity) + where TPixel : struct, IPixel + { + TPixel dest = default; + dest.PackFromVector4(LightenClear(backdrop.ToVector4(),source.ToVector4(),opacity)); + return dest; + } + + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TPixel LightenXor(TPixel backdrop, TPixel source, float opacity) + where TPixel : struct, IPixel + { + TPixel dest = default; + dest.PackFromVector4(LightenXor(backdrop.ToVector4(),source.ToVector4(),opacity)); + return dest; + } + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 OverlaySrc(Vector4 backdrop, Vector4 source, float opacity) + { + opacity = opacity.Clamp(0, 1); + source.W *= opacity; + + return source; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 OverlaySrcAtop(Vector4 backdrop, Vector4 source, float opacity) + { + opacity = opacity.Clamp(0, 1); + source.W *= opacity; + + return Atop(backdrop, source, Overlay(backdrop, source)); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 OverlaySrcOver(Vector4 backdrop, Vector4 source, float opacity) + { + opacity = opacity.Clamp(0, 1); + source.W *= opacity; + + return Over(backdrop, source, Overlay(backdrop, source)); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 OverlaySrcIn(Vector4 backdrop, Vector4 source, float opacity) + { + opacity = opacity.Clamp(0, 1); + source.W *= opacity; + + return In(backdrop, source, Overlay(backdrop, source)); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 OverlaySrcOut(Vector4 backdrop, Vector4 source, float opacity) + { + opacity = opacity.Clamp(0, 1); + source.W *= opacity; + + return Out(backdrop, source); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 OverlayDest(Vector4 backdrop, Vector4 source, float opacity) + { + return backdrop; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 OverlayDestAtop(Vector4 backdrop, Vector4 source, float opacity) + { + opacity = opacity.Clamp(0, 1); + source.W *= opacity; + + return Atop(source, backdrop, Overlay(source, backdrop)); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 OverlayDestOver(Vector4 backdrop, Vector4 source, float opacity) + { + opacity = opacity.Clamp(0, 1); + source.W *= opacity; + + return Over(source, backdrop, Overlay(source, backdrop)); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 OverlayDestIn(Vector4 backdrop, Vector4 source, float opacity) + { + opacity = opacity.Clamp(0, 1); + source.W *= opacity; + + return In(source, backdrop, Overlay(source, backdrop)); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 OverlayDestOut(Vector4 backdrop, Vector4 source, float opacity) + { + opacity = opacity.Clamp(0, 1); + source.W *= opacity; + + return Out(source, backdrop); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 OverlayXor(Vector4 backdrop, Vector4 source, float opacity) + { + opacity = opacity.Clamp(0, 1); + source.W *= opacity; + + return Xor(backdrop, source); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 OverlayClear(Vector4 backdrop, Vector4 source, float opacity) + { + opacity = opacity.Clamp(0, 1); + source.W *= opacity; + + return Clear(backdrop, source); + } + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TPixel OverlaySrc(TPixel backdrop, TPixel source, float opacity) + where TPixel : struct, IPixel + { + TPixel dest = default; + dest.PackFromVector4(OverlaySrc(backdrop.ToVector4(),source.ToVector4(),opacity)); + return dest; + } + + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TPixel OverlaySrcAtop(TPixel backdrop, TPixel source, float opacity) + where TPixel : struct, IPixel + { + TPixel dest = default; + dest.PackFromVector4(OverlaySrcAtop(backdrop.ToVector4(),source.ToVector4(),opacity)); + return dest; + } + + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TPixel OverlaySrcOver(TPixel backdrop, TPixel source, float opacity) + where TPixel : struct, IPixel + { + TPixel dest = default; + dest.PackFromVector4(OverlaySrcOver(backdrop.ToVector4(),source.ToVector4(),opacity)); + return dest; + } + + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TPixel OverlaySrcIn(TPixel backdrop, TPixel source, float opacity) + where TPixel : struct, IPixel + { + TPixel dest = default; + dest.PackFromVector4(OverlaySrcIn(backdrop.ToVector4(),source.ToVector4(),opacity)); + return dest; + } + + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TPixel OverlaySrcOut(TPixel backdrop, TPixel source, float opacity) + where TPixel : struct, IPixel + { + TPixel dest = default; + dest.PackFromVector4(OverlaySrcOut(backdrop.ToVector4(),source.ToVector4(),opacity)); + return dest; + } + + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TPixel OverlayDest(TPixel backdrop, TPixel source, float opacity) + where TPixel : struct, IPixel + { + TPixel dest = default; + dest.PackFromVector4(OverlayDest(backdrop.ToVector4(),source.ToVector4(),opacity)); + return dest; + } + + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TPixel OverlayDestAtop(TPixel backdrop, TPixel source, float opacity) + where TPixel : struct, IPixel + { + TPixel dest = default; + dest.PackFromVector4(OverlayDestAtop(backdrop.ToVector4(),source.ToVector4(),opacity)); + return dest; + } + + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TPixel OverlayDestOver(TPixel backdrop, TPixel source, float opacity) + where TPixel : struct, IPixel + { + TPixel dest = default; + dest.PackFromVector4(OverlayDestOver(backdrop.ToVector4(),source.ToVector4(),opacity)); + return dest; + } + + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TPixel OverlayDestIn(TPixel backdrop, TPixel source, float opacity) + where TPixel : struct, IPixel + { + TPixel dest = default; + dest.PackFromVector4(OverlayDestIn(backdrop.ToVector4(),source.ToVector4(),opacity)); + return dest; + } + + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TPixel OverlayDestOut(TPixel backdrop, TPixel source, float opacity) + where TPixel : struct, IPixel + { + TPixel dest = default; + dest.PackFromVector4(OverlayDestOut(backdrop.ToVector4(),source.ToVector4(),opacity)); + return dest; + } + + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TPixel OverlayClear(TPixel backdrop, TPixel source, float opacity) + where TPixel : struct, IPixel + { + TPixel dest = default; + dest.PackFromVector4(OverlayClear(backdrop.ToVector4(),source.ToVector4(),opacity)); + return dest; + } + + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TPixel OverlayXor(TPixel backdrop, TPixel source, float opacity) + where TPixel : struct, IPixel + { + TPixel dest = default; + dest.PackFromVector4(OverlayXor(backdrop.ToVector4(),source.ToVector4(),opacity)); + return dest; + } + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 HardLightSrc(Vector4 backdrop, Vector4 source, float opacity) + { + opacity = opacity.Clamp(0, 1); + source.W *= opacity; + + return source; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 HardLightSrcAtop(Vector4 backdrop, Vector4 source, float opacity) + { + opacity = opacity.Clamp(0, 1); + source.W *= opacity; + + return Atop(backdrop, source, HardLight(backdrop, source)); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 HardLightSrcOver(Vector4 backdrop, Vector4 source, float opacity) + { + opacity = opacity.Clamp(0, 1); + source.W *= opacity; + + return Over(backdrop, source, HardLight(backdrop, source)); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 HardLightSrcIn(Vector4 backdrop, Vector4 source, float opacity) + { + opacity = opacity.Clamp(0, 1); + source.W *= opacity; + + return In(backdrop, source, HardLight(backdrop, source)); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 HardLightSrcOut(Vector4 backdrop, Vector4 source, float opacity) + { + opacity = opacity.Clamp(0, 1); + source.W *= opacity; + + return Out(backdrop, source); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 HardLightDest(Vector4 backdrop, Vector4 source, float opacity) + { + return backdrop; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 HardLightDestAtop(Vector4 backdrop, Vector4 source, float opacity) + { + opacity = opacity.Clamp(0, 1); + source.W *= opacity; + + return Atop(source, backdrop, HardLight(source, backdrop)); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 HardLightDestOver(Vector4 backdrop, Vector4 source, float opacity) + { + opacity = opacity.Clamp(0, 1); + source.W *= opacity; + + return Over(source, backdrop, HardLight(source, backdrop)); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 HardLightDestIn(Vector4 backdrop, Vector4 source, float opacity) + { + opacity = opacity.Clamp(0, 1); + source.W *= opacity; + + return In(source, backdrop, HardLight(source, backdrop)); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 HardLightDestOut(Vector4 backdrop, Vector4 source, float opacity) + { + opacity = opacity.Clamp(0, 1); + source.W *= opacity; + + return Out(source, backdrop); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 HardLightXor(Vector4 backdrop, Vector4 source, float opacity) + { + opacity = opacity.Clamp(0, 1); + source.W *= opacity; + + return Xor(backdrop, source); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 HardLightClear(Vector4 backdrop, Vector4 source, float opacity) + { + opacity = opacity.Clamp(0, 1); + source.W *= opacity; + + return Clear(backdrop, source); + } + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TPixel HardLightSrc(TPixel backdrop, TPixel source, float opacity) + where TPixel : struct, IPixel + { + TPixel dest = default; + dest.PackFromVector4(HardLightSrc(backdrop.ToVector4(),source.ToVector4(),opacity)); + return dest; + } + + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TPixel HardLightSrcAtop(TPixel backdrop, TPixel source, float opacity) + where TPixel : struct, IPixel + { + TPixel dest = default; + dest.PackFromVector4(HardLightSrcAtop(backdrop.ToVector4(),source.ToVector4(),opacity)); + return dest; + } + + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TPixel HardLightSrcOver(TPixel backdrop, TPixel source, float opacity) + where TPixel : struct, IPixel + { + TPixel dest = default; + dest.PackFromVector4(HardLightSrcOver(backdrop.ToVector4(),source.ToVector4(),opacity)); + return dest; + } + + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TPixel HardLightSrcIn(TPixel backdrop, TPixel source, float opacity) + where TPixel : struct, IPixel + { + TPixel dest = default; + dest.PackFromVector4(HardLightSrcIn(backdrop.ToVector4(),source.ToVector4(),opacity)); + return dest; + } + + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TPixel HardLightSrcOut(TPixel backdrop, TPixel source, float opacity) + where TPixel : struct, IPixel + { + TPixel dest = default; + dest.PackFromVector4(HardLightSrcOut(backdrop.ToVector4(),source.ToVector4(),opacity)); + return dest; + } + + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TPixel HardLightDest(TPixel backdrop, TPixel source, float opacity) + where TPixel : struct, IPixel + { + TPixel dest = default; + dest.PackFromVector4(HardLightDest(backdrop.ToVector4(),source.ToVector4(),opacity)); + return dest; + } + + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TPixel HardLightDestAtop(TPixel backdrop, TPixel source, float opacity) + where TPixel : struct, IPixel + { + TPixel dest = default; + dest.PackFromVector4(HardLightDestAtop(backdrop.ToVector4(),source.ToVector4(),opacity)); + return dest; + } + + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TPixel HardLightDestOver(TPixel backdrop, TPixel source, float opacity) + where TPixel : struct, IPixel + { + TPixel dest = default; + dest.PackFromVector4(HardLightDestOver(backdrop.ToVector4(),source.ToVector4(),opacity)); + return dest; + } + + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TPixel HardLightDestIn(TPixel backdrop, TPixel source, float opacity) + where TPixel : struct, IPixel + { + TPixel dest = default; + dest.PackFromVector4(HardLightDestIn(backdrop.ToVector4(),source.ToVector4(),opacity)); + return dest; + } + + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TPixel HardLightDestOut(TPixel backdrop, TPixel source, float opacity) + where TPixel : struct, IPixel + { + TPixel dest = default; + dest.PackFromVector4(HardLightDestOut(backdrop.ToVector4(),source.ToVector4(),opacity)); + return dest; + } + + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TPixel HardLightClear(TPixel backdrop, TPixel source, float opacity) + where TPixel : struct, IPixel + { + TPixel dest = default; + dest.PackFromVector4(HardLightClear(backdrop.ToVector4(),source.ToVector4(),opacity)); + return dest; + } + + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TPixel HardLightXor(TPixel backdrop, TPixel source, float opacity) + where TPixel : struct, IPixel + { + TPixel dest = default; + dest.PackFromVector4(HardLightXor(backdrop.ToVector4(),source.ToVector4(),opacity)); + return dest; + } + + } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.Generated.tt b/src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.Generated.tt index 4cbc06861..5e46a89a8 100644 --- a/src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.Generated.tt +++ b/src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.Generated.tt @@ -1,112 +1,188 @@ -<# -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. -#> -<#@ 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" #> -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -// - -using System; -using System.Numerics; -using System.Runtime.CompilerServices; - -namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders -{ - internal static partial class PorterDuffFunctions - { -<# - - void GeneratePixelBlender (string blender) - { -#> - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static TPixel <#=blender#>(TPixel backdrop, TPixel source, float amount) - where TPixel : struct, IPixel - { - TPixel dest = default; - dest.PackFromVector4(<#=blender#>(backdrop.ToVector4(), source.ToVector4(), amount)); - return dest; - } - -<# - } - - void GenerateVectorCompositor(string name, string sourceVar, string destVar, string blendVar) - { - int a_s = sourceVar == "Vector4.Zero" ? 0 : 1; - int a_b = destVar == "Vector4.Zero" ? 0 : 1; - int a_x = blendVar == "Vector4.Zero" ? 0 : 1; -#> - [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; -<# } #> - - // calculate weights - float xw = backdrop.W * source.W; - float bw = backdrop.W - xw; - float sw = source.W - xw; - - // calculate final alpha - float fw = (sw * <#=a_s#>) + (bw * <#=a_b#>) + (xw * <#=a_x#>); - - // calculate final value - Vector4 xform = ((<#=blendVar#> * xw) + (<#=destVar#> * bw) + (<#=sourceVar#> * sw)) / MathF.Max(fw, Constants.Epsilon); - xform.W = fw; - - 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("Subtract"); - 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"); - - -#> - } +<# +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. +#> +<#@ 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" #> +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +// + +using System; +using System.Numerics; +using System.Runtime.CompilerServices; + +namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders +{ + internal static partial class PorterDuffFunctions + { + +<# void GeneratePixelBlenders(string blender) { #> + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 <#=blender#>Src(Vector4 backdrop, Vector4 source, float opacity) + { + opacity = opacity.Clamp(0, 1); + source.W *= opacity; + + return source; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 <#=blender#>SrcAtop(Vector4 backdrop, Vector4 source, float opacity) + { + opacity = opacity.Clamp(0, 1); + source.W *= opacity; + + return Atop(backdrop, source, <#=blender#>(backdrop, source)); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 <#=blender#>SrcOver(Vector4 backdrop, Vector4 source, float opacity) + { + opacity = opacity.Clamp(0, 1); + source.W *= opacity; + + return Over(backdrop, source, <#=blender#>(backdrop, source)); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 <#=blender#>SrcIn(Vector4 backdrop, Vector4 source, float opacity) + { + opacity = opacity.Clamp(0, 1); + source.W *= opacity; + + return In(backdrop, source, <#=blender#>(backdrop, source)); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 <#=blender#>SrcOut(Vector4 backdrop, Vector4 source, float opacity) + { + opacity = opacity.Clamp(0, 1); + source.W *= opacity; + + return Out(backdrop, source); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 <#=blender#>Dest(Vector4 backdrop, Vector4 source, float opacity) + { + return backdrop; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 <#=blender#>DestAtop(Vector4 backdrop, Vector4 source, float opacity) + { + opacity = opacity.Clamp(0, 1); + source.W *= opacity; + + return Atop(source, backdrop, <#=blender#>(source, backdrop)); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 <#=blender#>DestOver(Vector4 backdrop, Vector4 source, float opacity) + { + opacity = opacity.Clamp(0, 1); + source.W *= opacity; + + return Over(source, backdrop, <#=blender#>(source, backdrop)); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 <#=blender#>DestIn(Vector4 backdrop, Vector4 source, float opacity) + { + opacity = opacity.Clamp(0, 1); + source.W *= opacity; + + return In(source, backdrop, <#=blender#>(source, backdrop)); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 <#=blender#>DestOut(Vector4 backdrop, Vector4 source, float opacity) + { + opacity = opacity.Clamp(0, 1); + source.W *= opacity; + + return Out(source, backdrop); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 <#=blender#>Xor(Vector4 backdrop, Vector4 source, float opacity) + { + opacity = opacity.Clamp(0, 1); + source.W *= opacity; + + return Xor(backdrop, source); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 <#=blender#>Clear(Vector4 backdrop, Vector4 source, float opacity) + { + opacity = opacity.Clamp(0, 1); + source.W *= opacity; + + return Clear(backdrop, source); + } +<# } #> + + +<# void GenerateGenericPixelBlender(string blender, string composer) { #> + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TPixel <#=blender#><#=composer#>(TPixel backdrop, TPixel source, float opacity) + where TPixel : struct, IPixel + { + TPixel dest = default; + dest.PackFromVector4(<#=blender#><#=composer#>(backdrop.ToVector4(),source.ToVector4(),opacity)); + return dest; + } + +<# } #> + +<# + +string[] composers = new []{ + "Src", + "SrcAtop", + "SrcOver", + "SrcIn", + "SrcOut", + "Dest", + "DestAtop", + "DestOver", + "DestIn", + "DestOut", + "Clear", + "Xor", +}; + +string[] blenders = new []{ + "Normal", + "Multiply", + "Add", + "Subtract", + "Screen", + "Darken", + "Lighten", + "Overlay", + "HardLight" +}; + + foreach(var blender in blenders) + { + GeneratePixelBlenders(blender); + + foreach(var composer in composers) + { + GenerateGenericPixelBlender(blender,composer); + } + } + +#> + } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.cs b/src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.cs index c47ef35a3..e10c8fe91 100644 --- a/src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.cs +++ b/src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.cs @@ -1,194 +1,257 @@ -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -using System; -using System.Numerics; -using System.Runtime.CompilerServices; - -namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders -{ - /// - /// Collection of Porter Duff alpha blending functions applying an the 'Over' composition model. - /// - /// - /// These functions are designed to be a general solution for all color cases, - /// that is, they take in account the alpha value of both the backdrop - /// and source, and there's no need to alpha-premultiply neither the backdrop - /// nor the source. - /// Note there are faster functions for when the backdrop color is known - /// to be opaque - /// - internal static partial class PorterDuffFunctions - { - /// - /// Source over backdrop - /// - /// Backdrop color - /// Source color - /// Opacity applied to Source Alpha - /// Output color - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Vector4 Normal(Vector4 backdrop, Vector4 source, float opacity) - { - source.W *= opacity; - return Compose(backdrop, source, source); - } - - /// - /// Source multiplied by backdrop - /// - /// Backdrop color - /// Source color - /// Opacity applied to Source Alpha - /// Output color - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Vector4 Multiply(Vector4 backdrop, Vector4 source, float opacity) - { - source.W *= opacity; - return Compose(backdrop, source, backdrop * source); - } - - /// - /// Source added to backdrop - /// - /// Backdrop color - /// Source color - /// Opacity applied to Source Alpha - /// Output color - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Vector4 Add(Vector4 backdrop, Vector4 source, float opacity) - { - source.W *= opacity; - return Compose(backdrop, source, Vector4.Min(Vector4.One, backdrop + source)); - } - - /// - /// Source subtracted from backdrop - /// - /// Backdrop color - /// Source color - /// Opacity applied to Source Alpha - /// Output color - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Vector4 Subtract(Vector4 backdrop, Vector4 source, float opacity) - { - source.W *= opacity; - return Compose(backdrop, source, Vector4.Max(Vector4.Zero, backdrop - source)); - } - - /// - /// Complement of source multiplied by the complement of backdrop - /// - /// Backdrop color - /// Source color - /// Opacity applied to Source Alpha - /// Output color - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Vector4 Screen(Vector4 backdrop, Vector4 source, float opacity) - { - source.W *= opacity; - return Compose(backdrop, source, Vector4.One - ((Vector4.One - backdrop) * (Vector4.One - source))); - } - - /// - /// Per element, chooses the smallest value of source and backdrop - /// - /// Backdrop color - /// Source color - /// Opacity applied to Source Alpha - /// Output color - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Vector4 Darken(Vector4 backdrop, Vector4 source, float opacity) - { - source.W *= opacity; - return Compose(backdrop, source, Vector4.Min(backdrop, source)); - } - - /// - /// Per element, chooses the largest value of source and backdrop - /// - /// Backdrop color - /// Source color - /// Opacity applied to Source Alpha - /// Output color - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Vector4 Lighten(Vector4 backdrop, Vector4 source, float opacity) - { - source.W *= opacity; - return Compose(backdrop, source, Vector4.Max(backdrop, source)); - } - - /// - /// Overlays source over backdrop - /// - /// Backdrop color - /// Source color - /// Opacity applied to Source Alpha - /// Output color - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Vector4 Overlay(Vector4 backdrop, Vector4 source, float opacity) - { - source.W *= opacity; - float cr = OverlayValueFunction(backdrop.X, source.X); - float cg = OverlayValueFunction(backdrop.Y, source.Y); - float cb = OverlayValueFunction(backdrop.Z, source.Z); - - return Compose(backdrop, source, Vector4.Min(Vector4.One, new Vector4(cr, cg, cb, 0))); - } - - /// - /// Hard light effect - /// - /// Backdrop color - /// Source color - /// Opacity applied to Source Alpha - /// Output color - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Vector4 HardLight(Vector4 backdrop, Vector4 source, float opacity) - { - source.W *= opacity; - float cr = OverlayValueFunction(source.X, backdrop.X); - float cg = OverlayValueFunction(source.Y, backdrop.Y); - float cb = OverlayValueFunction(source.Z, backdrop.Z); - - return Compose(backdrop, source, Vector4.Min(Vector4.One, new Vector4(cr, cg, cb, 0))); - } - - /// - /// Helper function for Overlay andHardLight modes - /// - /// Backdrop color element - /// Source color element - /// Overlay value - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static float OverlayValueFunction(float backdrop, float source) - { - return backdrop <= 0.5f ? (2 * backdrop * source) : 1 - ((2 * (1 - source)) * (1 - backdrop)); - } - - /// - /// General composition function for all modes, with a general solution for alpha channel - /// - /// Original Backdrop color - /// Original source color - /// Desired transformed color, without taking Alpha channel in account - /// The final color - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static Vector4 Compose(Vector4 backdrop, Vector4 source, Vector4 xform) - { - // 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); - xform.W = a; - - return xform; - } - } +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Numerics; +using System.Runtime.CompilerServices; + +namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders +{ + /// + /// Collection of Porter Duff alpha blending functions applying an the 'Over' composition model. + /// + /// + /// These functions are designed to be a general solution for all color cases, + /// that is, they take in account the alpha value of both the backdrop + /// and source, and there's no need to alpha-premultiply neither the backdrop + /// nor the source. + /// Note there are faster functions for when the backdrop color is known + /// to be opaque + /// + internal static partial class PorterDuffFunctions + { + /// + /// Source over backdrop + /// + /// Backdrop color + /// Source color + /// Output color + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 Normal(Vector4 backdrop, Vector4 source) + { + return source; + } + + /// + /// Source multiplied by backdrop + /// + /// Backdrop color + /// Source color + /// Output color + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 Multiply(Vector4 backdrop, Vector4 source) + { + return backdrop * source; + } + + /// + /// Source added to backdrop + /// + /// Backdrop color + /// Source color + /// Output color + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 Add(Vector4 backdrop, Vector4 source) + { + return Vector4.Min(Vector4.One, backdrop + source); + } + + /// + /// Source subtracted from backdrop + /// + /// Backdrop color + /// Source color + /// Output color + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 Subtract(Vector4 backdrop, Vector4 source) + { + return Vector4.Max(Vector4.Zero, backdrop - source); + } + + /// + /// Complement of source multiplied by the complement of backdrop + /// + /// Backdrop color + /// Source color + /// Output color + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 Screen(Vector4 backdrop, Vector4 source) + { + return Vector4.One - ((Vector4.One - backdrop) * (Vector4.One - source)); + } + + /// + /// Per element, chooses the smallest value of source and backdrop + /// + /// Backdrop color + /// Source color + /// Output color + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 Darken(Vector4 backdrop, Vector4 source) + { + return Vector4.Min(backdrop, source); + } + + /// + /// Per element, chooses the largest value of source and backdrop + /// + /// Backdrop color + /// Source color + /// Output color + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 Lighten(Vector4 backdrop, Vector4 source) + { + return Vector4.Max(backdrop, source); + } + + /// + /// Overlays source over backdrop + /// + /// Backdrop color + /// Source color + /// Output color + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 Overlay(Vector4 backdrop, Vector4 source) + { + float cr = OverlayValueFunction(backdrop.X, source.X); + float cg = OverlayValueFunction(backdrop.Y, source.Y); + float cb = OverlayValueFunction(backdrop.Z, source.Z); + + return Vector4.Min(Vector4.One, new Vector4(cr, cg, cb, 0)); + } + + /// + /// Hard light effect + /// + /// Backdrop color + /// Source color + /// Output color + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 HardLight(Vector4 backdrop, Vector4 source) + { + float cr = OverlayValueFunction(source.X, backdrop.X); + float cg = OverlayValueFunction(source.Y, backdrop.Y); + float cb = OverlayValueFunction(source.Z, backdrop.Z); + + return Vector4.Min(Vector4.One, new Vector4(cr, cg, cb, 0)); + } + + /// + /// Helper function for Overlay andHardLight modes + /// + /// Backdrop color element + /// Source color element + /// Overlay value + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static float OverlayValueFunction(float backdrop, float source) + { + return backdrop <= 0.5f ? (2 * backdrop * source) : 1 - ((2 * (1 - source)) * (1 - backdrop)); + } + + /// + /// General composition function for all modes, with a general solution for alpha channel + /// + /// Original Backdrop color + /// Original source color + /// Desired transformed color, without taking Alpha channel in account + /// The final color + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static Vector4 SrcOverReference(Vector4 backdrop, Vector4 source, Vector4 xform) + { + // 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); + xform.W = a; + + return xform; + } + + public static Vector4 Over(Vector4 dst, Vector4 src, Vector4 blend) + { + // calculate weights + float blendW = dst.W * src.W; + float dstW = dst.W - blendW; + float srcW = src.W - blendW; + + // calculate final alpha + float alpha = dstW + srcW + blendW; + + // calculate final color + Vector4 color = (dst * dstW) + (src * srcW) + (blend * blendW); + + // unpremultiply + color /= MathF.Max(alpha, Constants.Epsilon); + color.W = alpha; + + return color; + } + + public static Vector4 Atop(Vector4 dst, Vector4 src, Vector4 blend) + { + // calculate weights + float blendW = dst.W * src.W; + float dstW = dst.W - blendW; + + // calculate final alpha + float alpha = dstW + blendW; + + // calculate final color + Vector4 color = (dst * dstW) + (blend * blendW); + + // unpremultiply + color /= MathF.Max(alpha, Constants.Epsilon); + color.W = alpha; + + return color; + } + + public static Vector4 In(Vector4 dst, Vector4 src, Vector4 blend) + { + float alpha = dst.W * src.W; + + Vector4 color = src * alpha; // premultiply + color /= MathF.Max(alpha, Constants.Epsilon); // unpremultiply + color.W = alpha; + + return color; + } + + public static Vector4 Out(Vector4 dst, Vector4 src) + { + float alpha = (1 - dst.W) * src.W; + + Vector4 color = src * alpha; // premultiply + color /= MathF.Max(alpha, Constants.Epsilon); // unpremultiply + color.W = alpha; + + return color; + } + + public static Vector4 Xor(Vector4 dst, Vector4 src) + { + float srcW = 1 - dst.W; + float dstW = 1 - src.W; + + float alpha = (src.W * srcW) + (dst.W * dstW); + Vector4 color = (src.W * src * srcW) + (dst.W * dst * dstW); + + // unpremultiply + color /= MathF.Max(alpha, Constants.Epsilon); + color.W = alpha; + + return color; + } + + private static Vector4 Clear(Vector4 backdrop, Vector4 source) + { + return Vector4.Zero; + } + } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.PixelBenders.cs b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.PixelBenders.cs index 2c225ba4c..ca6a28192 100644 --- a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.PixelBenders.cs +++ b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.PixelBenders.cs @@ -20,30 +20,30 @@ namespace SixLabors.ImageSharp.PixelFormats { switch (mode) { - case PixelBlenderMode.Multiply: return DefaultPixelBlenders.Multiply.Instance; - case PixelBlenderMode.Add: return DefaultPixelBlenders.Add.Instance; - case PixelBlenderMode.Subtract: return DefaultPixelBlenders.Subtract.Instance; - case PixelBlenderMode.Screen: return DefaultPixelBlenders.Screen.Instance; - case PixelBlenderMode.Darken: return DefaultPixelBlenders.Darken.Instance; - case PixelBlenderMode.Lighten: return DefaultPixelBlenders.Lighten.Instance; - case PixelBlenderMode.Overlay: return DefaultPixelBlenders.Overlay.Instance; - case PixelBlenderMode.HardLight: return DefaultPixelBlenders.HardLight.Instance; - case PixelBlenderMode.Src: return DefaultPixelBlenders.Src.Instance; - case PixelBlenderMode.Atop: return DefaultPixelBlenders.Atop.Instance; - case PixelBlenderMode.Over: return DefaultPixelBlenders.Over.Instance; - case PixelBlenderMode.In: return DefaultPixelBlenders.In.Instance; - case PixelBlenderMode.Out: return DefaultPixelBlenders.Out.Instance; - case PixelBlenderMode.Dest: return DefaultPixelBlenders.Dest.Instance; - case PixelBlenderMode.DestAtop: return DefaultPixelBlenders.DestAtop.Instance; - case PixelBlenderMode.DestOver: return DefaultPixelBlenders.DestOver.Instance; - case PixelBlenderMode.DestIn: return DefaultPixelBlenders.DestIn.Instance; - case PixelBlenderMode.DestOut: return DefaultPixelBlenders.DestOut.Instance; - case PixelBlenderMode.Clear: return DefaultPixelBlenders.Clear.Instance; - case PixelBlenderMode.Xor: return DefaultPixelBlenders.Xor.Instance; + case PixelBlenderMode.Multiply: return DefaultPixelBlenders.MultiplySrcOver.Instance; + case PixelBlenderMode.Add: return DefaultPixelBlenders.AddSrcOver.Instance; + case PixelBlenderMode.Subtract: return DefaultPixelBlenders.SubtractSrcOver.Instance; + case PixelBlenderMode.Screen: return DefaultPixelBlenders.ScreenSrcOver.Instance; + case PixelBlenderMode.Darken: return DefaultPixelBlenders.DarkenSrcOver.Instance; + case PixelBlenderMode.Lighten: return DefaultPixelBlenders.LightenSrcOver.Instance; + case PixelBlenderMode.Overlay: return DefaultPixelBlenders.OverlaySrcOver.Instance; + case PixelBlenderMode.HardLight: return DefaultPixelBlenders.HardLightSrcOver.Instance; + case PixelBlenderMode.Src: return DefaultPixelBlenders.NormalSrc.Instance; + case PixelBlenderMode.Atop: return DefaultPixelBlenders.NormalSrcAtop.Instance; + case PixelBlenderMode.Over: return DefaultPixelBlenders.NormalSrcOver.Instance; + case PixelBlenderMode.In: return DefaultPixelBlenders.NormalSrcIn.Instance; + case PixelBlenderMode.Out: return DefaultPixelBlenders.NormalSrcOut.Instance; + case PixelBlenderMode.Dest: return DefaultPixelBlenders.NormalDest.Instance; + case PixelBlenderMode.DestAtop: return DefaultPixelBlenders.NormalDestAtop.Instance; + case PixelBlenderMode.DestOver: return DefaultPixelBlenders.NormalDestOver.Instance; + case PixelBlenderMode.DestIn: return DefaultPixelBlenders.NormalDestIn.Instance; + case PixelBlenderMode.DestOut: return DefaultPixelBlenders.NormalDestOut.Instance; + case PixelBlenderMode.Clear: return DefaultPixelBlenders.NormalClear.Instance; + case PixelBlenderMode.Xor: return DefaultPixelBlenders.NormalXor.Instance; case PixelBlenderMode.Normal: default: - return DefaultPixelBlenders.Normal.Instance; + return DefaultPixelBlenders.NormalSrcOver.Instance; } } } diff --git a/src/ImageSharp/PixelFormats/Rgba32.cs b/src/ImageSharp/PixelFormats/Rgba32.cs index 3c94678aa..623c58d08 100644 --- a/src/ImageSharp/PixelFormats/Rgba32.cs +++ b/src/ImageSharp/PixelFormats/Rgba32.cs @@ -448,12 +448,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public override int GetHashCode() - { - int hash = HashHelpers.Combine(this.R.GetHashCode(), this.G.GetHashCode()); - hash = HashHelpers.Combine(hash, this.B.GetHashCode()); - return HashHelpers.Combine(hash, this.A.GetHashCode()); - } + public override int GetHashCode() => this.Rgba.GetHashCode(); /// /// Gets the representation without normalizing to [0, 1] diff --git a/src/ImageSharp/PixelFormats/Rgba64.cs b/src/ImageSharp/PixelFormats/Rgba64.cs index a66485ba4..8e6be1e8c 100644 --- a/src/ImageSharp/PixelFormats/Rgba64.cs +++ b/src/ImageSharp/PixelFormats/Rgba64.cs @@ -295,9 +295,6 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public override int GetHashCode() - { - return this.PackedValue.GetHashCode(); - } + public override int GetHashCode() => this.PackedValue.GetHashCode(); } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/Short2.cs b/src/ImageSharp/PixelFormats/Short2.cs index c298c5a48..9fc7618b9 100644 --- a/src/ImageSharp/PixelFormats/Short2.cs +++ b/src/ImageSharp/PixelFormats/Short2.cs @@ -249,10 +249,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public override int GetHashCode() - { - return this.PackedValue.GetHashCode(); - } + public override int GetHashCode() => this.PackedValue.GetHashCode(); /// public override string ToString() diff --git a/src/ImageSharp/PixelFormats/Short4.cs b/src/ImageSharp/PixelFormats/Short4.cs index 5683ffcee..641f154f9 100644 --- a/src/ImageSharp/PixelFormats/Short4.cs +++ b/src/ImageSharp/PixelFormats/Short4.cs @@ -247,10 +247,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// Hash code for the instance. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public override int GetHashCode() - { - return this.PackedValue.GetHashCode(); - } + public override int GetHashCode() => this.PackedValue.GetHashCode(); /// /// Returns a string representation of the current instance. diff --git a/tests/ImageSharp.Benchmarks/PixelBlenders/PorterDuffBulkVsPixel.cs b/tests/ImageSharp.Benchmarks/PixelBlenders/PorterDuffBulkVsPixel.cs index 59118a1df..d9cf65d4b 100644 --- a/tests/ImageSharp.Benchmarks/PixelBlenders/PorterDuffBulkVsPixel.cs +++ b/tests/ImageSharp.Benchmarks/PixelBlenders/PorterDuffBulkVsPixel.cs @@ -40,7 +40,7 @@ namespace SixLabors.ImageSharp.Benchmarks for (int i = 0; i < destination.Length; i++) { - destinationSpan[i] = PorterDuffFunctions.Normal(backgroundSpan[i], sourceSpan[i], amount[i]); + destinationSpan[i] = PorterDuffFunctions.NormalSrcOver(backgroundSpan[i], sourceSpan[i], amount[i]); } PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); @@ -60,7 +60,7 @@ namespace SixLabors.ImageSharp.Benchmarks for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.Normal(destination[i], source[i], amount[i]); + destination[i] = PorterDuffFunctions.NormalSrcOver(destination[i], source[i], amount[i]); } } diff --git a/tests/ImageSharp.Tests/Drawing/SolidFillBlendedShapesTests.cs b/tests/ImageSharp.Tests/Drawing/SolidFillBlendedShapesTests.cs index 0c08f66c6..b31a18ac4 100644 --- a/tests/ImageSharp.Tests/Drawing/SolidFillBlendedShapesTests.cs +++ b/tests/ImageSharp.Tests/Drawing/SolidFillBlendedShapesTests.cs @@ -1,153 +1,158 @@ -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. -using System; -using System.Collections.Generic; -using System.Linq; -using SixLabors.ImageSharp.PixelFormats; -using SixLabors.ImageSharp.Processing; -using SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison; -using SixLabors.Primitives; -using Xunit; - -// ReSharper disable InconsistentNaming -namespace SixLabors.ImageSharp.Tests.Drawing -{ - [GroupOutput("Drawing")] - public class SolidFillBlendedShapesTests - { - public static IEnumerable modes = - ((PixelBlenderMode[])Enum.GetValues(typeof(PixelBlenderMode))).Select(x => new object[] { x }); - - [Theory] - [WithBlankImages(nameof(modes), 250, 250, PixelTypes.Rgba32)] - public void _1DarkBlueRect_2BlendHotPinkRect( - TestImageProvider provider, - PixelBlenderMode mode) - where TPixel : struct, IPixel - { - using (Image img = provider.GetImage()) - { - int scaleX = img.Width / 100; - int scaleY = img.Height / 100; - img.Mutate( - x => x.Fill( - NamedColors.DarkBlue, - new Rectangle(0 * scaleX, 40 * scaleY, 100 * scaleX, 20 * scaleY) - ) - .Fill(new GraphicsOptions(true) { BlenderMode = mode }, - NamedColors.HotPink, - new Rectangle(20 * scaleX, 0 * scaleY, 30 * scaleX, 100 * scaleY)) - ); - - VerifyImage(provider, mode, img); - } - } - - [Theory] - [WithBlankImages(nameof(modes), 250, 250, PixelTypes.Rgba32)] - public void _1DarkBlueRect_2BlendHotPinkRect_3BlendTransparentEllipse( - TestImageProvider provider, - PixelBlenderMode mode) - where TPixel : struct, IPixel - { - using (Image img = provider.GetImage()) - { - int scaleX = img.Width / 100; - int scaleY = img.Height / 100; - img.Mutate( - x => x.Fill( - NamedColors.DarkBlue, - new Rectangle(0 * scaleX, 40 * scaleY, 100 * scaleX, 20 * scaleY))); - img.Mutate( - x => x.Fill( - new GraphicsOptions(true) { BlenderMode = mode }, - NamedColors.HotPink, - new Rectangle(20 * scaleX, 0 * scaleY, 30 * scaleX, 100 * scaleY))); - img.Mutate( - x => x.Fill( - new GraphicsOptions(true) { BlenderMode = mode }, - NamedColors.Transparent, - new Shapes.EllipsePolygon(40 * scaleX, 50 * scaleY, 50 * scaleX, 50 * scaleY)) - ); - - VerifyImage(provider, mode, img); - } - } - - [Theory] - [WithBlankImages(nameof(modes), 250, 250, PixelTypes.Rgba32)] - public void _1DarkBlueRect_2BlendHotPinkRect_3BlendSemiTransparentRedEllipse( - TestImageProvider provider, - PixelBlenderMode mode) - where TPixel : struct, IPixel - { - using (Image img = provider.GetImage()) - { - int scaleX = (img.Width / 100); - int scaleY = (img.Height / 100); - img.Mutate( - x => x.Fill( - NamedColors.DarkBlue, - new Rectangle(0 * scaleX, 40, 100 * scaleX, 20 * scaleY))); - img.Mutate( - x => x.Fill( - new GraphicsOptions(true) { BlenderMode = mode }, - NamedColors.HotPink, - new Rectangle(20 * scaleX, 0, 30 * scaleX, 100 * scaleY))); - var c = NamedColors.Red.ToVector4(); - c.W *= 0.5f; - var pixel = default(TPixel); - pixel.PackFromVector4(c); - - img.Mutate( - x => x.Fill( - new GraphicsOptions(true) { BlenderMode = mode }, - pixel, - new Shapes.EllipsePolygon(40 * scaleX, 50 * scaleY, 50 * scaleX, 50 * scaleY)) - ); - - VerifyImage(provider, mode, img); ; - } - } - - [Theory] - [WithBlankImages(nameof(modes), 250, 250, PixelTypes.Rgba32)] - public void _1DarkBlueRect_2BlendBlackEllipse(TestImageProvider provider, PixelBlenderMode mode) - where TPixel : struct, IPixel - { - using (Image img = provider.GetImage()) - { - int scaleX = (img.Width / 100); - int scaleY = (img.Height / 100); - img.Mutate( - x => x.Fill( - NamedColors.DarkBlue, - new Rectangle(0 * scaleX, 40 * scaleY, 100 * scaleX, 20 * scaleY))); - img.Mutate( - x => x.Fill( - new GraphicsOptions(true) { BlenderMode = mode }, - NamedColors.Black, - new Shapes.EllipsePolygon(40 * scaleX, 50 * scaleY, 50 * scaleX, 50 * scaleY))); - - VerifyImage(provider, mode, img); - } - } - - private static void VerifyImage(TestImageProvider provider, PixelBlenderMode mode, Image img) - where TPixel : struct, IPixel - { - img.DebugSave( - provider, - new { mode }, - appendPixelTypeToFileName: false, - appendSourceFileOrDescription: false); - - var comparer = ImageComparer.TolerantPercentage(0.01f, 3); - img.CompareFirstFrameToReferenceOutput(comparer, - provider, - new { mode }, - appendPixelTypeToFileName: false, - appendSourceFileOrDescription: false); - } - } +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. +using System; +using System.Collections.Generic; +using System.Linq; +using SixLabors.ImageSharp.PixelFormats; +using SixLabors.ImageSharp.Processing; +using SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison; +using SixLabors.Primitives; +using Xunit; + +// ReSharper disable InconsistentNaming +namespace SixLabors.ImageSharp.Tests.Drawing +{ + [GroupOutput("Drawing")] + public class SolidFillBlendedShapesTests + { + public static IEnumerable modes = + ((PixelBlenderMode[])Enum.GetValues(typeof(PixelBlenderMode))).Select(x => new object[] { x }); + + [Theory] + [WithBlankImages(nameof(modes), 250, 250, PixelTypes.Rgba32)] + public void _1DarkBlueRect_2BlendHotPinkRect( + TestImageProvider provider, + PixelBlenderMode mode) + where TPixel : struct, IPixel + { + using (Image img = provider.GetImage()) + { + int scaleX = img.Width / 100; + int scaleY = img.Height / 100; + img.Mutate( + x => x.Fill( + NamedColors.DarkBlue, + new Rectangle(0 * scaleX, 40 * scaleY, 100 * scaleX, 20 * scaleY) + ) + .Fill(new GraphicsOptions(true) { BlenderMode = mode }, + NamedColors.HotPink, + new Rectangle(20 * scaleX, 0 * scaleY, 30 * scaleX, 100 * scaleY)) + ); + + VerifyImage(provider, mode, img); + } + } + + [Theory] + [WithBlankImages(nameof(modes), 250, 250, PixelTypes.Rgba32)] + public void _1DarkBlueRect_2BlendHotPinkRect_3BlendTransparentEllipse( + TestImageProvider provider, + PixelBlenderMode mode) + where TPixel : struct, IPixel + { + using (Image img = provider.GetImage()) + { + int scaleX = img.Width / 100; + int scaleY = img.Height / 100; + img.Mutate( + x => x.Fill( + NamedColors.DarkBlue, + new Rectangle(0 * scaleX, 40 * scaleY, 100 * scaleX, 20 * scaleY))); + img.Mutate( + x => x.Fill( + new GraphicsOptions(true) { BlenderMode = mode }, + NamedColors.HotPink, + new Rectangle(20 * scaleX, 0 * scaleY, 30 * scaleX, 100 * scaleY))); + img.Mutate( + x => x.Fill( + new GraphicsOptions(true) { BlenderMode = mode }, + NamedColors.Transparent, + new Shapes.EllipsePolygon(40 * scaleX, 50 * scaleY, 50 * scaleX, 50 * scaleY)) + ); + + VerifyImage(provider, mode, img); + } + } + + [Theory] + [WithBlankImages(nameof(modes), 250, 250, PixelTypes.Rgba32)] + public void _1DarkBlueRect_2BlendHotPinkRect_3BlendSemiTransparentRedEllipse( + TestImageProvider provider, + PixelBlenderMode mode) + where TPixel : struct, IPixel + { + using (Image img = provider.GetImage()) + { + int scaleX = (img.Width / 100); + int scaleY = (img.Height / 100); + img.Mutate( + x => x.Fill( + NamedColors.DarkBlue, + new Rectangle(0 * scaleX, 40, 100 * scaleX, 20 * scaleY))); + img.Mutate( + x => x.Fill( + new GraphicsOptions(true) { BlenderMode = mode }, + NamedColors.HotPink, + new Rectangle(20 * scaleX, 0, 30 * scaleX, 100 * scaleY))); + var c = NamedColors.Red.ToVector4(); + c.W *= 0.5f; + var pixel = default(TPixel); + pixel.PackFromVector4(c); + + img.Mutate( + x => x.Fill( + new GraphicsOptions(true) { BlenderMode = mode }, + pixel, + new Shapes.EllipsePolygon(40 * scaleX, 50 * scaleY, 50 * scaleX, 50 * scaleY)) + ); + + VerifyImage(provider, mode, img); ; + } + } + + [Theory] + [WithBlankImages(nameof(modes), 250, 250, PixelTypes.Rgba32)] + public void _1DarkBlueRect_2BlendBlackEllipse(TestImageProvider provider, PixelBlenderMode mode) + where TPixel : struct, IPixel + { + using(Image dstImg = provider.GetImage(), srcImg = provider.GetImage()) + { + int scaleX = (dstImg.Width / 100); + int scaleY = (dstImg.Height / 100); + + dstImg.Mutate( + x => x.Fill( + NamedColors.DarkBlue, + new Rectangle(0 * scaleX, 40 * scaleY, 100 * scaleX, 20 * scaleY))); + + srcImg.Mutate( + x => x.Fill( + NamedColors.Black, + new Shapes.EllipsePolygon(40 * scaleX, 50 * scaleY, 50 * scaleX, 50 * scaleY))); + + dstImg.Mutate( + x => x.DrawImage(new GraphicsOptions(true) { BlenderMode = mode }, srcImg) + ); + + VerifyImage(provider, mode, dstImg); + } + } + + private static void VerifyImage(TestImageProvider provider, PixelBlenderMode mode, Image img) + where TPixel : struct, IPixel + { + img.DebugSave( + provider, + new { mode }, + appendPixelTypeToFileName: false, + appendSourceFileOrDescription: false); + + var comparer = ImageComparer.TolerantPercentage(0.01f, 3); + img.CompareFirstFrameToReferenceOutput(comparer, + provider, + new { mode }, + appendPixelTypeToFileName: false, + appendSourceFileOrDescription: false); + } + } } \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Formats/Bmp/BmpDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Bmp/BmpDecoderTests.cs index 09c3d1545..5f2de9f51 100644 --- a/tests/ImageSharp.Tests/Formats/Bmp/BmpDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Bmp/BmpDecoderTests.cs @@ -17,10 +17,7 @@ namespace SixLabors.ImageSharp.Tests { public const PixelTypes CommonNonDefaultPixelTypes = PixelTypes.Rgba32 | PixelTypes.Bgra32 | PixelTypes.RgbaVector; - public static readonly string[] AllBmpFiles = - { - Car, F, NegHeight, CoreHeader, V5Header, RLE, RLEInverted, Bit8, Bit8Inverted, Bit16, Bit16Inverted - }; + public static readonly string[] AllBmpFiles = All; public static readonly TheoryData RatioFiles = new TheoryData diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelBlenders/PorterDuffFunctionsTests.cs b/tests/ImageSharp.Tests/PixelFormats/PixelBlenders/PorterDuffFunctionsTests.cs index c5910e13a..9a196d9d5 100644 --- a/tests/ImageSharp.Tests/PixelFormats/PixelBlenders/PorterDuffFunctionsTests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/PixelBlenders/PorterDuffFunctionsTests.cs @@ -1,10 +1,7 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. -using System; -using System.Collections.Generic; using System.Numerics; -using System.Text; using SixLabors.ImageSharp.PixelFormats.PixelBlenders; using SixLabors.ImageSharp.Tests.TestUtilities; using Xunit; @@ -22,7 +19,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelBlenders [MemberData(nameof(NormalBlendFunctionData))] public void NormalBlendFunction(TestVector4 back, TestVector4 source, float amount, TestVector4 expected) { - Vector4 actual = PorterDuffFunctions.Normal((Vector4)back, source, amount); + Vector4 actual = PorterDuffFunctions.NormalSrcOver((Vector4)back, source, amount); Assert.Equal(expected, actual); } @@ -41,7 +38,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelBlenders [MemberData(nameof(MultiplyFunctionData))] public void MultiplyFunction(TestVector4 back, TestVector4 source, float amount, TestVector4 expected) { - Vector4 actual = PorterDuffFunctions.Multiply((Vector4)back, source, amount); + Vector4 actual = PorterDuffFunctions.MultiplySrcOver((Vector4)back, source, amount); VectorAssert.Equal(expected, actual, 5); } @@ -60,7 +57,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelBlenders [MemberData(nameof(AddFunctionData))] public void AddFunction(TestVector4 back, TestVector4 source, float amount, TestVector4 expected) { - Vector4 actual = PorterDuffFunctions.Multiply((Vector4)back, source, amount); + Vector4 actual = PorterDuffFunctions.MultiplySrcOver((Vector4)back, source, amount); VectorAssert.Equal(expected, actual, 5); } @@ -79,7 +76,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelBlenders [MemberData(nameof(SubstractFunctionData))] public void SubstractFunction(TestVector4 back, TestVector4 source, float amount, TestVector4 expected) { - Vector4 actual = PorterDuffFunctions.Subtract((Vector4)back, source, amount); + Vector4 actual = PorterDuffFunctions.SubtractSrcOver((Vector4)back, source, amount); VectorAssert.Equal(expected, actual, 5); } @@ -98,7 +95,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelBlenders [MemberData(nameof(ScreenFunctionData))] public void ScreenFunction(TestVector4 back, TestVector4 source, float amount, TestVector4 expected) { - Vector4 actual = PorterDuffFunctions.Screen((Vector4)back, source, amount); + Vector4 actual = PorterDuffFunctions.ScreenSrcOver((Vector4)back, source, amount); VectorAssert.Equal(expected, actual, 5); } @@ -117,7 +114,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelBlenders [MemberData(nameof(DarkenFunctionData))] public void DarkenFunction(TestVector4 back, TestVector4 source, float amount, TestVector4 expected) { - Vector4 actual = PorterDuffFunctions.Darken((Vector4)back, source, amount); + Vector4 actual = PorterDuffFunctions.DarkenSrcOver((Vector4)back, source, amount); VectorAssert.Equal(expected, actual, 5); } @@ -136,7 +133,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelBlenders [MemberData(nameof(LightenFunctionData))] public void LightenFunction(TestVector4 back, TestVector4 source, float amount, TestVector4 expected) { - Vector4 actual = PorterDuffFunctions.Lighten((Vector4)back, source, amount); + Vector4 actual = PorterDuffFunctions.LightenSrcOver((Vector4)back, source, amount); VectorAssert.Equal(expected, actual, 5); } @@ -155,7 +152,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelBlenders [MemberData(nameof(OverlayFunctionData))] public void OverlayFunction(TestVector4 back, TestVector4 source, float amount, TestVector4 expected) { - Vector4 actual = PorterDuffFunctions.Overlay((Vector4)back, source, amount); + Vector4 actual = PorterDuffFunctions.OverlaySrcOver((Vector4)back, source, amount); VectorAssert.Equal(expected, actual, 5); } @@ -174,7 +171,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelBlenders [MemberData(nameof(HardLightFunctionData))] public void HardLightFunction(TestVector4 back, TestVector4 source, float amount, TestVector4 expected) { - Vector4 actual = PorterDuffFunctions.HardLight((Vector4)back, source, amount); + Vector4 actual = PorterDuffFunctions.HardLightSrcOver((Vector4)back, source, amount); VectorAssert.Equal(expected, actual, 5); } } diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelBlenders/PorterDuffFunctionsTests_TPixel.cs b/tests/ImageSharp.Tests/PixelFormats/PixelBlenders/PorterDuffFunctionsTests_TPixel.cs index 1273a453e..3ea9bcad4 100644 --- a/tests/ImageSharp.Tests/PixelFormats/PixelBlenders/PorterDuffFunctionsTests_TPixel.cs +++ b/tests/ImageSharp.Tests/PixelFormats/PixelBlenders/PorterDuffFunctionsTests_TPixel.cs @@ -2,9 +2,6 @@ // Licensed under the Apache License, Version 2.0. using System; -using System.Collections.Generic; -using System.Numerics; -using System.Text; using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats.PixelBlenders; using SixLabors.ImageSharp.Tests.TestUtilities; @@ -14,7 +11,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelBlenders { using SixLabors.Memory; - public class PorterDuffFunctionsTests_TPixel + public class PorterDuffFunctionsTestsTPixel { private static Span AsSpan(T value) where T : struct @@ -34,26 +31,26 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelBlenders public void NormalBlendFunction(TestPixel back, TestPixel source, float amount, TestPixel expected) where TPixel : struct, IPixel { - TPixel actual = PorterDuffFunctions.Normal((TPixel)(TPixel)back, source, amount); + TPixel actual = PorterDuffFunctions.NormalSrcOver((TPixel)(TPixel)back, source, amount); VectorAssert.Equal(expected, actual, 2); } [Theory] [MemberData(nameof(NormalBlendFunctionData))] - public void NormalBlendFunction_Blender(TestPixel back, TestPixel source, float amount, TestPixel expected) + public void NormalBlendFunctionBlender(TestPixel back, TestPixel source, float amount, TestPixel expected) where TPixel : struct, IPixel { - TPixel actual = new DefaultPixelBlenders.Normal().Blend(back, source, amount); + TPixel actual = new DefaultPixelBlenders.NormalSrcOver().Blend(back, source, amount); VectorAssert.Equal(expected, actual, 2); } [Theory] [MemberData(nameof(NormalBlendFunctionData))] - public void NormalBlendFunction_Blender_Bulk(TestPixel back, TestPixel source, float amount, TestPixel expected) + public void NormalBlendFunctionBlenderBulk(TestPixel back, TestPixel source, float amount, TestPixel expected) where TPixel : struct, IPixel { - Span dest = new Span(new TPixel[1]); - new DefaultPixelBlenders.Normal().Blend(this.MemoryAllocator, dest, back.AsSpan(), source.AsSpan(), AsSpan(amount)); + var dest = new Span(new TPixel[1]); + new DefaultPixelBlenders.NormalSrcOver().Blend(this.MemoryAllocator, dest, back.AsSpan(), source.AsSpan(), AsSpan(amount)); VectorAssert.Equal(expected, dest[0], 2); } @@ -73,26 +70,26 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelBlenders public void MultiplyFunction(TestPixel back, TestPixel source, float amount, TestPixel expected) where TPixel : struct, IPixel { - TPixel actual = PorterDuffFunctions.Multiply((TPixel)back, source, amount); + TPixel actual = PorterDuffFunctions.MultiplySrcOver((TPixel)back, source, amount); VectorAssert.Equal(expected, actual, 2); } [Theory] [MemberData(nameof(MultiplyFunctionData))] - public void MultiplyFunction_Blender(TestPixel back, TestPixel source, float amount, TestPixel expected) + public void MultiplyFunctionBlender(TestPixel back, TestPixel source, float amount, TestPixel expected) where TPixel : struct, IPixel { - TPixel actual = new DefaultPixelBlenders.Multiply().Blend(back, source, amount); + TPixel actual = new DefaultPixelBlenders.MultiplySrcOver().Blend(back, source, amount); VectorAssert.Equal(expected, actual, 2); } [Theory] [MemberData(nameof(MultiplyFunctionData))] - public void MultiplyFunction_Blender_Bulk(TestPixel back, TestPixel source, float amount, TestPixel expected) + public void MultiplyFunctionBlenderBulk(TestPixel back, TestPixel source, float amount, TestPixel expected) where TPixel : struct, IPixel { - Span dest = new Span(new TPixel[1]); - new DefaultPixelBlenders.Multiply().Blend(this.MemoryAllocator, dest, back.AsSpan(), source.AsSpan(), AsSpan(amount)); + var dest = new Span(new TPixel[1]); + new DefaultPixelBlenders.MultiplySrcOver().Blend(this.MemoryAllocator, dest, back.AsSpan(), source.AsSpan(), AsSpan(amount)); VectorAssert.Equal(expected, dest[0], 2); } @@ -112,26 +109,26 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelBlenders public void AddFunction(TestPixel back, TestPixel source, float amount, TestPixel expected) where TPixel : struct, IPixel { - TPixel actual = PorterDuffFunctions.Add((TPixel)back, source, amount); + TPixel actual = PorterDuffFunctions.AddSrcOver((TPixel)back, source, amount); VectorAssert.Equal(expected, actual, 2); } [Theory] [MemberData(nameof(AddFunctionData))] - public void AddFunction_Blender(TestPixel back, TestPixel source, float amount, TestPixel expected) + public void AddFunctionBlender(TestPixel back, TestPixel source, float amount, TestPixel expected) where TPixel : struct, IPixel { - TPixel actual = new DefaultPixelBlenders.Add().Blend(back, source, amount); + TPixel actual = new DefaultPixelBlenders.AddSrcOver().Blend(back, source, amount); VectorAssert.Equal(expected, actual, 2); } [Theory] [MemberData(nameof(AddFunctionData))] - public void AddFunction_Blender_Bulk(TestPixel back, TestPixel source, float amount, TestPixel expected) + public void AddFunctionBlenderBulk(TestPixel back, TestPixel source, float amount, TestPixel expected) where TPixel : struct, IPixel { - Span dest = new Span(new TPixel[1]); - new DefaultPixelBlenders.Add().Blend(this.MemoryAllocator, dest, back.AsSpan(), source.AsSpan(), AsSpan(amount)); + var dest = new Span(new TPixel[1]); + new DefaultPixelBlenders.AddSrcOver().Blend(this.MemoryAllocator, dest, back.AsSpan(), source.AsSpan(), AsSpan(amount)); VectorAssert.Equal(expected, dest[0], 2); } @@ -151,26 +148,26 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelBlenders public void SubstractFunction(TestPixel back, TestPixel source, float amount, TestPixel expected) where TPixel : struct, IPixel { - TPixel actual = PorterDuffFunctions.Subtract((TPixel)back, source, amount); + TPixel actual = PorterDuffFunctions.SubtractSrcOver((TPixel)back, source, amount); VectorAssert.Equal(expected, actual, 2); } [Theory] [MemberData(nameof(SubstractFunctionData))] - public void SubstractFunction_Blender(TestPixel back, TestPixel source, float amount, TestPixel expected) + public void SubstractFunctionBlender(TestPixel back, TestPixel source, float amount, TestPixel expected) where TPixel : struct, IPixel { - TPixel actual = new DefaultPixelBlenders.Subtract().Blend(back, source, amount); + TPixel actual = new DefaultPixelBlenders.SubtractSrcOver().Blend(back, source, amount); VectorAssert.Equal(expected, actual, 2); } [Theory] [MemberData(nameof(SubstractFunctionData))] - public void SubstractFunction_Blender_Bulk(TestPixel back, TestPixel source, float amount, TestPixel expected) + public void SubstractFunctionBlenderBulk(TestPixel back, TestPixel source, float amount, TestPixel expected) where TPixel : struct, IPixel { - Span dest = new Span(new TPixel[1]); - new DefaultPixelBlenders.Subtract().Blend(this.MemoryAllocator, dest, back.AsSpan(), source.AsSpan(), AsSpan(amount)); + var dest = new Span(new TPixel[1]); + new DefaultPixelBlenders.SubtractSrcOver().Blend(this.MemoryAllocator, dest, back.AsSpan(), source.AsSpan(), AsSpan(amount)); VectorAssert.Equal(expected, dest[0], 2); } @@ -190,26 +187,26 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelBlenders public void ScreenFunction(TestPixel back, TestPixel source, float amount, TestPixel expected) where TPixel : struct, IPixel { - TPixel actual = PorterDuffFunctions.Screen((TPixel)back, source, amount); + TPixel actual = PorterDuffFunctions.ScreenSrcOver((TPixel)back, source, amount); VectorAssert.Equal(expected, actual, 2); } [Theory] [MemberData(nameof(ScreenFunctionData))] - public void ScreenFunction_Blender(TestPixel back, TestPixel source, float amount, TestPixel expected) + public void ScreenFunctionBlender(TestPixel back, TestPixel source, float amount, TestPixel expected) where TPixel : struct, IPixel { - TPixel actual = new DefaultPixelBlenders.Screen().Blend(back, source, amount); + TPixel actual = new DefaultPixelBlenders.ScreenSrcOver().Blend(back, source, amount); VectorAssert.Equal(expected, actual, 2); } [Theory] [MemberData(nameof(ScreenFunctionData))] - public void ScreenFunction_Blender_Bulk(TestPixel back, TestPixel source, float amount, TestPixel expected) + public void ScreenFunctionBlenderBulk(TestPixel back, TestPixel source, float amount, TestPixel expected) where TPixel : struct, IPixel { - Span dest = new Span(new TPixel[1]); - new DefaultPixelBlenders.Screen().Blend(this.MemoryAllocator, dest, back.AsSpan(), source.AsSpan(), AsSpan(amount)); + var dest = new Span(new TPixel[1]); + new DefaultPixelBlenders.ScreenSrcOver().Blend(this.MemoryAllocator, dest, back.AsSpan(), source.AsSpan(), AsSpan(amount)); VectorAssert.Equal(expected, dest[0], 2); } @@ -229,26 +226,26 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelBlenders public void DarkenFunction(TestPixel back, TestPixel source, float amount, TestPixel expected) where TPixel : struct, IPixel { - TPixel actual = PorterDuffFunctions.Darken((TPixel)back, source, amount); + TPixel actual = PorterDuffFunctions.DarkenSrcOver((TPixel)back, source, amount); VectorAssert.Equal(expected, actual, 2); } [Theory] [MemberData(nameof(DarkenFunctionData))] - public void DarkenFunction_Blender(TestPixel back, TestPixel source, float amount, TestPixel expected) + public void DarkenFunctionBlender(TestPixel back, TestPixel source, float amount, TestPixel expected) where TPixel : struct, IPixel { - TPixel actual = new DefaultPixelBlenders.Darken().Blend(back, source, amount); + TPixel actual = new DefaultPixelBlenders.DarkenSrcOver().Blend(back, source, amount); VectorAssert.Equal(expected, actual, 2); } [Theory] [MemberData(nameof(DarkenFunctionData))] - public void DarkenFunction_Blender_Bulk(TestPixel back, TestPixel source, float amount, TestPixel expected) + public void DarkenFunctionBlenderBulk(TestPixel back, TestPixel source, float amount, TestPixel expected) where TPixel : struct, IPixel { - Span dest = new Span(new TPixel[1]); - new DefaultPixelBlenders.Darken().Blend(this.MemoryAllocator, dest, back.AsSpan(), source.AsSpan(), AsSpan(amount)); + var dest = new Span(new TPixel[1]); + new DefaultPixelBlenders.DarkenSrcOver().Blend(this.MemoryAllocator, dest, back.AsSpan(), source.AsSpan(), AsSpan(amount)); VectorAssert.Equal(expected, dest[0], 2); } @@ -268,26 +265,26 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelBlenders public void LightenFunction(TestPixel back, TestPixel source, float amount, TestPixel expected) where TPixel : struct, IPixel { - TPixel actual = PorterDuffFunctions.Lighten((TPixel)back, source, amount); + TPixel actual = PorterDuffFunctions.LightenSrcOver((TPixel)back, source, amount); VectorAssert.Equal(expected, actual, 2); } [Theory] [MemberData(nameof(LightenFunctionData))] - public void LightenFunction_Blender(TestPixel back, TestPixel source, float amount, TestPixel expected) + public void LightenFunctionBlender(TestPixel back, TestPixel source, float amount, TestPixel expected) where TPixel : struct, IPixel { - TPixel actual = new DefaultPixelBlenders.Lighten().Blend(back, source, amount); + TPixel actual = new DefaultPixelBlenders.LightenSrcOver().Blend(back, source, amount); VectorAssert.Equal(expected, actual, 2); } [Theory] [MemberData(nameof(LightenFunctionData))] - public void LightenFunction_Blender_Bulk(TestPixel back, TestPixel source, float amount, TestPixel expected) + public void LightenFunctionBlenderBulk(TestPixel back, TestPixel source, float amount, TestPixel expected) where TPixel : struct, IPixel { - Span dest = new Span(new TPixel[1]); - new DefaultPixelBlenders.Lighten().Blend(this.MemoryAllocator, dest, back.AsSpan(), source.AsSpan(), AsSpan(amount)); + var dest = new Span(new TPixel[1]); + new DefaultPixelBlenders.LightenSrcOver().Blend(this.MemoryAllocator, dest, back.AsSpan(), source.AsSpan(), AsSpan(amount)); VectorAssert.Equal(expected, dest[0], 2); } @@ -307,26 +304,26 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelBlenders public void OverlayFunction(TestPixel back, TestPixel source, float amount, TestPixel expected) where TPixel : struct, IPixel { - TPixel actual = PorterDuffFunctions.Overlay((TPixel)back, source, amount); + TPixel actual = PorterDuffFunctions.OverlaySrcOver((TPixel)back, source, amount); VectorAssert.Equal(expected, actual, 2); } [Theory] [MemberData(nameof(OverlayFunctionData))] - public void OverlayFunction_Blender(TestPixel back, TestPixel source, float amount, TestPixel expected) + public void OverlayFunctionBlender(TestPixel back, TestPixel source, float amount, TestPixel expected) where TPixel : struct, IPixel { - TPixel actual = new DefaultPixelBlenders.Overlay().Blend(back, source, amount); + TPixel actual = new DefaultPixelBlenders.OverlaySrcOver().Blend(back, source, amount); VectorAssert.Equal(expected, actual, 2); } [Theory] [MemberData(nameof(OverlayFunctionData))] - public void OverlayFunction_Blender_Bulk(TestPixel back, TestPixel source, float amount, TestPixel expected) + public void OverlayFunctionBlenderBulk(TestPixel back, TestPixel source, float amount, TestPixel expected) where TPixel : struct, IPixel { - Span dest = new Span(new TPixel[1]); - new DefaultPixelBlenders.Overlay().Blend(this.MemoryAllocator, dest, back.AsSpan(), source.AsSpan(), AsSpan(amount)); + var dest = new Span(new TPixel[1]); + new DefaultPixelBlenders.OverlaySrcOver().Blend(this.MemoryAllocator, dest, back.AsSpan(), source.AsSpan(), AsSpan(amount)); VectorAssert.Equal(expected, dest[0], 2); } @@ -346,26 +343,26 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelBlenders public void HardLightFunction(TestPixel back, TestPixel source, float amount, TestPixel expected) where TPixel : struct, IPixel { - TPixel actual = PorterDuffFunctions.HardLight((TPixel)back, source, amount); + TPixel actual = PorterDuffFunctions.HardLightSrcOver((TPixel)back, source, amount); VectorAssert.Equal(expected, actual, 2); } [Theory] [MemberData(nameof(HardLightFunctionData))] - public void HardLightFunction_Blender(TestPixel back, TestPixel source, float amount, TestPixel expected) + public void HardLightFunctionBlender(TestPixel back, TestPixel source, float amount, TestPixel expected) where TPixel : struct, IPixel { - TPixel actual = new DefaultPixelBlenders.HardLight().Blend(back, source, amount); + TPixel actual = new DefaultPixelBlenders.HardLightSrcOver().Blend(back, source, amount); VectorAssert.Equal(expected, actual, 2); } [Theory] [MemberData(nameof(HardLightFunctionData))] - public void HardLightFunction_Blender_Bulk(TestPixel back, TestPixel source, float amount, TestPixel expected) + public void HardLightFunctionBlenderBulk(TestPixel back, TestPixel source, float amount, TestPixel expected) where TPixel : struct, IPixel { - Span dest = new Span(new TPixel[1]); - new DefaultPixelBlenders.HardLight().Blend(this.MemoryAllocator, dest, back.AsSpan(), source.AsSpan(), AsSpan(amount)); + var dest = new Span(new TPixel[1]); + new DefaultPixelBlenders.HardLightSrcOver().Blend(this.MemoryAllocator, dest, back.AsSpan(), source.AsSpan(), AsSpan(amount)); VectorAssert.Equal(expected, dest[0], 2); } } diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.Blender.cs b/tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.Blender.cs index d3956ecd5..3923a5675 100644 --- a/tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.Blender.cs +++ b/tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.Blender.cs @@ -17,50 +17,50 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats public static TheoryData BlenderMappings = new TheoryData() { - { new TestPixel(), typeof(DefaultPixelBlenders.Normal), PixelBlenderMode.Normal }, - { new TestPixel(), typeof(DefaultPixelBlenders.Screen), PixelBlenderMode.Screen }, - { new TestPixel(), typeof(DefaultPixelBlenders.HardLight), PixelBlenderMode.HardLight }, - { new TestPixel(), typeof(DefaultPixelBlenders.Overlay), PixelBlenderMode.Overlay }, - { new TestPixel(), typeof(DefaultPixelBlenders.Darken), PixelBlenderMode.Darken }, - { new TestPixel(), typeof(DefaultPixelBlenders.Lighten), PixelBlenderMode.Lighten }, - { new TestPixel(), typeof(DefaultPixelBlenders.Add), PixelBlenderMode.Add }, - { new TestPixel(), typeof(DefaultPixelBlenders.Subtract), PixelBlenderMode.Subtract }, - { new TestPixel(), typeof(DefaultPixelBlenders.Multiply), PixelBlenderMode.Multiply }, + { new TestPixel(), typeof(DefaultPixelBlenders.NormalSrcOver), PixelBlenderMode.Normal }, + { new TestPixel(), typeof(DefaultPixelBlenders.ScreenSrcOver), PixelBlenderMode.Screen }, + { new TestPixel(), typeof(DefaultPixelBlenders.HardLightSrcOver), PixelBlenderMode.HardLight }, + { new TestPixel(), typeof(DefaultPixelBlenders.OverlaySrcOver), PixelBlenderMode.Overlay }, + { new TestPixel(), typeof(DefaultPixelBlenders.DarkenSrcOver), PixelBlenderMode.Darken }, + { new TestPixel(), typeof(DefaultPixelBlenders.LightenSrcOver), PixelBlenderMode.Lighten }, + { new TestPixel(), typeof(DefaultPixelBlenders.AddSrcOver), PixelBlenderMode.Add }, + { new TestPixel(), typeof(DefaultPixelBlenders.SubtractSrcOver), PixelBlenderMode.Subtract }, + { new TestPixel(), typeof(DefaultPixelBlenders.MultiplySrcOver), PixelBlenderMode.Multiply }, - { new TestPixel(), typeof(DefaultPixelBlenders.Src), PixelBlenderMode.Src }, - { new TestPixel(), typeof(DefaultPixelBlenders.Atop), PixelBlenderMode.Atop }, - { new TestPixel(), typeof(DefaultPixelBlenders.Over), PixelBlenderMode.Over }, - { new TestPixel(), typeof(DefaultPixelBlenders.In), PixelBlenderMode.In }, - { new TestPixel(), typeof(DefaultPixelBlenders.Out), PixelBlenderMode.Out }, - { new TestPixel(), typeof(DefaultPixelBlenders.Dest), PixelBlenderMode.Dest }, - { new TestPixel(), typeof(DefaultPixelBlenders.DestAtop), PixelBlenderMode.DestAtop }, - { new TestPixel(), typeof(DefaultPixelBlenders.DestOver), PixelBlenderMode.DestOver }, - { new TestPixel(), typeof(DefaultPixelBlenders.DestIn), PixelBlenderMode.DestIn }, - { new TestPixel(), typeof(DefaultPixelBlenders.DestOut), PixelBlenderMode.DestOut }, - { new TestPixel(), typeof(DefaultPixelBlenders.Clear), PixelBlenderMode.Clear }, - { new TestPixel(), typeof(DefaultPixelBlenders.Xor), PixelBlenderMode.Xor }, + { new TestPixel(), typeof(DefaultPixelBlenders.NormalSrc), PixelBlenderMode.Src }, + { new TestPixel(), typeof(DefaultPixelBlenders.NormalSrcAtop), PixelBlenderMode.Atop }, + { new TestPixel(), typeof(DefaultPixelBlenders.NormalSrcOver), PixelBlenderMode.Over }, + { new TestPixel(), typeof(DefaultPixelBlenders.NormalSrcIn), PixelBlenderMode.In }, + { new TestPixel(), typeof(DefaultPixelBlenders.NormalSrcOut), PixelBlenderMode.Out }, + { new TestPixel(), typeof(DefaultPixelBlenders.NormalDest), PixelBlenderMode.Dest }, + { new TestPixel(), typeof(DefaultPixelBlenders.NormalDestAtop), PixelBlenderMode.DestAtop }, + { new TestPixel(), typeof(DefaultPixelBlenders.NormalDestOver), PixelBlenderMode.DestOver }, + { new TestPixel(), typeof(DefaultPixelBlenders.NormalDestIn), PixelBlenderMode.DestIn }, + { new TestPixel(), typeof(DefaultPixelBlenders.NormalDestOut), PixelBlenderMode.DestOut }, + { new TestPixel(), typeof(DefaultPixelBlenders.NormalClear), PixelBlenderMode.Clear }, + { new TestPixel(), typeof(DefaultPixelBlenders.NormalXor), PixelBlenderMode.Xor }, - { new TestPixel(), typeof(DefaultPixelBlenders.Normal), PixelBlenderMode.Normal }, - { new TestPixel(), typeof(DefaultPixelBlenders.Screen), PixelBlenderMode.Screen }, - { new TestPixel(), typeof(DefaultPixelBlenders.HardLight), PixelBlenderMode.HardLight }, - { new TestPixel(), typeof(DefaultPixelBlenders.Overlay), PixelBlenderMode.Overlay }, - { new TestPixel(), typeof(DefaultPixelBlenders.Darken), PixelBlenderMode.Darken }, - { new TestPixel(), typeof(DefaultPixelBlenders.Lighten), PixelBlenderMode.Lighten }, - { new TestPixel(), typeof(DefaultPixelBlenders.Add), PixelBlenderMode.Add }, - { new TestPixel(), typeof(DefaultPixelBlenders.Subtract), PixelBlenderMode.Subtract }, - { new TestPixel(), typeof(DefaultPixelBlenders.Multiply), PixelBlenderMode.Multiply }, - { new TestPixel(), typeof(DefaultPixelBlenders.Src), PixelBlenderMode.Src }, - { new TestPixel(), typeof(DefaultPixelBlenders.Atop), PixelBlenderMode.Atop }, - { new TestPixel(), typeof(DefaultPixelBlenders.Over), PixelBlenderMode.Over }, - { new TestPixel(), typeof(DefaultPixelBlenders.In), PixelBlenderMode.In }, - { new TestPixel(), typeof(DefaultPixelBlenders.Out), PixelBlenderMode.Out }, - { new TestPixel(), typeof(DefaultPixelBlenders.Dest), PixelBlenderMode.Dest }, - { new TestPixel(), typeof(DefaultPixelBlenders.DestAtop), PixelBlenderMode.DestAtop }, - { new TestPixel(), typeof(DefaultPixelBlenders.DestOver), PixelBlenderMode.DestOver }, - { new TestPixel(), typeof(DefaultPixelBlenders.DestIn), PixelBlenderMode.DestIn }, - { new TestPixel(), typeof(DefaultPixelBlenders.DestOut), PixelBlenderMode.DestOut }, - { new TestPixel(), typeof(DefaultPixelBlenders.Clear), PixelBlenderMode.Clear }, - { new TestPixel(), typeof(DefaultPixelBlenders.Xor), PixelBlenderMode.Xor }, + { new TestPixel(), typeof(DefaultPixelBlenders.NormalSrcOver), PixelBlenderMode.Normal }, + { new TestPixel(), typeof(DefaultPixelBlenders.ScreenSrcOver), PixelBlenderMode.Screen }, + { new TestPixel(), typeof(DefaultPixelBlenders.HardLightSrcOver), PixelBlenderMode.HardLight }, + { new TestPixel(), typeof(DefaultPixelBlenders.OverlaySrcOver), PixelBlenderMode.Overlay }, + { new TestPixel(), typeof(DefaultPixelBlenders.DarkenSrcOver), PixelBlenderMode.Darken }, + { new TestPixel(), typeof(DefaultPixelBlenders.LightenSrcOver), PixelBlenderMode.Lighten }, + { new TestPixel(), typeof(DefaultPixelBlenders.AddSrcOver), PixelBlenderMode.Add }, + { new TestPixel(), typeof(DefaultPixelBlenders.SubtractSrcOver), PixelBlenderMode.Subtract }, + { new TestPixel(), typeof(DefaultPixelBlenders.MultiplySrcOver), PixelBlenderMode.Multiply }, + { new TestPixel(), typeof(DefaultPixelBlenders.NormalSrc), PixelBlenderMode.Src }, + { new TestPixel(), typeof(DefaultPixelBlenders.NormalSrcAtop), PixelBlenderMode.Atop }, + { new TestPixel(), typeof(DefaultPixelBlenders.NormalSrcOver), PixelBlenderMode.Over }, + { new TestPixel(), typeof(DefaultPixelBlenders.NormalSrcIn), PixelBlenderMode.In }, + { new TestPixel(), typeof(DefaultPixelBlenders.NormalSrcOut), PixelBlenderMode.Out }, + { new TestPixel(), typeof(DefaultPixelBlenders.NormalDest), PixelBlenderMode.Dest }, + { new TestPixel(), typeof(DefaultPixelBlenders.NormalDestAtop), PixelBlenderMode.DestAtop }, + { new TestPixel(), typeof(DefaultPixelBlenders.NormalDestOver), PixelBlenderMode.DestOver }, + { new TestPixel(), typeof(DefaultPixelBlenders.NormalDestIn), PixelBlenderMode.DestIn }, + { new TestPixel(), typeof(DefaultPixelBlenders.NormalDestOut), PixelBlenderMode.DestOut }, + { new TestPixel(), typeof(DefaultPixelBlenders.NormalClear), PixelBlenderMode.Clear }, + { new TestPixel(), typeof(DefaultPixelBlenders.NormalXor), PixelBlenderMode.Xor }, }; diff --git a/tests/ImageSharp.Tests/TestImages.cs b/tests/ImageSharp.Tests/TestImages.cs index 142b923ed..5eb70117e 100644 --- a/tests/ImageSharp.Tests/TestImages.cs +++ b/tests/ImageSharp.Tests/TestImages.cs @@ -165,12 +165,30 @@ namespace SixLabors.ImageSharp.Tests public const string V5Header = "Bmp/BITMAPV5HEADER.bmp"; public const string RLE = "Bmp/RunLengthEncoded.bmp"; public const string RLEInverted = "Bmp/RunLengthEncoded-inverted.bmp"; + public const string Bit1 = "Bmp/pal1.bmp"; + public const string Bit1Pal1 = "Bmp/pal1p1.bmp"; + public const string Bit4 = "Bmp/pal4.bmp"; public const string Bit8 = "Bmp/test8.bmp"; public const string Bit8Inverted = "Bmp/test8-inverted.bmp"; public const string Bit16 = "Bmp/test16.bmp"; public const string Bit16Inverted = "Bmp/test16-inverted.bmp"; - public static readonly string[] All = { Car, F, NegHeight, CoreHeader, V5Header, RLE, RLEInverted, Bit8, Bit8Inverted, Bit16, Bit16Inverted }; + public static readonly string[] All + = { + Car, + F, + NegHeight, + CoreHeader, + V5Header, RLE, + RLEInverted, + Bit1, + Bit1Pal1, + Bit4, + Bit8, + Bit8Inverted, + Bit16, + Bit16Inverted + }; } public static class Gif diff --git a/tests/Images/External b/tests/Images/External index 98fb7e2e4..825220cdc 160000 --- a/tests/Images/External +++ b/tests/Images/External @@ -1 +1 @@ -Subproject commit 98fb7e2e4d5935b1c733bd2b206b6145b71ef378 +Subproject commit 825220cdc4e9d1b4b3b474c63139e18e1cdb800e diff --git a/tests/Images/Input/Bmp/pal1.bmp b/tests/Images/Input/Bmp/pal1.bmp new file mode 100644 index 000000000..4776f8277 Binary files /dev/null and b/tests/Images/Input/Bmp/pal1.bmp differ diff --git a/tests/Images/Input/Bmp/pal1p1.bmp b/tests/Images/Input/Bmp/pal1p1.bmp new file mode 100644 index 000000000..b68321c4c Binary files /dev/null and b/tests/Images/Input/Bmp/pal1p1.bmp differ diff --git a/tests/Images/Input/Bmp/pal4.bmp b/tests/Images/Input/Bmp/pal4.bmp new file mode 100644 index 000000000..7fd36303c Binary files /dev/null and b/tests/Images/Input/Bmp/pal4.bmp differ