mirror of https://github.com/SixLabors/ImageSharp
70 changed files with 1430 additions and 322 deletions
@ -0,0 +1,83 @@ |
|||||
|
// <copyright file="PixelCompositor{TPixel}.cs" company="James Jackson-South">
|
||||
|
// Copyright (c) James Jackson-South and contributors.
|
||||
|
// Licensed under the Apache License, Version 2.0.
|
||||
|
// </copyright>
|
||||
|
|
||||
|
namespace ImageSharp.PixelFormats |
||||
|
{ |
||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Text; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// The various blending modes.
|
||||
|
/// </summary>
|
||||
|
public enum PixelBlenderMode |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// The default composition mode.
|
||||
|
/// </summary>
|
||||
|
/// <remarks> uses PremultipliedLerpTransform </remarks>
|
||||
|
Default = 0, |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Normal transform.
|
||||
|
/// </summary>
|
||||
|
Normal, |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Multiply Transform.
|
||||
|
/// </summary>
|
||||
|
Multiply, |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Screen Transform.
|
||||
|
/// </summary>
|
||||
|
Screen, |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// HardLight Transform.
|
||||
|
/// </summary>
|
||||
|
HardLight, |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Overlay Transform.
|
||||
|
/// </summary>
|
||||
|
Overlay, |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Darken Transform.
|
||||
|
/// </summary>
|
||||
|
Darken, |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Lighten Transform.
|
||||
|
/// </summary>
|
||||
|
Lighten, |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// SoftLight Transform.
|
||||
|
/// </summary>
|
||||
|
SoftLight, |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Dodge Transform.
|
||||
|
/// </summary>
|
||||
|
Dodge, |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Burn Transform.
|
||||
|
/// </summary>
|
||||
|
Burn, |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Difference Transform.
|
||||
|
/// </summary>
|
||||
|
Difference, |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Exclusion Transform.
|
||||
|
/// </summary>
|
||||
|
Exclusion |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,42 @@ |
|||||
|
// <copyright file="DefaultBurnPixelBlender{TPixel}.cs" company="James Jackson-South">
|
||||
|
// Copyright (c) James Jackson-South and contributors.
|
||||
|
// Licensed under the Apache License, Version 2.0.
|
||||
|
// </copyright>
|
||||
|
|
||||
|
namespace ImageSharp.PixelFormats.PixelBlenders |
||||
|
{ |
||||
|
using System; |
||||
|
using System.Numerics; |
||||
|
using ImageSharp.PixelFormats; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Abstract base class for calling pixel composition functions
|
||||
|
/// </summary>
|
||||
|
/// <typeparam name="TPixel">The type of the pixel</typeparam>
|
||||
|
internal class DefaultBurnPixelBlender<TPixel> : PixelBlender<TPixel> |
||||
|
where TPixel : struct, IPixel<TPixel> |
||||
|
{ |
||||
|
/// <inheritdoc />
|
||||
|
public override TPixel Compose(TPixel background, TPixel source, float amount) |
||||
|
{ |
||||
|
Vector4 result = Vector4BlendTransforms.Burn(background.ToVector4(), source.ToVector4()); |
||||
|
TPixel resultPixel = default(TPixel); |
||||
|
resultPixel.PackFromVector4(result); |
||||
|
return resultPixel; |
||||
|
} |
||||
|
|
||||
|
/// <inheritdoc />
|
||||
|
public override void Compose(BufferSpan<TPixel> destination, BufferSpan<TPixel> background, BufferSpan<TPixel> source, BufferSpan<float> amount) |
||||
|
{ |
||||
|
Guard.MustBeGreaterThanOrEqualTo(destination.Length, background.Length, nameof(destination)); |
||||
|
Guard.MustBeGreaterThanOrEqualTo(source.Length, background.Length, nameof(destination)); |
||||
|
Guard.MustBeGreaterThanOrEqualTo(amount.Length, background.Length, nameof(destination)); |
||||
|
|
||||
|
for (int i = 0; i < destination.Length; i++) |
||||
|
{ |
||||
|
Vector4 result = Vector4BlendTransforms.Burn(background[i].ToVector4(), source[i].ToVector4()); |
||||
|
destination[i].PackFromVector4(result); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,42 @@ |
|||||
|
// <copyright file="DefaultDarkenPixelBlender{TPixel}.cs" company="James Jackson-South">
|
||||
|
// Copyright (c) James Jackson-South and contributors.
|
||||
|
// Licensed under the Apache License, Version 2.0.
|
||||
|
// </copyright>
|
||||
|
|
||||
|
namespace ImageSharp.PixelFormats.PixelBlenders |
||||
|
{ |
||||
|
using System; |
||||
|
using System.Numerics; |
||||
|
using ImageSharp.PixelFormats; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Abstract base class for calling pixel composition functions
|
||||
|
/// </summary>
|
||||
|
/// <typeparam name="TPixel">The type of the pixel</typeparam>
|
||||
|
internal class DefaultDarkenPixelBlender<TPixel> : PixelBlender<TPixel> |
||||
|
where TPixel : struct, IPixel<TPixel> |
||||
|
{ |
||||
|
/// <inheritdoc />
|
||||
|
public override TPixel Compose(TPixel background, TPixel source, float amount) |
||||
|
{ |
||||
|
Vector4 result = Vector4BlendTransforms.Darken(background.ToVector4(), source.ToVector4()); |
||||
|
TPixel resultPixel = default(TPixel); |
||||
|
resultPixel.PackFromVector4(result); |
||||
|
return resultPixel; |
||||
|
} |
||||
|
|
||||
|
/// <inheritdoc />
|
||||
|
public override void Compose(BufferSpan<TPixel> destination, BufferSpan<TPixel> background, BufferSpan<TPixel> source, BufferSpan<float> amount) |
||||
|
{ |
||||
|
Guard.MustBeGreaterThanOrEqualTo(destination.Length, background.Length, nameof(destination)); |
||||
|
Guard.MustBeGreaterThanOrEqualTo(source.Length, background.Length, nameof(destination)); |
||||
|
Guard.MustBeGreaterThanOrEqualTo(amount.Length, background.Length, nameof(destination)); |
||||
|
|
||||
|
for (int i = 0; i < destination.Length; i++) |
||||
|
{ |
||||
|
Vector4 result = Vector4BlendTransforms.Darken(background[i].ToVector4(), source[i].ToVector4()); |
||||
|
destination[i].PackFromVector4(result); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,42 @@ |
|||||
|
// <copyright file="DefaultDifferencePixelBlender{TPixel}.cs" company="James Jackson-South">
|
||||
|
// Copyright (c) James Jackson-South and contributors.
|
||||
|
// Licensed under the Apache License, Version 2.0.
|
||||
|
// </copyright>
|
||||
|
|
||||
|
namespace ImageSharp.PixelFormats.PixelBlenders |
||||
|
{ |
||||
|
using System; |
||||
|
using System.Numerics; |
||||
|
using ImageSharp.PixelFormats; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Abstract base class for calling pixel composition functions
|
||||
|
/// </summary>
|
||||
|
/// <typeparam name="TPixel">The type of the pixel</typeparam>
|
||||
|
internal class DefaultDifferencePixelBlender<TPixel> : PixelBlender<TPixel> |
||||
|
where TPixel : struct, IPixel<TPixel> |
||||
|
{ |
||||
|
/// <inheritdoc />
|
||||
|
public override TPixel Compose(TPixel background, TPixel source, float amount) |
||||
|
{ |
||||
|
Vector4 result = Vector4BlendTransforms.Difference(background.ToVector4(), source.ToVector4()); |
||||
|
TPixel resultPixel = default(TPixel); |
||||
|
resultPixel.PackFromVector4(result); |
||||
|
return resultPixel; |
||||
|
} |
||||
|
|
||||
|
/// <inheritdoc />
|
||||
|
public override void Compose(BufferSpan<TPixel> destination, BufferSpan<TPixel> background, BufferSpan<TPixel> source, BufferSpan<float> amount) |
||||
|
{ |
||||
|
Guard.MustBeGreaterThanOrEqualTo(destination.Length, background.Length, nameof(destination)); |
||||
|
Guard.MustBeGreaterThanOrEqualTo(source.Length, background.Length, nameof(destination)); |
||||
|
Guard.MustBeGreaterThanOrEqualTo(amount.Length, background.Length, nameof(destination)); |
||||
|
|
||||
|
for (int i = 0; i < destination.Length; i++) |
||||
|
{ |
||||
|
Vector4 result = Vector4BlendTransforms.Difference(background[i].ToVector4(), source[i].ToVector4()); |
||||
|
destination[i].PackFromVector4(result); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,42 @@ |
|||||
|
// <copyright file="DefaultDodgePixelBlender{TPixel}.cs" company="James Jackson-South">
|
||||
|
// Copyright (c) James Jackson-South and contributors.
|
||||
|
// Licensed under the Apache License, Version 2.0.
|
||||
|
// </copyright>
|
||||
|
|
||||
|
namespace ImageSharp.PixelFormats.PixelBlenders |
||||
|
{ |
||||
|
using System; |
||||
|
using System.Numerics; |
||||
|
using ImageSharp.PixelFormats; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Abstract base class for calling pixel composition functions
|
||||
|
/// </summary>
|
||||
|
/// <typeparam name="TPixel">The type of the pixel</typeparam>
|
||||
|
internal class DefaultDodgePixelBlender<TPixel> : PixelBlender<TPixel> |
||||
|
where TPixel : struct, IPixel<TPixel> |
||||
|
{ |
||||
|
/// <inheritdoc />
|
||||
|
public override TPixel Compose(TPixel background, TPixel source, float amount) |
||||
|
{ |
||||
|
Vector4 result = Vector4BlendTransforms.Dodge(background.ToVector4(), source.ToVector4()); |
||||
|
TPixel resultPixel = default(TPixel); |
||||
|
resultPixel.PackFromVector4(result); |
||||
|
return resultPixel; |
||||
|
} |
||||
|
|
||||
|
/// <inheritdoc />
|
||||
|
public override void Compose(BufferSpan<TPixel> destination, BufferSpan<TPixel> background, BufferSpan<TPixel> source, BufferSpan<float> amount) |
||||
|
{ |
||||
|
Guard.MustBeGreaterThanOrEqualTo(destination.Length, background.Length, nameof(destination)); |
||||
|
Guard.MustBeGreaterThanOrEqualTo(source.Length, background.Length, nameof(destination)); |
||||
|
Guard.MustBeGreaterThanOrEqualTo(amount.Length, background.Length, nameof(destination)); |
||||
|
|
||||
|
for (int i = 0; i < destination.Length; i++) |
||||
|
{ |
||||
|
Vector4 result = Vector4BlendTransforms.Dodge(background[i].ToVector4(), source[i].ToVector4()); |
||||
|
destination[i].PackFromVector4(result); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,42 @@ |
|||||
|
// <copyright file="DefaultExclusionPixelBlender{TPixel}.cs" company="James Jackson-South">
|
||||
|
// Copyright (c) James Jackson-South and contributors.
|
||||
|
// Licensed under the Apache License, Version 2.0.
|
||||
|
// </copyright>
|
||||
|
|
||||
|
namespace ImageSharp.PixelFormats.PixelBlenders |
||||
|
{ |
||||
|
using System; |
||||
|
using System.Numerics; |
||||
|
using ImageSharp.PixelFormats; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Abstract base class for calling pixel composition functions
|
||||
|
/// </summary>
|
||||
|
/// <typeparam name="TPixel">The type of the pixel</typeparam>
|
||||
|
internal class DefaultExclusionPixelBlender<TPixel> : PixelBlender<TPixel> |
||||
|
where TPixel : struct, IPixel<TPixel> |
||||
|
{ |
||||
|
/// <inheritdoc />
|
||||
|
public override TPixel Compose(TPixel background, TPixel source, float amount) |
||||
|
{ |
||||
|
Vector4 result = Vector4BlendTransforms.Exclusion(background.ToVector4(), source.ToVector4()); |
||||
|
TPixel resultPixel = default(TPixel); |
||||
|
resultPixel.PackFromVector4(result); |
||||
|
return resultPixel; |
||||
|
} |
||||
|
|
||||
|
/// <inheritdoc />
|
||||
|
public override void Compose(BufferSpan<TPixel> destination, BufferSpan<TPixel> background, BufferSpan<TPixel> source, BufferSpan<float> amount) |
||||
|
{ |
||||
|
Guard.MustBeGreaterThanOrEqualTo(destination.Length, background.Length, nameof(destination)); |
||||
|
Guard.MustBeGreaterThanOrEqualTo(source.Length, background.Length, nameof(destination)); |
||||
|
Guard.MustBeGreaterThanOrEqualTo(amount.Length, background.Length, nameof(destination)); |
||||
|
|
||||
|
for (int i = 0; i < destination.Length; i++) |
||||
|
{ |
||||
|
Vector4 result = Vector4BlendTransforms.Exclusion(background[i].ToVector4(), source[i].ToVector4()); |
||||
|
destination[i].PackFromVector4(result); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,42 @@ |
|||||
|
// <copyright file="DefaultHardLightPixelBlender{TPixel}.cs" company="James Jackson-South">
|
||||
|
// Copyright (c) James Jackson-South and contributors.
|
||||
|
// Licensed under the Apache License, Version 2.0.
|
||||
|
// </copyright>
|
||||
|
|
||||
|
namespace ImageSharp.PixelFormats.PixelBlenders |
||||
|
{ |
||||
|
using System; |
||||
|
using System.Numerics; |
||||
|
using ImageSharp.PixelFormats; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Abstract base class for calling pixel composition functions
|
||||
|
/// </summary>
|
||||
|
/// <typeparam name="TPixel">The type of the pixel</typeparam>
|
||||
|
internal class DefaultHardLightPixelBlender<TPixel> : PixelBlender<TPixel> |
||||
|
where TPixel : struct, IPixel<TPixel> |
||||
|
{ |
||||
|
/// <inheritdoc />
|
||||
|
public override TPixel Compose(TPixel background, TPixel source, float amount) |
||||
|
{ |
||||
|
Vector4 result = Vector4BlendTransforms.HardLight(background.ToVector4(), source.ToVector4()); |
||||
|
TPixel resultPixel = default(TPixel); |
||||
|
resultPixel.PackFromVector4(result); |
||||
|
return resultPixel; |
||||
|
} |
||||
|
|
||||
|
/// <inheritdoc />
|
||||
|
public override void Compose(BufferSpan<TPixel> destination, BufferSpan<TPixel> background, BufferSpan<TPixel> source, BufferSpan<float> amount) |
||||
|
{ |
||||
|
Guard.MustBeGreaterThanOrEqualTo(destination.Length, background.Length, nameof(destination)); |
||||
|
Guard.MustBeGreaterThanOrEqualTo(source.Length, background.Length, nameof(destination)); |
||||
|
Guard.MustBeGreaterThanOrEqualTo(amount.Length, background.Length, nameof(destination)); |
||||
|
|
||||
|
for (int i = 0; i < destination.Length; i++) |
||||
|
{ |
||||
|
Vector4 result = Vector4BlendTransforms.HardLight(background[i].ToVector4(), source[i].ToVector4()); |
||||
|
destination[i].PackFromVector4(result); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,42 @@ |
|||||
|
// <copyright file="DefaultDarkenPixelBlender{TPixel}.cs" company="James Jackson-South">
|
||||
|
// Copyright (c) James Jackson-South and contributors.
|
||||
|
// Licensed under the Apache License, Version 2.0.
|
||||
|
// </copyright>
|
||||
|
|
||||
|
namespace ImageSharp.PixelFormats.PixelBlenders |
||||
|
{ |
||||
|
using System; |
||||
|
using System.Numerics; |
||||
|
using ImageSharp.PixelFormats; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Abstract base class for calling pixel composition functions
|
||||
|
/// </summary>
|
||||
|
/// <typeparam name="TPixel">The type of the pixel</typeparam>
|
||||
|
internal class DefaultLightenPixelBlender<TPixel> : PixelBlender<TPixel> |
||||
|
where TPixel : struct, IPixel<TPixel> |
||||
|
{ |
||||
|
/// <inheritdoc />
|
||||
|
public override TPixel Compose(TPixel background, TPixel source, float amount) |
||||
|
{ |
||||
|
Vector4 result = Vector4BlendTransforms.Lighten(background.ToVector4(), source.ToVector4()); |
||||
|
TPixel resultPixel = default(TPixel); |
||||
|
resultPixel.PackFromVector4(result); |
||||
|
return resultPixel; |
||||
|
} |
||||
|
|
||||
|
/// <inheritdoc />
|
||||
|
public override void Compose(BufferSpan<TPixel> destination, BufferSpan<TPixel> background, BufferSpan<TPixel> source, BufferSpan<float> amount) |
||||
|
{ |
||||
|
Guard.MustBeGreaterThanOrEqualTo(destination.Length, background.Length, nameof(destination)); |
||||
|
Guard.MustBeGreaterThanOrEqualTo(source.Length, background.Length, nameof(destination)); |
||||
|
Guard.MustBeGreaterThanOrEqualTo(amount.Length, background.Length, nameof(destination)); |
||||
|
|
||||
|
for (int i = 0; i < destination.Length; i++) |
||||
|
{ |
||||
|
Vector4 result = Vector4BlendTransforms.Lighten(background[i].ToVector4(), source[i].ToVector4()); |
||||
|
destination[i].PackFromVector4(result); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,42 @@ |
|||||
|
// <copyright file="DefaultMultiplyPixelBlender{TPixel}.cs" company="James Jackson-South">
|
||||
|
// Copyright (c) James Jackson-South and contributors.
|
||||
|
// Licensed under the Apache License, Version 2.0.
|
||||
|
// </copyright>
|
||||
|
|
||||
|
namespace ImageSharp.PixelFormats.PixelBlenders |
||||
|
{ |
||||
|
using System; |
||||
|
using System.Numerics; |
||||
|
using ImageSharp.PixelFormats; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Abstract base class for calling pixel composition functions
|
||||
|
/// </summary>
|
||||
|
/// <typeparam name="TPixel">The type of the pixel</typeparam>
|
||||
|
internal class DefaultMultiplyPixelBlender<TPixel> : PixelBlender<TPixel> |
||||
|
where TPixel : struct, IPixel<TPixel> |
||||
|
{ |
||||
|
/// <inheritdoc />
|
||||
|
public override TPixel Compose(TPixel background, TPixel source, float amount) |
||||
|
{ |
||||
|
Vector4 result = Vector4BlendTransforms.Multiply(background.ToVector4(), source.ToVector4()); |
||||
|
TPixel resultPixel = default(TPixel); |
||||
|
resultPixel.PackFromVector4(result); |
||||
|
return resultPixel; |
||||
|
} |
||||
|
|
||||
|
/// <inheritdoc />
|
||||
|
public override void Compose(BufferSpan<TPixel> destination, BufferSpan<TPixel> background, BufferSpan<TPixel> source, BufferSpan<float> amount) |
||||
|
{ |
||||
|
Guard.MustBeGreaterThanOrEqualTo(destination.Length, background.Length, nameof(destination)); |
||||
|
Guard.MustBeGreaterThanOrEqualTo(source.Length, background.Length, nameof(destination)); |
||||
|
Guard.MustBeGreaterThanOrEqualTo(amount.Length, background.Length, nameof(destination)); |
||||
|
|
||||
|
for (int i = 0; i < destination.Length; i++) |
||||
|
{ |
||||
|
Vector4 result = Vector4BlendTransforms.Multiply(background[i].ToVector4(), source[i].ToVector4()); |
||||
|
destination[i].PackFromVector4(result); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,37 @@ |
|||||
|
// <copyright file="DefaultNormalPixelBlender{TPixel}.cs" company="James Jackson-South">
|
||||
|
// Copyright (c) James Jackson-South and contributors.
|
||||
|
// Licensed under the Apache License, Version 2.0.
|
||||
|
// </copyright>
|
||||
|
|
||||
|
namespace ImageSharp.PixelFormats.PixelBlenders |
||||
|
{ |
||||
|
using System; |
||||
|
using ImageSharp.PixelFormats; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Abstract base class for calling pixel composition functions
|
||||
|
/// </summary>
|
||||
|
/// <typeparam name="TPixel">The type of the pixel</typeparam>
|
||||
|
internal class DefaultNormalPixelBlender<TPixel> : PixelBlender<TPixel> |
||||
|
where TPixel : struct, IPixel<TPixel> |
||||
|
{ |
||||
|
/// <inheritdoc />
|
||||
|
public override TPixel Compose(TPixel background, TPixel source, float amount) |
||||
|
{ |
||||
|
return source; |
||||
|
} |
||||
|
|
||||
|
/// <inheritdoc />
|
||||
|
public override void Compose(BufferSpan<TPixel> destination, BufferSpan<TPixel> background, BufferSpan<TPixel> source, BufferSpan<float> amount) |
||||
|
{ |
||||
|
Guard.MustBeGreaterThanOrEqualTo(destination.Length, background.Length, nameof(destination)); |
||||
|
Guard.MustBeGreaterThanOrEqualTo(source.Length, background.Length, nameof(destination)); |
||||
|
Guard.MustBeGreaterThanOrEqualTo(amount.Length, background.Length, nameof(destination)); |
||||
|
|
||||
|
for (int i = 0; i < destination.Length; i++) |
||||
|
{ |
||||
|
destination[i] = source[i]; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,42 @@ |
|||||
|
// <copyright file="DefaultOverlayPixelBlender{TPixel}.cs" company="James Jackson-South">
|
||||
|
// Copyright (c) James Jackson-South and contributors.
|
||||
|
// Licensed under the Apache License, Version 2.0.
|
||||
|
// </copyright>
|
||||
|
|
||||
|
namespace ImageSharp.PixelFormats.PixelBlenders |
||||
|
{ |
||||
|
using System; |
||||
|
using System.Numerics; |
||||
|
using ImageSharp.PixelFormats; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Abstract base class for calling pixel composition functions
|
||||
|
/// </summary>
|
||||
|
/// <typeparam name="TPixel">The type of the pixel</typeparam>
|
||||
|
internal class DefaultOverlayPixelBlender<TPixel> : PixelBlender<TPixel> |
||||
|
where TPixel : struct, IPixel<TPixel> |
||||
|
{ |
||||
|
/// <inheritdoc />
|
||||
|
public override TPixel Compose(TPixel background, TPixel source, float amount) |
||||
|
{ |
||||
|
Vector4 result = Vector4BlendTransforms.Overlay(background.ToVector4(), source.ToVector4()); |
||||
|
TPixel resultPixel = default(TPixel); |
||||
|
resultPixel.PackFromVector4(result); |
||||
|
return resultPixel; |
||||
|
} |
||||
|
|
||||
|
/// <inheritdoc />
|
||||
|
public override void Compose(BufferSpan<TPixel> destination, BufferSpan<TPixel> background, BufferSpan<TPixel> source, BufferSpan<float> amount) |
||||
|
{ |
||||
|
Guard.MustBeGreaterThanOrEqualTo(destination.Length, background.Length, nameof(destination)); |
||||
|
Guard.MustBeGreaterThanOrEqualTo(source.Length, background.Length, nameof(destination)); |
||||
|
Guard.MustBeGreaterThanOrEqualTo(amount.Length, background.Length, nameof(destination)); |
||||
|
|
||||
|
for (int i = 0; i < destination.Length; i++) |
||||
|
{ |
||||
|
Vector4 result = Vector4BlendTransforms.Overlay(background[i].ToVector4(), source[i].ToVector4()); |
||||
|
destination[i].PackFromVector4(result); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,42 @@ |
|||||
|
// <copyright file="DefaultDifferencePixelBlender{TPixel}.cs" company="James Jackson-South">
|
||||
|
// Copyright (c) James Jackson-South and contributors.
|
||||
|
// Licensed under the Apache License, Version 2.0.
|
||||
|
// </copyright>
|
||||
|
|
||||
|
namespace ImageSharp.PixelFormats.PixelBlenders |
||||
|
{ |
||||
|
using System; |
||||
|
using System.Numerics; |
||||
|
using ImageSharp.PixelFormats; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Abstract base class for calling pixel composition functions
|
||||
|
/// </summary>
|
||||
|
/// <typeparam name="TPixel">The type of the pixel</typeparam>
|
||||
|
internal class DefaultPremultipliedLerpPixelBlender<TPixel> : PixelBlender<TPixel> |
||||
|
where TPixel : struct, IPixel<TPixel> |
||||
|
{ |
||||
|
/// <inheritdoc />
|
||||
|
public override TPixel Compose(TPixel background, TPixel source, float amount) |
||||
|
{ |
||||
|
Vector4 result = Vector4BlendTransforms.PremultipliedLerp(background.ToVector4(), source.ToVector4(), amount); |
||||
|
TPixel resultPixel = default(TPixel); |
||||
|
resultPixel.PackFromVector4(result); |
||||
|
return resultPixel; |
||||
|
} |
||||
|
|
||||
|
/// <inheritdoc />
|
||||
|
public override void Compose(BufferSpan<TPixel> destination, BufferSpan<TPixel> background, BufferSpan<TPixel> source, BufferSpan<float> amount) |
||||
|
{ |
||||
|
Guard.MustBeGreaterThanOrEqualTo(destination.Length, background.Length, nameof(destination)); |
||||
|
Guard.MustBeGreaterThanOrEqualTo(source.Length, background.Length, nameof(destination)); |
||||
|
Guard.MustBeGreaterThanOrEqualTo(amount.Length, background.Length, nameof(destination)); |
||||
|
|
||||
|
for (int i = 0; i < destination.Length; i++) |
||||
|
{ |
||||
|
Vector4 result = Vector4BlendTransforms.PremultipliedLerp(background[i].ToVector4(), source[i].ToVector4(), amount[i]); |
||||
|
destination[i].PackFromVector4(result); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,42 @@ |
|||||
|
// <copyright file="DefaultScreenPixelBlender{TPixel}.cs" company="James Jackson-South">
|
||||
|
// Copyright (c) James Jackson-South and contributors.
|
||||
|
// Licensed under the Apache License, Version 2.0.
|
||||
|
// </copyright>
|
||||
|
|
||||
|
namespace ImageSharp.PixelFormats.PixelBlenders |
||||
|
{ |
||||
|
using System; |
||||
|
using System.Numerics; |
||||
|
using ImageSharp.PixelFormats; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Abstract base class for calling pixel composition functions
|
||||
|
/// </summary>
|
||||
|
/// <typeparam name="TPixel">The type of the pixel</typeparam>
|
||||
|
internal class DefaultScreenPixelBlender<TPixel> : PixelBlender<TPixel> |
||||
|
where TPixel : struct, IPixel<TPixel> |
||||
|
{ |
||||
|
/// <inheritdoc />
|
||||
|
public override TPixel Compose(TPixel background, TPixel source, float amount) |
||||
|
{ |
||||
|
Vector4 result = Vector4BlendTransforms.Screen(background.ToVector4(), source.ToVector4()); |
||||
|
TPixel resultPixel = default(TPixel); |
||||
|
resultPixel.PackFromVector4(result); |
||||
|
return resultPixel; |
||||
|
} |
||||
|
|
||||
|
/// <inheritdoc />
|
||||
|
public override void Compose(BufferSpan<TPixel> destination, BufferSpan<TPixel> background, BufferSpan<TPixel> source, BufferSpan<float> amount) |
||||
|
{ |
||||
|
Guard.MustBeGreaterThanOrEqualTo(destination.Length, background.Length, nameof(destination)); |
||||
|
Guard.MustBeGreaterThanOrEqualTo(source.Length, background.Length, nameof(destination)); |
||||
|
Guard.MustBeGreaterThanOrEqualTo(amount.Length, background.Length, nameof(destination)); |
||||
|
|
||||
|
for (int i = 0; i < destination.Length; i++) |
||||
|
{ |
||||
|
Vector4 result = Vector4BlendTransforms.Screen(background[i].ToVector4(), source[i].ToVector4()); |
||||
|
destination[i].PackFromVector4(result); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,42 @@ |
|||||
|
// <copyright file="DefaultSoftLightPixelBlender{TPixel}.cs" company="James Jackson-South">
|
||||
|
// Copyright (c) James Jackson-South and contributors.
|
||||
|
// Licensed under the Apache License, Version 2.0.
|
||||
|
// </copyright>
|
||||
|
|
||||
|
namespace ImageSharp.PixelFormats.PixelBlenders |
||||
|
{ |
||||
|
using System; |
||||
|
using System.Numerics; |
||||
|
using ImageSharp.PixelFormats; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Abstract base class for calling pixel composition functions
|
||||
|
/// </summary>
|
||||
|
/// <typeparam name="TPixel">The type of the pixel</typeparam>
|
||||
|
internal class DefaultSoftLightPixelBlender<TPixel> : PixelBlender<TPixel> |
||||
|
where TPixel : struct, IPixel<TPixel> |
||||
|
{ |
||||
|
/// <inheritdoc />
|
||||
|
public override TPixel Compose(TPixel background, TPixel source, float amount) |
||||
|
{ |
||||
|
Vector4 result = Vector4BlendTransforms.SoftLight(background.ToVector4(), source.ToVector4()); |
||||
|
TPixel resultPixel = default(TPixel); |
||||
|
resultPixel.PackFromVector4(result); |
||||
|
return resultPixel; |
||||
|
} |
||||
|
|
||||
|
/// <inheritdoc />
|
||||
|
public override void Compose(BufferSpan<TPixel> destination, BufferSpan<TPixel> background, BufferSpan<TPixel> source, BufferSpan<float> amount) |
||||
|
{ |
||||
|
Guard.MustBeGreaterThanOrEqualTo(destination.Length, background.Length, nameof(destination)); |
||||
|
Guard.MustBeGreaterThanOrEqualTo(source.Length, background.Length, nameof(destination)); |
||||
|
Guard.MustBeGreaterThanOrEqualTo(amount.Length, background.Length, nameof(destination)); |
||||
|
|
||||
|
for (int i = 0; i < destination.Length; i++) |
||||
|
{ |
||||
|
Vector4 result = Vector4BlendTransforms.SoftLight(background[i].ToVector4(), source[i].ToVector4()); |
||||
|
destination[i].PackFromVector4(result); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,39 @@ |
|||||
|
// <copyright file="PixelCompositor{TPixel}.cs" company="James Jackson-South">
|
||||
|
// Copyright (c) James Jackson-South and contributors.
|
||||
|
// Licensed under the Apache License, Version 2.0.
|
||||
|
// </copyright>
|
||||
|
|
||||
|
namespace ImageSharp.PixelFormats |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Abstract base class for calling pixel composition functions
|
||||
|
/// </summary>
|
||||
|
/// <typeparam name="TPixel">The type of the pixel</typeparam>
|
||||
|
internal abstract class PixelBlender<TPixel> |
||||
|
where TPixel : struct, IPixel<TPixel> |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Composes 2 pixels together.
|
||||
|
/// </summary>
|
||||
|
/// <param name="background">The background color.</param>
|
||||
|
/// <param name="source">The source color.</param>
|
||||
|
/// <param name="amount">
|
||||
|
/// A value between 0 and 1 indicating the weight of the second source vector.
|
||||
|
/// At amount = 0, "from" is returned, at amount = 1, "to" is returned.
|
||||
|
/// </param>
|
||||
|
/// <returns>The final pixel value after composition</returns>
|
||||
|
public abstract TPixel Compose(TPixel background, TPixel source, float amount); |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Composes 2 pixels together.
|
||||
|
/// </summary>
|
||||
|
/// <param name="destination">The destination span.</param>
|
||||
|
/// <param name="background">The background span.</param>
|
||||
|
/// <param name="source">The source span.</param>
|
||||
|
/// <param name="amount">
|
||||
|
/// A value between 0 and 1 indicating the weight of the second source vector.
|
||||
|
/// At amount = 0, "from" is returned, at amount = 1, "to" is returned.
|
||||
|
/// </param>
|
||||
|
public abstract void Compose(BufferSpan<TPixel> destination, BufferSpan<TPixel> background, BufferSpan<TPixel> source, BufferSpan<float> amount); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,125 @@ |
|||||
|
// <copyright file="PixelOperations{TPixel}.cs" company="James Jackson-South">
|
||||
|
// Copyright (c) James Jackson-South and contributors.
|
||||
|
// Licensed under the Apache License, Version 2.0.
|
||||
|
// </copyright>
|
||||
|
|
||||
|
namespace ImageSharp.PixelFormats |
||||
|
{ |
||||
|
using System.Numerics; |
||||
|
using System.Runtime.CompilerServices; |
||||
|
using ImageSharp.PixelFormats.PixelBlenders; |
||||
|
|
||||
|
#pragma warning disable CS1710 // XML comment has a duplicate typeparam tag
|
||||
|
/// <summary>
|
||||
|
/// A stateless class implementing Strategy Pattern for batched pixel-data conversion operations
|
||||
|
/// for pixel buffers of type <typeparamref name="TPixel"/>.
|
||||
|
/// </summary>
|
||||
|
/// <typeparam name="TPixel">The pixel format.</typeparam>
|
||||
|
public partial class PixelOperations<TPixel> |
||||
|
#pragma warning restore CS1710 // XML comment has a duplicate typeparam tag
|
||||
|
where TPixel : struct, IPixel<TPixel> |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Gets the NormalBlender.
|
||||
|
/// </summary>
|
||||
|
private PixelBlender<TPixel> normalBlender = new DefaultNormalPixelBlender<TPixel>(); |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets the MultiplyBlender.
|
||||
|
/// </summary>
|
||||
|
private PixelBlender<TPixel> multiplyBlender = new DefaultMultiplyPixelBlender<TPixel>(); |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets the ScreenBlender.
|
||||
|
/// </summary>
|
||||
|
private PixelBlender<TPixel> screenBlender = new DefaultScreenPixelBlender<TPixel>(); |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets the HardLightBlender.
|
||||
|
/// </summary>
|
||||
|
private PixelBlender<TPixel> hardLightBlender = new DefaultHardLightPixelBlender<TPixel>(); |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets the OverlayBlender.
|
||||
|
/// </summary>
|
||||
|
private PixelBlender<TPixel> overlayBlender = new DefaultOverlayPixelBlender<TPixel>(); |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets the DarkenBlender.
|
||||
|
/// </summary>
|
||||
|
private PixelBlender<TPixel> darkenBlender = new DefaultDarkenPixelBlender<TPixel>(); |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets the LightenBlender.
|
||||
|
/// </summary>
|
||||
|
private PixelBlender<TPixel> lightenBlender = new DefaultLightenPixelBlender<TPixel>(); |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets the SoftLightBlender.
|
||||
|
/// </summary>
|
||||
|
private PixelBlender<TPixel> softLightBlender = new DefaultSoftLightPixelBlender<TPixel>(); |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets the DodgeBlender.
|
||||
|
/// </summary>
|
||||
|
private PixelBlender<TPixel> dodgeBlender = new DefaultDodgePixelBlender<TPixel>(); |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets the BurnBlender.
|
||||
|
/// </summary>
|
||||
|
private PixelBlender<TPixel> burnBlender = new DefaultBurnPixelBlender<TPixel>(); |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets the DifferenceBlender.
|
||||
|
/// </summary>
|
||||
|
private PixelBlender<TPixel> differenceBlender = new DefaultDifferencePixelBlender<TPixel>(); |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets the DifferenceBlender.
|
||||
|
/// </summary>
|
||||
|
private PixelBlender<TPixel> exclusionBlender = new DefaultExclusionPixelBlender<TPixel>(); |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets the PremultipliedLerpBlender.
|
||||
|
/// </summary>
|
||||
|
private PixelBlender<TPixel> premultipliedLerpBlender = new DefaultPremultipliedLerpPixelBlender<TPixel>(); |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Find an instance of the pixel blender.
|
||||
|
/// </summary>
|
||||
|
/// <param name="mode">The blending mode to apply</param>
|
||||
|
/// <returns>A <see cref="PixelBlender{TPixel}"/>.</returns>
|
||||
|
internal virtual PixelBlender<TPixel> GetPixelBlender(PixelBlenderMode mode) |
||||
|
{ |
||||
|
switch (mode) |
||||
|
{ |
||||
|
case PixelBlenderMode.Normal: |
||||
|
return this.normalBlender; |
||||
|
case PixelBlenderMode.Multiply: |
||||
|
return this.multiplyBlender; |
||||
|
case PixelBlenderMode.Screen: |
||||
|
return this.screenBlender; |
||||
|
case PixelBlenderMode.HardLight: |
||||
|
return this.hardLightBlender; |
||||
|
case PixelBlenderMode.Overlay: |
||||
|
return this.overlayBlender; |
||||
|
case PixelBlenderMode.Darken: |
||||
|
return this.darkenBlender; |
||||
|
case PixelBlenderMode.Lighten: |
||||
|
return this.lightenBlender; |
||||
|
case PixelBlenderMode.SoftLight: |
||||
|
return this.softLightBlender; |
||||
|
case PixelBlenderMode.Dodge: |
||||
|
return this.dodgeBlender; |
||||
|
case PixelBlenderMode.Burn: |
||||
|
return this.burnBlender; |
||||
|
case PixelBlenderMode.Difference: |
||||
|
return this.differenceBlender; |
||||
|
case PixelBlenderMode.Exclusion: |
||||
|
return this.exclusionBlender; |
||||
|
default: |
||||
|
return this.premultipliedLerpBlender; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,100 @@ |
|||||
|
// <copyright file="GlowProcessor.cs" company="James Jackson-South">
|
||||
|
// Copyright (c) James Jackson-South and contributors.
|
||||
|
// Licensed under the Apache License, Version 2.0.
|
||||
|
// </copyright>
|
||||
|
|
||||
|
namespace ImageSharp.Processing.Processors |
||||
|
{ |
||||
|
using System; |
||||
|
using System.Numerics; |
||||
|
using System.Threading.Tasks; |
||||
|
|
||||
|
using ImageSharp.PixelFormats; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// An <see cref="IImageProcessor{TPixel}"/> that applies a radial glow effect an <see cref="Image{TPixel}"/>.
|
||||
|
/// </summary>
|
||||
|
/// <typeparam name="TPixel">The pixel format.</typeparam>
|
||||
|
internal class GlowProcessorParallel<TPixel> : ImageProcessor<TPixel> |
||||
|
where TPixel : struct, IPixel<TPixel> |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Initializes a new instance of the <see cref="GlowProcessorParallel{TPixel}" /> class.
|
||||
|
/// </summary>
|
||||
|
/// <param name="color">The color or the glow.</param>
|
||||
|
public GlowProcessorParallel(TPixel color) |
||||
|
{ |
||||
|
this.GlowColor = color; |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets or sets the glow color to apply.
|
||||
|
/// </summary>
|
||||
|
public TPixel GlowColor { get; set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets or sets the the radius.
|
||||
|
/// </summary>
|
||||
|
public float Radius { get; set; } |
||||
|
|
||||
|
/// <inheritdoc/>
|
||||
|
protected override void OnApply(ImageBase<TPixel> source, Rectangle sourceRectangle) |
||||
|
{ |
||||
|
int startY = sourceRectangle.Y; |
||||
|
int endY = sourceRectangle.Bottom; |
||||
|
int startX = sourceRectangle.X; |
||||
|
int endX = sourceRectangle.Right; |
||||
|
TPixel glowColor = this.GlowColor; |
||||
|
Vector2 centre = Rectangle.Center(sourceRectangle).ToVector2(); |
||||
|
float maxDistance = this.Radius > 0 ? MathF.Min(this.Radius, sourceRectangle.Width * .5F) : sourceRectangle.Width * .5F; |
||||
|
|
||||
|
// Align start/end positions.
|
||||
|
int minX = Math.Max(0, startX); |
||||
|
int maxX = Math.Min(source.Width, endX); |
||||
|
int minY = Math.Max(0, startY); |
||||
|
int maxY = Math.Min(source.Height, endY); |
||||
|
|
||||
|
// Reset offset if necessary.
|
||||
|
if (minX > 0) |
||||
|
{ |
||||
|
startX = 0; |
||||
|
} |
||||
|
|
||||
|
if (minY > 0) |
||||
|
{ |
||||
|
startY = 0; |
||||
|
} |
||||
|
|
||||
|
int width = maxX - minX; |
||||
|
using (Buffer<TPixel> rowColors = new Buffer<TPixel>(width)) |
||||
|
using (PixelAccessor<TPixel> sourcePixels = source.Lock()) |
||||
|
{ |
||||
|
for (int i = 0; i < width; i++) |
||||
|
{ |
||||
|
rowColors[i] = glowColor; |
||||
|
} |
||||
|
|
||||
|
PixelBlender<TPixel> blender = PixelOperations<TPixel>.Instance.GetPixelBlender(PixelBlenderMode.Default); |
||||
|
|
||||
|
Parallel.For( |
||||
|
minY, |
||||
|
maxY, |
||||
|
this.ParallelOptions, |
||||
|
y => |
||||
|
{ |
||||
|
int offsetY = y - startY; |
||||
|
|
||||
|
for (int x = minX; x < maxX; x++) |
||||
|
{ |
||||
|
int offsetX = x - startX; |
||||
|
float distance = Vector2.Distance(centre, new Vector2(offsetX, offsetY)); |
||||
|
Vector4 sourceColor = sourcePixels[offsetX, offsetY].ToVector4(); |
||||
|
TPixel packed = default(TPixel); |
||||
|
packed.PackFromVector4(Vector4BlendTransforms.PremultipliedLerp(sourceColor, glowColor.ToVector4(), 1 - (.95F * (distance / maxDistance)))); |
||||
|
sourcePixels[offsetX, offsetY] = packed; |
||||
|
} |
||||
|
}); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,48 @@ |
|||||
|
// <copyright file="Crop.cs" company="James Jackson-South">
|
||||
|
// Copyright (c) James Jackson-South and contributors.
|
||||
|
// Licensed under the Apache License, Version 2.0.
|
||||
|
// </copyright>
|
||||
|
|
||||
|
namespace ImageSharp.Benchmarks |
||||
|
{ |
||||
|
|
||||
|
using BenchmarkDotNet.Attributes; |
||||
|
using ImageSharp.PixelFormats; |
||||
|
using ImageSharp.Drawing; |
||||
|
using ImageSharp.Processing.Processors; |
||||
|
using CoreImage = ImageSharp.Image; |
||||
|
using CoreSize = ImageSharp.Size; |
||||
|
|
||||
|
public class Glow : BenchmarkBase |
||||
|
{ |
||||
|
private GlowProcessor<Rgba32> bulk; |
||||
|
private GlowProcessorParallel<Rgba32> parallel; |
||||
|
|
||||
|
[Setup] |
||||
|
public void Setup() |
||||
|
{ |
||||
|
this.bulk = new GlowProcessor<Rgba32>(NamedColors<Rgba32>.Beige) { Radius = 800 * .5f, }; |
||||
|
this.parallel = new GlowProcessorParallel<Rgba32>(NamedColors<Rgba32>.Beige) { Radius = 800 * .5f, }; |
||||
|
|
||||
|
} |
||||
|
[Benchmark(Description = "ImageSharp Glow - Bulk")] |
||||
|
public CoreSize GlowBulk() |
||||
|
{ |
||||
|
using (CoreImage image = new CoreImage(800, 800)) |
||||
|
{ |
||||
|
image.ApplyProcessor(bulk, image.Bounds); |
||||
|
return new CoreSize(image.Width, image.Height); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
[Benchmark(Description = "ImageSharp Glow - Parallel")] |
||||
|
public CoreSize GLowSimple() |
||||
|
{ |
||||
|
using (CoreImage image = new CoreImage(800, 800)) |
||||
|
{ |
||||
|
image.ApplyProcessor(parallel, image.Bounds); |
||||
|
return new CoreSize(image.Width, image.Height); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,53 @@ |
|||||
|
|
||||
|
|
||||
|
namespace ImageSharp.Tests.PixelFormats |
||||
|
{ |
||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Text; |
||||
|
using ImageSharp.PixelFormats; |
||||
|
using ImageSharp.PixelFormats.PixelBlenders; |
||||
|
using ImageSharp.Tests.TestUtilities; |
||||
|
using Xunit; |
||||
|
|
||||
|
public class PixelOperations |
||||
|
{ |
||||
|
public static TheoryData<object, Type, PixelBlenderMode> blenderMappings = new TheoryData<object, Type, PixelBlenderMode>() |
||||
|
{ |
||||
|
{ new TestPixel<Rgba32>(), typeof(DefaultPremultipliedLerpPixelBlender<Rgba32>), PixelBlenderMode.Default }, |
||||
|
{ new TestPixel<Rgba32>(), typeof(DefaultNormalPixelBlender<Rgba32>), PixelBlenderMode.Normal }, |
||||
|
{ new TestPixel<Rgba32>(), typeof(DefaultScreenPixelBlender<Rgba32>), PixelBlenderMode.Screen }, |
||||
|
{ new TestPixel<Rgba32>(), typeof(DefaultHardLightPixelBlender<Rgba32>), PixelBlenderMode.HardLight }, |
||||
|
{ new TestPixel<Rgba32>(), typeof(DefaultOverlayPixelBlender<Rgba32>), PixelBlenderMode.Overlay }, |
||||
|
{ new TestPixel<Rgba32>(), typeof(DefaultDarkenPixelBlender<Rgba32>), PixelBlenderMode.Darken }, |
||||
|
{ new TestPixel<Rgba32>(), typeof(DefaultLightenPixelBlender<Rgba32>), PixelBlenderMode.Lighten }, |
||||
|
{ new TestPixel<Rgba32>(), typeof(DefaultSoftLightPixelBlender<Rgba32>), PixelBlenderMode.SoftLight }, |
||||
|
{ new TestPixel<Rgba32>(), typeof(DefaultDodgePixelBlender<Rgba32>), PixelBlenderMode.Dodge }, |
||||
|
{ new TestPixel<Rgba32>(), typeof(DefaultBurnPixelBlender<Rgba32>), PixelBlenderMode.Burn }, |
||||
|
{ new TestPixel<Rgba32>(), typeof(DefaultDifferencePixelBlender<Rgba32>), PixelBlenderMode.Difference }, |
||||
|
{ new TestPixel<Rgba32>(), typeof(DefaultExclusionPixelBlender<Rgba32>), PixelBlenderMode.Exclusion }, |
||||
|
|
||||
|
{ new TestPixel<RgbaVector>(), typeof(DefaultPremultipliedLerpPixelBlender<RgbaVector>), PixelBlenderMode.Default }, |
||||
|
{ new TestPixel<RgbaVector>(), typeof(DefaultNormalPixelBlender<RgbaVector>), PixelBlenderMode.Normal }, |
||||
|
{ new TestPixel<RgbaVector>(), typeof(DefaultScreenPixelBlender<RgbaVector>), PixelBlenderMode.Screen }, |
||||
|
{ new TestPixel<RgbaVector>(), typeof(DefaultHardLightPixelBlender<RgbaVector>), PixelBlenderMode.HardLight }, |
||||
|
{ new TestPixel<RgbaVector>(), typeof(DefaultOverlayPixelBlender<RgbaVector>), PixelBlenderMode.Overlay }, |
||||
|
{ new TestPixel<RgbaVector>(), typeof(DefaultDarkenPixelBlender<RgbaVector>), PixelBlenderMode.Darken }, |
||||
|
{ new TestPixel<RgbaVector>(), typeof(DefaultLightenPixelBlender<RgbaVector>), PixelBlenderMode.Lighten }, |
||||
|
{ new TestPixel<RgbaVector>(), typeof(DefaultSoftLightPixelBlender<RgbaVector>), PixelBlenderMode.SoftLight }, |
||||
|
{ new TestPixel<RgbaVector>(), typeof(DefaultDodgePixelBlender<RgbaVector>), PixelBlenderMode.Dodge }, |
||||
|
{ new TestPixel<RgbaVector>(), typeof(DefaultBurnPixelBlender<RgbaVector>), PixelBlenderMode.Burn }, |
||||
|
{ new TestPixel<RgbaVector>(), typeof(DefaultDifferencePixelBlender<RgbaVector>), PixelBlenderMode.Difference }, |
||||
|
{ new TestPixel<RgbaVector>(), typeof(DefaultExclusionPixelBlender<RgbaVector>), PixelBlenderMode.Exclusion } |
||||
|
}; |
||||
|
|
||||
|
[Theory] |
||||
|
[MemberData(nameof(blenderMappings))] |
||||
|
public void ReturnsCorrectBlender<TPixel>(TestPixel<TPixel> pixel, Type type, PixelBlenderMode mode) |
||||
|
where TPixel : struct, IPixel<TPixel> |
||||
|
{ |
||||
|
PixelBlender<TPixel> blender = PixelOperations<TPixel>.Instance.GetPixelBlender(mode); |
||||
|
Assert.IsType(type, blender); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,62 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Text; |
||||
|
using ImageSharp.PixelFormats; |
||||
|
using Xunit.Abstractions; |
||||
|
|
||||
|
namespace ImageSharp.Tests.TestUtilities |
||||
|
{ |
||||
|
public class TestPixel<TPixel> : IXunitSerializable |
||||
|
where TPixel : struct, IPixel<TPixel> |
||||
|
{ |
||||
|
public TestPixel() |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
public TestPixel(float red, float green, float blue, float alpha) |
||||
|
{ |
||||
|
this.Red = red; |
||||
|
this.Green = green; |
||||
|
this.Blue = blue; |
||||
|
this.Alpha = alpha; |
||||
|
} |
||||
|
|
||||
|
public float Red { get; set; } |
||||
|
public float Green { get; set; } |
||||
|
public float Blue { get; set; } |
||||
|
public float Alpha { get; set; } |
||||
|
|
||||
|
public static implicit operator TPixel(TestPixel<TPixel> d) |
||||
|
{ |
||||
|
return d?.AsPixel() ?? default(TPixel); |
||||
|
} |
||||
|
|
||||
|
public TPixel AsPixel() |
||||
|
{ |
||||
|
TPixel pix = default(TPixel); |
||||
|
pix.PackFromVector4(new System.Numerics.Vector4( this.Red, this.Green, this.Blue, this.Alpha)); |
||||
|
return pix; |
||||
|
} |
||||
|
|
||||
|
public void Deserialize(IXunitSerializationInfo info) |
||||
|
{ |
||||
|
this.Red = info.GetValue<float>("red"); |
||||
|
this.Green = info.GetValue<float>("green"); |
||||
|
this.Blue = info.GetValue<float>("blue"); |
||||
|
this.Alpha = info.GetValue<float>("alpha"); |
||||
|
} |
||||
|
|
||||
|
public void Serialize(IXunitSerializationInfo info) |
||||
|
{ |
||||
|
info.AddValue("red", this.Red); |
||||
|
info.AddValue("green", this.Green); |
||||
|
info.AddValue("blue", this.Blue); |
||||
|
info.AddValue("alpha", this.Alpha); |
||||
|
} |
||||
|
|
||||
|
public override string ToString() |
||||
|
{ |
||||
|
return $"{typeof(TPixel).Name}{this.AsPixel().ToString()}"; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
Loading…
Reference in new issue